现在的位置: 首页 > 综合 > 正文

Dalvik虚拟机的启动过程分析

2013年10月01日 ⁄ 综合 ⁄ 共 4706字 ⁄ 字号 评论关闭

在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

  1. void AndroidRuntime::start(const char* className, const bool startSystemServer)  
  2. {  
  3.     ......  
  4.   
  5.     /* start the virtual machine */  
  6.     if (startVm(&mJavaVM, &env) != 0)  
  7.         goto bail;  
  8.   
  9.     /* 
  10.      * Register android functions. 
  11.      */  
  12.     if (startReg(env) < 0) {  
  13.         LOGE("Unable to register all android natives\n");  
  14.         goto bail;  
  15.     }  
  16.   
  17.     ......  
  18.   
  19.     /* 
  20.      * Start VM.  This thread becomes the main thread of the VM, and will 
  21.      * not return until the VM exits. 
  22.      */  
  23.     jclass startClass;  
  24.     jmethodID startMeth;  
  25.   
  26.     slashClassName = strdup(className);  
  27.     for (cp = slashClassName; *cp != '\0'; cp++)  
  28.         if (*cp == '.')  
  29.             *cp = '/';  
  30.   
  31.     startClass = env->FindClass(slashClassName);  
  32.     if (startClass == NULL) {  
  33.         LOGE("JavaVM unable to locate class '%s'\n", slashClassName);  
  34.         /* keep going */  
  35.     } else {  
  36.         startMeth = env->GetStaticMethodID(startClass, "main",  
  37.             "([Ljava/lang/String;)V");  
  38.         if (startMeth == NULL) {  
  39.             LOGE("JavaVM unable to find main() in '%s'\n", className);  
  40.             /* keep going */  
  41.         } else {  
  42.             env->CallStaticVoidMethod(startClass, startMeth, strArray);  
  43.             ......  
  44.         }  
  45.     }  
  46.   
  47.     LOGD("Shutting down VM\n");  
  48.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
  49.         LOGW("Warning: unable to detach main thread\n");  
  50.     if (mJavaVM->DestroyJavaVM() != 0)  
  51.         LOGW("Warning: VM did not shut down cleanly\n");  
  52.   
  53.     ......  
  54. }  

        这个函数定义在文件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

  1. int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)  
  2. {  
  3.     int result = -1;  
  4.     JavaVMInitArgs initArgs;  
  5.     JavaVMOption opt;  
  6.     ......  
  7.   
  8.     property_get("dalvik.vm.checkjni", propBuf, "");  
  9.     if (strcmp(propBuf, "true") == 0) {  
  10.         checkJni = true;  
  11.     } else if (strcmp(propBuf, "false") != 0) {  
  12.         /* property is neither true nor false; fall back on kernel parameter */  
  13.         property_get("ro.kernel.android.checkjni", propBuf, "");  
  14.         if (propBuf[0] == '1') {  
  15.             checkJni = true;  
  16.         }  
  17.     }  
  18.     ......  
  19.   
  20.     property_get("dalvik.vm.execution-mode", propBuf, "");  
  21.     if (strcmp(propBuf, "int:portable") == 0) {  
  22.         executionMode = kEMIntPortable;  
  23.     } else if (strcmp(propBuf, "int:fast") == 0) {  
  24.         executionMode = kEMIntFast;  
  25. #if defined(WITH_JIT)  
  26.     } else if (strcmp(propBuf, "int:jit") == 0) {  
  27.         executionMode = kEMJitCompiler;  
  28. #endif  
  29.     }  
  30.   
  31.     property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");  
  32.     ......  
  33.   
  34.     strcpy(heapsizeOptsBuf, "-Xmx");  
  35.     property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");  
  36.     //LOGI("Heap size: %s", heapsizeOptsBuf);  
  37.     opt.optionString = heapsizeOptsBuf;  
  38.     mOptions.add(opt);  
  39.     ......  
  40.   
  41.     if (checkJni) {  
  42.         /* extended JNI checking */  
  43.         opt.optionString = "-Xcheck:jni";  
  44.         mOptions.add(opt);  
  45.   
  46.         ......  
  47.     }  
  48.     ......  
  49.   
  50.     if
【上篇】
【下篇】

抱歉!评论已关闭.