基于性能的考虑,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。