在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的。Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例。在本文中,我们就分析Dalvik虚拟机在Zygote进程中的启动过程。
老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!
Zygote进程在启动的过程中,除了会创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中来,以及注册一些Android核心类的JNI方法来前面创建的Dalvik虚拟机实例中去。注意,一个应用程序进程被Zygote进程孵化出来的时候,不仅会获得Zygote进程中的Dalvik虚拟机实例拷贝,还会与Zygote一起共享Java运行时库,这完全得益于Linux内核的进程创建机制(fork)。这种Zygote孵化机制的优点是不仅可以快速地启动一个应用程序进程,还可以节省整体的内存消耗,缺点是会影响开机速度,毕竟Zygote是在开机过程中启动的。不过,总体来说,是利大于弊的,毕竟整个系统只有一个Zygote进程,而可能有无数个应用程序进程,而且我们不会经常去关闭手机,大多数情况下只是让它进入休眠状态。
从前面Android系统进程Zygote启动过程的源代码分析一文可以知道,Zygote进程在启动的过程中,会调用到AndroidRuntime类的成员函数start,接下来我们就这个函数开始分析Dalvik虚拟机启动相关的过程,如图1所示:
图1 Dalvik虚拟机的启动过程
这个过程可以分为8个步骤,接下来我们就详细分析每一个步骤。
Step 1. AndroidRuntime.start
- void AndroidRuntime::start(const char* className, const bool startSystemServer)
- {
- ......
- /* start the virtual machine */
- if (startVm(&mJavaVM, &env) != 0)
- goto bail;
- /*
- * Register android functions.
- */
- if (startReg(env) < 0) {
- LOGE("Unable to register all android natives\n");
- goto bail;
- }
- ......
- /*
- * Start VM. This thread becomes the main thread of the VM, and will
- * not return until the VM exits.
- */
- jclass startClass;
- jmethodID startMeth;
- slashClassName = strdup(className);
- for (cp = slashClassName; *cp != '\0'; cp++)
- if (*cp == '.')
- *cp = '/';
- startClass = env->FindClass(slashClassName);
- if (startClass == NULL) {
- LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
- /* keep going */
- } else {
- startMeth = env->GetStaticMethodID(startClass, "main",
- "([Ljava/lang/String;)V");
- if (startMeth == NULL) {
- LOGE("JavaVM unable to find main() in '%s'\n", className);
- /* keep going */
- } else {
- env->CallStaticVoidMethod(startClass, startMeth, strArray);
- ......
- }
- }
- LOGD("Shutting down VM\n");
- if (mJavaVM->DetachCurrentThread() != JNI_OK)
- LOGW("Warning: unable to detach main thread\n");
- if (mJavaVM->DestroyJavaVM() != 0)
- LOGW("Warning: VM did not shut down cleanly\n");
- ......
- }
这个函数定义在文件frameworks/base/core/jni/AndroidRuntime.cpp中。
AndroidRuntime类的成员函数start主要做了以下四件事情:
1. 调用成员函数startVm来创建一个Dalvik虚拟机实例,并且保存在成员变量mJavaVM中。
2. 调用成员函数startReg来注册一些Android核心类的JNI方法。
3. 调用参数className所描述的一个Java类的静态成员函数main,来作为Zygote进程的Java层入口。从前面Android系统进程Zygote启动过程的源代码分析一文可以知道,这个入口类就为com.android.internal.os.ZygoteInit。执行这一步的时候,Zygote进程中的Dalvik虚拟机实例就开始正式运作了。注意,在这一步中,也就是在com.android.internal.os.ZygoteInit类的静态成员函数main,会进行大量的Android核心类和系统资源文件预加载。其中,预加载的Android核心类可以参考frameworks/base/preloaded-classes这个文件,而预加载的系统资源就是包含在/system/framework/framework-res.apk中。
4. 从com.android.internal.os.ZygoteInit类的静态成员函数main返回来的时候,就说明Zygote进程准备要退出来了。在退出之前,会调用前面创建的Dalvik虚拟机实例的成员函数DetachCurrentThread和DestroyJavaVM。其中,前者用来将Zygote进程的主线程脱离前面创建的Dalvik虚拟机实例,后者是用来销毁前面创建的Dalvik虚拟机实例。
接下来,我们就主要关注Dalvik虚拟机实例的创建过程,以及Android核心类JNI方法的注册过程,即AndroidRuntime类的成员函数startVm和startReg的实现。
Step 2. AndroidRuntime.startVm
- int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
- {
- int result = -1;
- JavaVMInitArgs initArgs;
- JavaVMOption opt;
- ......
- property_get("dalvik.vm.checkjni", propBuf, "");
- if (strcmp(propBuf, "true") == 0) {
- checkJni = true;
- } else if (strcmp(propBuf, "false") != 0) {
- /* property is neither true nor false; fall back on kernel parameter */
- property_get("ro.kernel.android.checkjni", propBuf, "");
- if (propBuf[0] == '1') {
- checkJni = true;
- }
- }
- ......
- property_get("dalvik.vm.execution-mode", propBuf, "");
- if (strcmp(propBuf, "int:portable") == 0) {
- executionMode = kEMIntPortable;
- } else if (strcmp(propBuf, "int:fast") == 0) {
- executionMode = kEMIntFast;
- #if defined(WITH_JIT)
- } else if (strcmp(propBuf, "int:jit") == 0) {
- executionMode = kEMJitCompiler;
- #endif
- }
- property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
- ......
- strcpy(heapsizeOptsBuf, "-Xmx");
- property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
- //LOGI("Heap size: %s", heapsizeOptsBuf);
- opt.optionString = heapsizeOptsBuf;
- mOptions.add(opt);
- ......
- if (checkJni) {
- /* extended JNI checking */
- opt.optionString = "-Xcheck:jni";
- mOptions.add(opt);
- ......
- }
- ......
- if