Zygote启动分析

来源:互联网 发布:古代画家排名知乎 编辑:程序博客网 时间:2024/04/27 15:12

         基于性能的考虑,Dalvik虚拟机只启动一次,新的实例将从第一次启动的Dalvik中拷贝。这个功能是通过系统服务Zygote来实现的。

   Zygote的启动过程简述如下:首先,它预初始化和预加载通用的Android类到它的堆中。然后,它监听在Socket端口上,等待启动一个新的Android应用程序的命令。当接收到一个启动应用程序命令,它将利用已经加载的应用程序fork出一个新的进程。该进程就是被启动的应用程序,且与原始的Zygote进程共享同一个写时复制(copy-on-write)映射的堆。因此,Zygote的堆被链接到该新进程。如果该应用程序只从堆中读取数据,那么就一直与Zygote共享堆。但是,一旦应用程序在堆上执行写操作,那么堆对应的内存页被会被复制且会链接到新页上。这样,应用程序就可以修改过堆中的数据而不用担心会影响Zygote进程的堆了。

当一个新的Android应用程序产生时,它使用Zygote的内存布局,因此,对每个应用程序来说,它们的内存布局是一样的。

         下面分析一下代码的流程:

1.  根据init.rc的启动服务的命令,将运行/system/bin/app_process启动zygote。 app_process的命令参数形式为:app_process[java-options] cmd-dir start-class-name [options],

由此可知,传入虚拟机的参数为-Xzygote,首先,-X一般是虚拟机的非标准选项,允许虚拟机定义一些特别的选项,其中zygote就是dalvik虚拟机定义的特制的选项,表示当前运行在zygote模式。在zygote模式下,虚拟机不会启动额外的线程。命令所在的目录是/system/bin,传给app_process的参数是--zygote和--start-system-server。这两个参数表示当前启动的进程名字叫zygote,并且要启动SystemServer。

 

    while (i < argc) {

        const char* arg = argv[i++];

        if (!parentDir) {

            parentDir = arg;

        } else if (strcmp(arg, "--zygote") == 0) {

            zygote = true;

            niceName = "zygote";

        } else if (strcmp(arg, "--start-system-server") == 0) {

            startSystemServer = true;

        } else if (strcmp(arg, "--application") == 0) {

            application = true;

        } else if (strncmp(arg, "--nice-name=", 12) == 0) {

            niceName = arg + 12;

        } else {

            className = arg;

            break;

        }

    }

 

 

2. 接下来,将启动ZygoteInit这个类。在启动这个类之前,会调用startVM(JavaVM** pJavaVM, JNIEnv** pEnv)创建一个dalvik虚拟机,其中JavaVM代表dalvik虚拟机的一个实例,每个进程只有一个实例,JNIEnv代表一个dalvik虚拟机运行环境,每个线程拥有一个实例。接下来通过调用startReg(env)来向虚拟机注册一些JNI本地函数。最后进入ZygoteInit类中的入口函数main中去运行。

 

    if (zygote) {

        runtime.start("com.android.internal.os.ZygoteInit",

                startSystemServer ? "start-system-server" : "");

    } else if (className) {

 

在Android::start()方法中,启动虚拟机以及注册Android的JNI本地函数。

 

void AndroidRuntime::start(const char* className, const char* options)

{

         ...

 

    /* start the virtual machine */

    JNIEnv* env;

    if (startVm(&mJavaVM, &env) != 0) {

        return;

    }

    onVmCreated(env);

 

    /*

     * Register android functions.

     */

    if (startReg(env) < 0) {

        ALOGE("Unable to register all android natives\n");

        return;

    }

 

   ...

 

    /*

     * Start VM.  This thread becomes the main thread of the VM, and will

     * not return until the VM exits.

     */

    char* slashClassName = toSlashClassName(className);

    jclass startClass = env->FindClass(slashClassName);

    if (startClass == NULL) {

        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);

        /* keep going */

    } else {

        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",

            "([Ljava/lang/String;)V");

        if (startMeth == NULL) {

            ALOGE("JavaVM unable to find main() in '%s'\n", className);

            /* keep going */

        } else {

            env->CallStaticVoidMethod(startClass, startMeth, strArray);

 

#if 0

            if (env->ExceptionCheck())

                threadExitUncaughtException(env);

#endif

        }

    }

         ...

}

 

3. 接下来,将进入ZygoteInit的main方法,首先registerZygoteSocket()会注册一个服务器端的本地Socket,Socket的路径由环境变量ANDROID_SOCKET_zygote指定。它的主要目的是监听启动应用程序的命令请求,并fork一个子进程来处理启动相应的应用程序。然后,preload()函数会预加载一些资源和一些通用类(由preloaded-classes资源文件指定)。接下来,调用startSystemServer()来启动SystemServer进程。主线程继续执行代码,最后阻塞在runSelectLoop(),在该函数中将接受请求,并fork子进程来处理。

 

   public static void main(String argv[]) {

        try {

                            ...

 

            registerZygoteSocket();

                            ...

            preload();

                            ...

            if (argv[1].equals("start-system-server")) {

                startSystemServer();

            } else if (!argv[1].equals("")) {

                throw new RuntimeException(argv[0] + USAGE_STRING);

            }

 

            Log.i(TAG, "Accepting command socket connections");

 

            runSelectLoop();

 

            closeServerSocket();

        } catch (MethodAndArgsCaller caller) {

            caller.run();

        } catch (RuntimeException ex) {

            Log.e(TAG, "Zygote died with exception", ex);

            closeServerSocket();

            throw ex;

        }

    }

 

4. 最后我们看一下,如何启动SystemServer。

     在startSystemServer()中,进入handleSystemServerProcess(…)。最终调用的是RuntimeInit.zygoteInit(…),这个函数会执行一些通用的初始化,最后通过applicationInit(…)调用com.android.server.SystemServer的main函数。

 

5. SystemServer会开启一个ServerThread线程,在该线程中启动一系列服务后,最后会通过ActivityManagerService.self().systemReady(…) -> resumeTopActivityLocked->startHomeActivityLocked启动Home Activity,即Launcher。

0 0