Zygote

Author Avatar
罗炜光 10月 03, 2016
  • 在其它设备中阅读本文章

本篇基于android2.2.3
Zygote是Android系统应用中一个相当重要的进程,它的主要功能就是执行Android应用程序

Zygote进程运行时,会初始化Dalvik虚拟机,并启动它。

在Android中,应用程序运行前,Zygote进程通过共享已运行的虚拟机的代码与内存信息,缩短应用程序运行所耗费的时间。并且,它会实现将应用程序要使用的Android Framework中的类与资源加载到内存中,并组织形成所用资源的链接信息。新运行的Android应用程序在使用所需资源时不必每次重新形成资源的链接信息,这会节省大量时间,提供程序运行速度

Android的服务与应用程序都由Zygote进程启动运行

Zygote启动后,初始化运行Dalvik虚拟机,而后将需要的类与资源加载到内存中。随后调用fork()创建出Zygote的子进程,接着Zygote的子进程动态加载并运行Android应用程序A。运行的应用程序A会使用Zygote已经初始化并启动运行的Dalvik虚拟机代码,通过使用已加载至内存中的类与资源来加快运行速度。

与其他本地服务或Daemon不同的是,Zygote由Java编写而成,不能直接由init进程启动运行。若想运行Zygote类,必须先生成Dalvik虚拟机,再在Dalvik虚拟机上装载ZygoteInit类,执行这一任务的就是app_process进程。

app_process

int main(int argc, const char* const argv[])
{
    mArgC = argc;
    mArgV = argv;
    mArgLen = 0;
    for (int i=0; i<argc; i++) {
        mArgLen += strlen(argv[i]) + 1;
    }
    mArgLen--;
    AppRuntime runtime;
    ...

    int i = runtime.addVmArguments(argc, argv);

    if (i < argc) {
        runtime.mParentDir = argv[i++];
        if (0 == strcmp("--zygote", arg)) {
            bool startSystemServer = (i < argc) ?
            strcmp(argv[i], "--start-system-server") == 0 : false;
            setArgv0(argv0, "zygote");
            //设置本进程的名称为zygote
            set_process_name("zygote");
            //注意第二个参数为true
            runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
        } else {
            set_process_name(argv0);
            runtime.mClassName = arg;


            runtime.mArgC = argc-i;
            runtime.mArgV = argv+i;

            ...
            runtime.start();
        }
    }
    ...
}

AndroidRuntime

AppRuntime类继承字AndroidRuntime类,AndroidRuntime类用于初始化并运行Dalvik虚拟机,为运行Android应用程序做好准备。

在运行Dalvik虚拟机之前,通过AppRuntime对象,分析环境变量以及运行的参数,并以此生成虚拟机选项。

AndroidRuntime::start

void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
    //className的值"com.android.internal.os.ZygoteInit"
    //startSystemServer的值是true
    char* slashClassName = NULL;
    char* cp;
    JNIEnv* env;

    blockSigpipe(); //处理SIGPIPE信号
    ...

const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        //如果环境变量中没有ANDROID_ROOT,则新增该变量。并设置值为"/system"
        rootDir = "/system";
        ...
    setenv("ANDROID_ROOT", rootDir, 1);
    }
    //创建虚拟机
    if (startVm(&mJavaVM, &env) != 0)
        goto bail;

    ...

    //注册JNI函数
    if (startReg(env) < 0) {
        ...
        goto bail;
    }
    ...
    stringClass = env->FindClass("java/lang/String");
    //创建一个有两个元素的String数组,即Java代码String strArray[] = new String[2];
    strArray = env->NewObjectArray(2, stringClass, NULL);
    classNameStr = env->NewStringUTF(className);
    //设置第一个元素"com.android.internal.os.ZygoteInit"
    env->SetObjectArrayElement(strArray, 0, classNameStr);
    startSystemServerStr = env->NewStringUTF(startSystemServer ?"true" : "false");
    //设置第二个元素为"true",注意这两个元素都是String类型,即字符串
    env->SetObjectArrayElement(strArray, 1, startSystemServerStr);

    jclass startClass;
    jmethodID startMeth;
    slashClassName = strdup(className);
    /*
    将字符串"com.android.internal.os.ZygoteInot"中的"."换成"/".
    即"com/android/internal/os/ZygoteInit",这个名称符合JNI规范。
    */
    for (cp = slashClassName; *cp != '\0'; cp++)
        if (*cp == '.')
            *cp = '/';

    startClass = env->FindClass(slashClassName);

    if (startClass == NULL) {

    } else {
        //找到ZygoteInit类的static main函数的jMethodId
        startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
        if (startMeth == NULL) {
        } else {
            /*
            通过JNI调用Java函数,注意调用的函数是main,传入的参数为"true"
            所属的类是com.android.internal.os.ZygoteInit
            在调用ZygoteInit的main函数后,Zygote便进入Java世界
            */
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

    //zygote退出,在正常情况下,zygote不需要退出
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ...
    if (mJavaVM->DestroyJavaVM() != 0)
        ...

bail:
    free(slashClassName);


}

AndroidRuntime::startVm

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
    //设置虚拟机参数,创建虚拟机
    ...
}

AndroidRuntime::startReg

int AndroidRuntime::startReg(JNIEnv* env)
{
    //设置Thread类的线程创建函数为javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    env->PushLocalFrame(200);
    //注册JNI函数,gRegJNI是一个全局数组
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);
    ...
    return 0;
}

ZygoteInit

public static void main(String argv[]) {
    try {
        SamplingProfilerIntegration.start();
        //注册Zygote用的socket    
        registerZygoteSocket();
        ...
        //预加载类和资源
        preloadClasses();
        preloadResources();
        ...
        //强制执行一次垃圾收集
        gc();
        ...

        if (argv[1].equals("true")) {
            startSystemServer();//启动system_server
        } else if (!argv[1].equals("false")) {
            throw new RuntimeException(argv[0] + USAGE_STRING);
        }
        ...
        if (ZYGOTE_FORK_MODE) {
            runForkMode();
        } else {
            //处理新Android应用程序运行请求
            runSelectLoopMode();
        }
        closeServerSocket();//关闭socket
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        ...
        closeServerSocket();
        throw ex;
    }
}

ZygoteInit类的功能

绑定套接字,接收新Android应用程序运行请求

为了从ActivityManager接收新Android应用程序的运行请求,Zygote使用UDS(Unix Domain Socket),init进程在运行app_process时,使用init.rc文件中以”/dev/zygote”形式注册的套接字
registerZygoteSocket

private static void registerZygoteSocket() {
    if (sServerSocket == null) {
        int fileDesc;
        try {
            //从环境变量中获取Socket的fd
            String env = System.getenv(ANDROID_SOCKET_ENV);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(ANDROID_SOCKET_ENV + " unset or invalid", ex);
        }

        try {
            //创建服务端Socket,这个Socket将listen并accept Client
            sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
        } catch (IOException ex) {
            throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

加载Android Application Framework使用的类与资源

将应用程序框架中的类、平台资源(图像、XML信息、字符串等)预先加载到内存中。新进程直接使用这些类与资源,而不需要重新加载它们,这大大加快了程序的执行速度
preloadClasses

private static final String PRELOADED_CLASSES = "preloaded-classes";

private static void preloadClasses() {
    final VMRuntime runtime = VMRuntime.getRuntime();
    //预加载类的信息存储在PRELOADED_CLASSES变量中,它的值为"preloaded-classes"
    InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(PRELOADED_CLASSES);
    if (is == null) {
        Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
    } else {
        ...//做一些统计和准备工作
        try {
            //读取"preloaded-classes"文件的内容
            BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
            int count = 0;
            String line;
            String missingClasses = null;
            while ((line = br.readLine()) != null) {
                //读取文件的每一行,忽略#开头的注释行
                line = line.trim();
                if (line.startsWith("#") || line.equals("")) {
                    continue;
                }

                try {
                    if (Config.LOGV) {
                        Log.v(TAG, "Preloading " + line + "...");
                    }
                    //通过Java反射来记载类,line中存储的是预加载的类名
                    Class.forName(line);
                    ...
                    count++;
                } catch (ClassNotFoundException e) {
                    ...

                } catch (Throwable t) {
                    ...
                }
            }
            ...//扫尾工作
        }
    }
}

preloaded-classes

# Classes which are preloaded by com.android.internal.os.ZygoteInit.
2# Automatically generated by frameworks/base/tools/preload/WritePreloadedClassFile.java.
3# MIN_LOAD_TIME_MICROS=1250
4android.R$styleable
5android.accounts.AccountManager
6android.accounts.AccountManager$4
7android.accounts.AccountManager$6
8android.accounts.AccountManager$AmsTask
...

preload_class文件由framework/base/tools/preload工具生成,它判断每个类的加载的时间是否大于1250微秒(1.25毫秒)即MIN_LOAD_TIME_MICROS=1250,超时的类会被写入到preload-classes文件中,最后由zygote预加载
preloadResources

private static void preloadResources() {
    final VMRuntime runtime = VMRuntime.getRuntime();

    Debug.startAllocCounting();
    try {
        runtime.gcSoftReferences();
        runtime.runFinalizationSync();
        //预加载系统资源
        mResources = Resources.getSystem();
        mResources.startPreloading();
        if (PRELOAD_RESOURCES) {
            Log.i(TAG, "Preloading resources...");

            long startTime = SystemClock.uptimeMillis();
            //加载Drawable资源
            TypedArray ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_drawables);
            int N = preloadDrawables(runtime, ar);
            Log.i(TAG, "...preloaded " + N + " resources in "+ (SystemClock.uptimeMillis()-startTime) + "ms.");
            startTime = SystemClock.uptimeMillis();
            //加载Color State资源
            ar = mResources.obtainTypedArray(com.android.internal.R.array.preloaded_color_state_lists);
            N = preloadColorStateLists(runtime, ar);
            Log.i(TAG, "...preloaded " + N + " resources in "+ (SystemClock.uptimeMillis()-startTime) + "ms.");
        }
        mResources.finishPreloading();
    } catch (RuntimeException e) {
    Log.w(TAG, "Failure preloading resources", e);
    } finally {
        Debug.stopAllocCounting();
    }
}

加载Drawable与Color State资源,preloaded_drawablespreloaded_color_state_lists记录的会被加载到内存中

启动运行SystemServer

通过app_process运行zygote时,参数”–start-system-server”会调用startSystemServer方法启动系统服务器,系统服务器用来运行Android平台需要的一些主要的本地服务
startSystemServer

private static boolean startSystemServer()throws MethodAndArgsCaller, RuntimeException {

    //该数组保存SystemServer的启动参数
    String args[] = {
        "--setuid=1000",    //uid
        "--setgid=1000",    //gid
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
        "--capabilities=130104352,130104352",
        "--runtime-init",
        "--nice-name=system_server",    //进程名
        "com.android.server.SystemServer",  //启动的类名
    };
    ZygoteConnection.Arguments parsedArgs = null;
    int pid;
    try {
        //把上面字符串数组参数转换成Arguments对象
        parsedArgs = new ZygoteConnection.Arguments(args);
        int debugFlags = parsedArgs.debugFlags;
        if("1".equals(SystemProperties.get("ro.debuggable")))
            debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
        //fork一个子进程
        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
    throw new RuntimeException(ex);
    }
    //如果pid为0,表示处在子进程中,也就是处于system_server进程中
    if (pid == 0) {
        //system_server进程工作
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

与运行其他应用程序不同,startSystemServer方法会调用forkSystemServer()方法来创建新进程,并运行SystemServer。系统在运行普通Android应用程序时,只负责创建应用程序进程,至于进程是否创建成功并不检查。与此不同,SystemServer是必须运行的,因此在forkSystemServer()方法中必须检查生成的SystemServer进程是否正常

在生成的SystemServer进程中运行com.android.server.SystemServer类的main()方法
main

public static void main(String[] args) {
    ...
    VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
    System.loadLibrary("android_servers");
    init1(args);
}

执行main()方法时会加载名称为android_server的本地库。
本地库加载完毕后,继续加载init1()函数,它是一个JNI本地方法。init1()函数调用system_init()函数,启动Audio Flinger、Surface Flinger、MediaPlayerService、CameraService等本地服务
system_init

extern "C" status_t system_init()
{
    ...
    if (strcmp(propBuf, "1") == 0) {
        SurfaceFlinger::instantiate();
    }

    if (!proc->supportsProcesses()) {
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
    }
    ...
    AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    ...
    runtime->callStatic("com/android/server/SystemServer", "init2");

    if (proc->supportsProcesses()) {
        LOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        LOGI("System server: exiting thread pool.\n");
    }
    return NO_ERROR;
}

本地服务组成完毕后,再此调用SystemServer类的静态方法init2(),init2()方法创建android.server.ServerThread线程,并启动它,从而运行Android Framework的主要服务
init2

public static final void init2() {
    Slog.i(TAG, "Entered the Android system server!");
    Thread thr = new ServerThread();
    thr.setName("android.server.ServerThread");
    thr.start();
}

当ServerThread线程创建好并运行后,Thread类的run()方法被调用,此时ServerThread类中重定义的run()方法被调用。在run()方法中包含主要服务生成与注册的代码
当所有服务正常启动后,Zygote才做好运行新应用程序的准备

处理新Android应用程序运行请求

监视UDS,若收到新Android应用程序生成请求,则进入处理循环

在SystemServer运行后,程序会进入一个循环,处理来自多有绑定的套接字的请求,若ZYGOTE_FORK_MODE为false,程序就会调用runSelectLoopMode()方法,直到Zygote进程终止,该方法才会返回
runSelectLoopMode

private static void runSelectLoopMode() throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList();
    ArrayList<ZygoteConnection> peers = new ArrayList();
    FileDescriptor[] fdArray = new FileDescriptor[4];
    //sServerSocket是我们先前在registerZygoteSocket中建立的Socket
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    int loopCount = GC_LOOP_COUNT;
    while (true) {
        int index;

        if (loopCount <= 0) {
            gc();
            loopCount = GC_LOOP_COUNT;
        } else {
            loopCount--;
        }

        try {
            fdArray = fds.toArray(fdArray);
            /*
                selectReadable内部调用select,使用多路复用I/O模型
                当有客户端连接或有数据时,则selectReadable就会返回
            */
            index = selectReadable(fdArray);
        } catch (IOException ex) {
            throw new RuntimeException("Error in select()", ex);
        }

        if (index < 0) {
            throw new RuntimeException("Error in select()");
        } else if (index == 0) {
            ZygoteConnection newPeer = acceptCommandPeer();
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            boolean done;
            //客户端发送了请求,peers.get返回的是ZygoteConnection
            done = peers.get(index).runOnce();

            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

runOnce

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        //读取请求信息,请求信息包含创建新进程的参数选项
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        Log.w(TAG, "IOException on command socket " + ex.getMessage());
        closeSocket();
        return true;
    }
    if (args == null) {
        closeSocket();
        return true;
    }
    PrintStream newStderr = null;
    if (descriptors != null && descriptors.length >= 3) {
        newStderr = new PrintStream(
        new FileOutputStream(descriptors[2]));
    }
    int pid;
    try {
        /*
        分析请求信息中的字符串数组,为运行进程设置好各个选项,具体
        包括了设置应用程序的gid、uid、调试标记处理,设置rlimit,以及检查运行权限等
        */
        parsedArgs = new Arguments(args);
        applyUidSecurityPolicy(parsedArgs, peer);
        applyDebuggerSecurityPolicy(parsedArgs);
        applyRlimitSecurityPolicy(parsedArgs, peer);
        applyCapabilitiesSecurityPolicy(parsedArgs, peer);

        int[][] rlimits = null;

        if (parsedArgs.rlimits != null) {
            rlimits = parsedArgs.rlimits.toArray(intArray2d);
        }
        //创建新进程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
        parsedArgs.gids, parsedArgs.debugFlags, rlimits);
    } catch (IllegalArgumentException ex) {
        logAndPrintError (newStderr, "Invalid zygote arguments", ex);
        pid = -1;
    } catch (ZygoteSecurityException ex) {
        logAndPrintError(newStderr,"Zygote security policy preventsrequest: ", ex);
        pid = -1;
    }
    if (pid == 0) {
        handleChildProc(parsedArgs, descriptors, newStderr);
        return true;
    } else { 
        return handleParentProc(pid, descriptors, parsedArgs);
    }
}

参考资料

Amdroid框架揭秘
深入理解Android卷I