Zygote進程【1】——Zygote的誕生

Android中存在着C和Java兩個徹底不一樣的世界,前者直接創建在Linux的基礎上,後者直接創建在JVM的基礎上。zygote的中文名字爲「受精卵」,這個名字很好的詮釋了zygote進程的做用。做爲java世界的孵化者,zygote自己是一個native程序,是由init根據init.rc文件中的配置項建立的。php

@/system/core/rootdir/init.rchtml

  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
  2.     class main  
  3.     socket zygote stream 660 root system  
  4.     onrestart write /sys/android_power/request_state wake  
  5.     onrestart write /sys/power/state on  
  6.     onrestart restart media  
  7.     onrestart restart netd  

關於init是如何解析和建立zygote進程的,這裏再也不贅述,不明的同窗能夠參考init進程【2】——解析配置文件一文。這裏解析一下上面的第一行:service是rc腳本中的一種SECTION,zygote表示service的名字,/system/bin/app_process表示service的路徑,-Xzygote /system/bin --zygote --start-system-server則表示傳入的參數。java

zygote的實如今app_main.cpp中:linux

@frameworks/base/cmds/app_process/app_main.cppandroid

  1. int main(int argc, char* const argv[])  
  2. {  
  3. //針對ARM平臺的特殊邏輯  
  4. #ifdef __arm__  
  5.     /* 
  6.      * b/7188322 - Temporarily revert to the compat memory layout 
  7.      * to avoid breaking third party apps. 
  8.      * 
  9.      * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. 
  10.      * 
  11.      * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 
  12.      * changes the kernel mapping from bottom up to top-down. 
  13.      * This breaks some programs which improperly embed 
  14.      * an out of date copy of Android's linker. 
  15.      */  
  16.     char value[PROPERTY_VALUE_MAX];  
  17.     property_get("ro.kernel.qemu", value, "");  
  18.     bool is_qemu = (strcmp(value, "1") == 0);  
  19.     if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {  
  20.         int current = personality(0xFFFFFFFF);  
  21.         if ((current & ADDR_COMPAT_LAYOUT) == 0) {  
  22.             personality(current | ADDR_COMPAT_LAYOUT);  
  23.             setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);  
  24.             execv("/system/bin/app_process", argv);  
  25.             return -1;  
  26.         }  
  27.     }  
  28.     unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");  
  29. #endif  
  30.   
  31.     // These are global variables in ProcessState.cpp  
  32.     mArgC = argc;  
  33.     mArgV = argv;  
  34.   
  35.     mArgLen = 0;  
  36.     for (int i=0; i<argc; i++) {  
  37.         mArgLen += strlen(argv[i]) + 1;  
  38.     }  
  39.     mArgLen--;  
  40.   
  41.     AppRuntime runtime;  
  42.     const char* argv0 = argv[0];  
  43.   
  44.     // Process command line arguments  
  45.     // ignore argv[0]  
  46.     argc--;  
  47.     argv++;  
  48.   
  49.     // Everything up to '--' or first non '-' arg goes to the vm  
  50.   
  51.     int i = runtime.addVmArguments(argc, argv);  
  52.   
  53.     // Parse runtime arguments.  Stop at first unrecognized option.  
  54.     bool zygote = false;  
  55.     bool startSystemServer = false;  
  56.     bool application = false;  
  57.     const char* parentDir = NULL;  
  58.     const char* niceName = NULL;  
  59.     const char* className = NULL;  
  60.     while (i < argc) {//根據傳入的參數,初始化啓動zygote所需的參數  
  61.         const char* arg = argv[i++];  
  62.         if (!parentDir) {  
  63.             parentDir = arg;  
  64.         } else if (strcmp(arg, "--zygote") == 0) {  
  65.             zygote = true;  
  66.             niceName = "zygote";  
  67.         } else if (strcmp(arg, "--start-system-server") == 0) {  
  68.             startSystemServer = true;  
  69.         } else if (strcmp(arg, "--application") == 0) {  
  70.             application = true;  
  71.         } else if (strncmp(arg, "--nice-name=", 12) == 0) {  
  72.             niceName = arg + 12;  
  73.         } else {  
  74.             className = arg;  
  75.             break;  
  76.         }  
  77.     }  
  78.   
  79.     if (niceName && *niceName) {  
  80.         setArgv0(argv0, niceName);  
  81.         set_process_name(niceName);//設置本進程的名稱爲zygote,至此進程有app_process變爲了zygote  
  82.     }  
  83.   
  84.     runtime.mParentDir = parentDir;  
  85.   
  86.     if (zygote) {//根據咱們傳入的參考,這裏的zygote值爲TRUE  
  87.         runtime.start("com.android.internal.os.ZygoteInit",  
  88.                 startSystemServer ? "start-system-server" : "");  
  89.     } else if (className) {//能夠看出除了zygote,RuntimeInit也是在這裏啓動的  
  90.         // Remainder of args get passed to startup class main()  
  91.         runtime.mClassName = className;  
  92.         runtime.mArgC = argc - i;  
  93.         runtime.mArgV = argv + i;  
  94.         runtime.start("com.android.internal.os.RuntimeInit",  
  95.                 application ? "application" : "tool");  
  96.     } else {  
  97.         fprintf(stderr, "Error: no class name or --zygote supplied.\n");  
  98.         app_usage();  
  99.         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");  
  100.         return 10;  
  101.     }  
  102. }  

經過對main()函數的分析,能夠看出main()主要根據傳入的參數初始化啓動參數,具體的啓動過程是由AppRuntime完成的。AppRuntime的聲明和實現都在app_main.cpp中,它繼承自AndroidRuntime,AppRuntime的實現以下:git


能夠看出start是AndroidRuntime中的方法。經過start函數前面的註釋咱們瞭解到它的主要做用是:啓動Android運行時環境,包括啓動虛擬機和調用className參數所指定的類的main()方法(即:Java中的main方法)。
  1. /* 
  2.  * Start the Android runtime.  This involves starting the virtual machine 
  3.  * and calling the "static void main(String[] args)" method in the class 
  4.  * named by "className". 
  5.  * 
  6.  * Passes the main function two arguments, the class name and the specified 
  7.  * options string. 
  8.  */  
  9. void AndroidRuntime::start(const char* className, const char* options)  
  10. {  
  11.     ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",  
  12.             className != NULL ? className : "(unknown)");  
  13.   
  14.     /* 
  15.      * 'startSystemServer == true' means runtime is obsolete and not run from 
  16.      * init.rc anymore, so we print out the boot start event here. 
  17.      */  
  18.     if (strcmp(options, "start-system-server") == 0) {  
  19.         /* track our progress through the boot sequence */  
  20.         const int LOG_BOOT_PROGRESS_START = 3000;  
  21.         LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  
  22.                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));  
  23.     }  
  24.   
  25.     //環境變量ANDROID_ROOT是否已經設置,若是未設置,則設置其值爲"/system"  
  26.     const char* rootDir = getenv("ANDROID_ROOT");  
  27.     if (rootDir == NULL) {  
  28.         rootDir = "/system";  
  29.         if (!hasDir("/system")) {  
  30.             LOG_FATAL("No root directory specified, and /android does not exist.");  
  31.             return;  
  32.         }  
  33.         setenv("ANDROID_ROOT", rootDir, 1);  
  34.     }  
  35.   
  36.     //const char* kernelHack = getenv("LD_ASSUME_KERNEL");  
  37.     //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);  
  38.   
  39.     /* start the virtual machine */  
  40.     JniInvocation jni_invocation;  
  41.     jni_invocation.Init(NULL);  
  42.     JNIEnv* env;  
  43.     if (startVm(&mJavaVM, &env) != 0) {//啓動Java虛擬機  
  44.         return;  
  45.     }  
  46.     onVmCreated(env);//空函數  
  47.   
  48.     /* 
  49.      * Register android functions. 
  50.      */  
  51.     if (startReg(env) < 0) {//註冊Android JNI函數  
  52.         ALOGE("Unable to register all android natives\n");  
  53.         return;  
  54.     }  
  55.   
  56.     /* 
  57.      * We want to call main() with a String array with arguments in it. 
  58.      * At present we have two arguments, the class name and an option string. 
  59.      * Create an array to hold them. 
  60.      */  
  61.     jclass stringClass;  
  62.     jobjectArray strArray;  
  63.     jstring classNameStr;  
  64.     jstring optionsStr;  
  65.   
  66.     stringClass = env->FindClass("java/lang/String");//JNI中調用java中的String類  
  67.     assert(stringClass != NULL);  
  68.     //建立包含2個元素的String數組,這裏至關於Java中的String strArray[] = new String[2]  
  69.     strArray = env->NewObjectArray(2, stringClass, NULL);  
  70.     assert(strArray != NULL);  
  71.     classNameStr = env->NewStringUTF(className);//classNameStr的值爲"com.android.internal.os.ZygoteInit"  
  72.     assert(classNameStr != NULL);  
  73.     env->SetObjectArrayElement(strArray, 0, classNameStr);  
  74.     optionsStr = env->NewStringUTF(options);//optionsStr的值爲"start-system-server"  
  75.     env->SetObjectArrayElement(strArray, 1, optionsStr);  
  76.   
  77.     /* 
  78.      * Start VM.  This thread becomes the main thread of the VM, and will 
  79.      * not return until the VM exits. 
  80.      */  
  81.     char* slashClassName = toSlashClassName(className);//將"com.android.internal.os.ZygoteInit"中的"."替換成"/"供JNI調用  
  82.     jclass startClass = env->FindClass(slashClassName);  
  83.     if (startClass == NULL) {  
  84.         ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);  
  85.         /* keep going */  
  86.     } else {  
  87.         jmethodID startMeth = env->GetStaticMethodID(startClass, "main",  
  88.             "([Ljava/lang/String;)V");//ZygoteInit類中的main()方法  
  89.         if (startMeth == NULL) {  
  90.             ALOGE("JavaVM unable to find main() in '%s'\n", className);  
  91.             /* keep going */  
  92.         } else {  
  93.             env->CallStaticVoidMethod(startClass, startMeth, strArray);//經過JNI調用main()方法  
  94.   
  95. #if 0  
  96.             if (env->ExceptionCheck())  
  97.                 threadExitUncaughtException(env);  
  98. #endif  
  99.         }  
  100.     }  
  101.     free(slashClassName);  
  102.   
  103.     //若是JVM退出。這兩句代碼通常來講執行不到  
  104.     ALOGD("Shutting down VM\n");  
  105.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
  106.         ALOGW("Warning: unable to detach main thread\n");  
  107.     if (mJavaVM->DestroyJavaVM() != 0)  
  108.         ALOGW("Warning: VM did not shut down cleanly\n");  
  109. }  
經過上面對start()函數的分析能夠發現,在start()中主要完成了以下三項工做:
  1. 啓動JVM。
  2. 註冊Android JNI函數。
  3. 調用ZygoteInit的main()方法。

建立Java虛擬機

start()中與建立虛擬機相關的代碼以下:
  1. /* start the virtual machine */  
  2. JniInvocation jni_invocation;  
  3. jni_invocation.Init(NULL);  
  4. JNIEnv* env;  
  5. if (startVm(&mJavaVM, &env) != 0) {//啓動Java虛擬機  
  6.     return;  
  7. }  
  8. onVmCreated(env);//空函數  
這裏代碼中  建立一個JniInvocation實例,而且調用它的成員函數init來初始化JNI環境:
@/libnativehelper/jniInvocation.cpp
  1. bool JniInvocation::Init(const char* library) {  
  2. #ifdef HAVE_ANDROID_OS  
  3.   char default_library[PROPERTY_VALUE_MAX];  
  4.   property_get("persist.sys.dalvik.vm.lib", default_library, "libdvm.so");  
  5. #else  
  6.   const char* default_library = "libdvm.so";  
  7. #endif  
  8.   if (library == NULL) {  
  9.     library = default_library;  
  10.   }  
  11.   
  12.   handle_ = dlopen(library, RTLD_NOW);  
  13.   if (handle_ == NULL) {  
  14.     ALOGE("Failed to dlopen %s: %s", library, dlerror());  
  15.     return false;  
  16.   }  
  17.   if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),  
  18.                   "JNI_GetDefaultJavaVMInitArgs")) {  
  19.     return false;  
  20.   }  
  21.   if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),  
  22.                   "JNI_CreateJavaVM")) {  
  23.     return false;  
  24.   }  
  25.   if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),  
  26.                   "JNI_GetCreatedJavaVMs")) {  
  27.     return false;  
  28.   }  
  29.   return true;  
  30. }  
JniInvocation類的成員函數init所作的事情很簡單。它首先是讀取系統屬性persist.sys.dalvik.vm.lib的值。系統屬性persist.sys.dalvik.vm.lib的值要麼等於libdvm.so,要麼等於libart.so,這兩個so庫分別對應着Dalvik虛擬機和ART虛擬機環境。
在初始化完虛擬機環境後,接下來調用startVm()來建立虛擬機。
@/frameworks/base/core/jni/AndroidRuntime.cpp
  1. /* 
  2.  * Start the Dalvik Virtual Machine. 
  3.  * 
  4.  * Various arguments, most determined by system properties, are passed in. 
  5.  * The "mOptions" vector is updated. 
  6.  * 
  7.  * Returns 0 on success. 
  8.  */  
  9. int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)  
  10. {  
  11.     int result = -1;  
  12.     JavaVMInitArgs initArgs;  
  13.     JavaVMOption opt;  
  14.     char propBuf[PROPERTY_VALUE_MAX];  
  15.     char stackTraceFileBuf[PROPERTY_VALUE_MAX];  
  16.     char dexoptFlagsBuf[PROPERTY_VALUE_MAX];  
  17.     char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];  
  18.     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];  
  19.     char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];  
  20.     char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];  
  21.     char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];  
  22.     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];  
  23.     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];  
  24.     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];  
  25.     char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];  
  26.     char extraOptsBuf[PROPERTY_VALUE_MAX];  
  27.     char* stackTraceFile = NULL;  
  28.     bool checkJni = false;  
  29.     bool checkDexSum = false;  
  30.     bool logStdio = false;  
  31.     enum {  
  32.       kEMDefault,  
  33.       kEMIntPortable,  
  34.       kEMIntFast,  
  35.       kEMJitCompiler,  
  36.     } executionMode = kEMDefault;  
  37.   
  38.   
  39.     property_get("dalvik.vm.checkjni", propBuf, "");  
  40.     if (strcmp(propBuf, "true") == 0) {  
  41.         checkJni = true;  
  42.     } else if (strcmp(propBuf, "false") != 0) {  
  43.         /* property is neither true nor false; fall back on kernel parameter */  
  44.         property_get("ro.kernel.android.checkjni", propBuf, "");  
  45.         if (propBuf[0] == '1') {  
  46.             checkJni = true;  
  47.         }  
  48.     }  
  49.   
  50.     property_get("dalvik.vm.execution-mode", propBuf, "");  
  51.     if (strcmp(propBuf, "int:portable") == 0) {  
  52.         executionMode = kEMIntPortable;  
  53.     } else if (strcmp(propBuf, "int:fast") == 0) {  
  54.         executionMode = kEMIntFast;  
  55.     } else if (strcmp(propBuf, "int:jit") == 0) {  
  56.         executionMode = kEMJitCompiler;  
  57.     }  
  58.   
  59.     property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");  
  60.   
  61.     property_get("dalvik.vm.check-dex-sum", propBuf, "");  
  62.     if (strcmp(propBuf, "true") == 0) {  
  63.         checkDexSum = true;  
  64.     }  
  65.   
  66.     property_get("log.redirect-stdio", propBuf, "");  
  67.     if (strcmp(propBuf, "true") == 0) {  
  68.         logStdio = true;  
  69.     }  
  70.   
  71.     strcpy(enableAssertBuf, "-ea:");  
  72.     property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");  
  73.   
  74.     strcpy(jniOptsBuf, "-Xjniopts:");  
  75.     property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");  
  76.   
  77.     /* route exit() to our handler */  
  78.     opt.extraInfo = (void*) runtime_exit;  
  79.     opt.optionString = "exit";  
  80.     mOptions.add(opt);  
  81.   
  82.     /* route fprintf() to our handler */  
  83.     opt.extraInfo = (void*) runtime_vfprintf;  
  84.     opt.optionString = "vfprintf";  
  85.     mOptions.add(opt);  
  86.   
  87.     /* register the framework-specific "is sensitive thread" hook */  
  88.     opt.extraInfo = (void*) runtime_isSensitiveThread;  
  89.     opt.optionString = "sensitiveThread";  
  90.     mOptions.add(opt);  
  91.   
  92.     opt.extraInfo = NULL;  
  93.   
  94.     /* enable verbose; standard options are { jni, gc, class } */  
  95.     //options[curOpt++].optionString = "-verbose:jni";  
  96.     opt.optionString = "-verbose:gc";  
  97.     mOptions.add(opt);  
  98.     //options[curOpt++].optionString = "-verbose:class";  
  99.   
  100.     /* 
  101.      * The default starting and maximum size of the heap.  Larger 
  102.      * values should be specified in a product property override. 
  103.      */  
  104.     strcpy(heapstartsizeOptsBuf, "-Xms");  
  105.     property_get("dalvik.vm.heapstartsize", heapstartsizeOptsBuf+4, "4m");  
  106.     opt.optionString = heapstartsizeOptsBuf;  
  107.     mOptions.add(opt);  
  108.     strcpy(heapsizeOptsBuf, "-Xmx");  
  109.     property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");  
  110.     opt.optionString = heapsizeOptsBuf;  
  111.     mOptions.add(opt);  
  112.   
  113.     // Increase the main thread's interpreter stack size for bug 6315322.  
  114.     opt.optionString = "-XX:mainThreadStackSize=24K";  
  115.     mOptions.add(opt);  
  116.   
  117.     // Set the max jit code cache size.  Note: size of 0 will disable the JIT.  
  118.     strcpy(jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");  
  119.     property_get("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf+19,  NULL);  
  120.     if (jitcodecachesizeOptsBuf[19] != '\0') {  
  121.       opt.optionString = jitcodecachesizeOptsBuf;  
  122.       mOptions.add(opt);  
  123.     }  
  124.   
  125.     strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");  
  126.     property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");  
  127.     if (heapgrowthlimitOptsBuf[20] != '\0') {  
  128.         opt.optionString = heapgrowthlimitOptsBuf;  
  129.         mOptions.add(opt);  
  130.     }  
  131.   
  132.     strcpy(heapminfreeOptsBuf, "-XX:HeapMinFree=");  
  133.     property_get("dalvik.vm.heapminfree", heapminfreeOptsBuf+16, "");  
  134.     if (heapminfreeOptsBuf[16] != '\0') {  
  135.         opt.optionString = heapminfreeOptsBuf;  
  136.         mOptions.add(opt);  
  137.     }  
  138.   
  139.     strcpy(heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");  
  140.     property_get("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf+16, "");  
  141.     if (heapmaxfreeOptsBuf[16] != '\0') {  
  142.         opt.optionString = heapmaxfreeOptsBuf;  
  143.         mOptions.add(opt);  
  144.     }  
  145.   
  146.     strcpy(heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");  
  147.     property_get("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf+26, "");  
  148.     if (heaptargetutilizationOptsBuf[26] != '\0') {  
  149.         opt.optionString = heaptargetutilizationOptsBuf;  
  150.         mOptions.add(opt);  
  151.     }  
  152.   
  153.     property_get("ro.config.low_ram", propBuf, "");  
  154.     if (strcmp(propBuf, "true") == 0) {  
  155.       opt.optionString = "-XX:LowMemoryMode";  
  156.       mOptions.add(opt);  
  157.     }  
  158.   
  159.     /* 
  160.      * Enable or disable dexopt features, such as bytecode verification and 
  161.      * calculation of register maps for precise GC. 
  162.      */  
  163.     property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, "");  
  164.     if (dexoptFlagsBuf[0] != '\0') {  
  165.         const char* opc;  
  166.         const char* val;  
  167.   
  168.         opc = strstr(dexoptFlagsBuf, "v=");     /* verification */  
  169.         if (opc != NULL) {  
  170.             switch (*(opc+2)) {  
  171.             case 'n':   val = "-Xverify:none";      break;  
  172.             case 'r':   val = "-Xverify:remote";    break;  
  173.             case 'a':   val = "-Xverify:all";       break;  
  174.             default:    val = NULL;                 break;  
  175.             }  
  176.   
  177.             if (val != NULL) {  
  178.                 opt.optionString = val;  
  179.                 mOptions.add(opt);  
  180.             }  
  181.         }  
  182.   
  183.         opc = strstr(dexoptFlagsBuf, "o=");     /* optimization */  
  184.         if (opc != NULL) {  
  185.             switch (*(opc+2)) {  
  186.             case 'n':   val = "-Xdexopt:none";      break;  
  187.             case 'v':   val = "-Xdexopt:verified";  break;  
  188.             case 'a':   val = "-Xdexopt:all";       break;  
  189.             case 'f':   val = "-Xdexopt:full";      break;  
  190.             default:    val = NULL;                 break;  
  191.             }  
  192.   
  193.             if (val != NULL) {  
  194.                 opt.optionString = val;  
  195.                 mOptions.add(opt);  
  196.             }  
  197.         }  
  198.   
  199.         opc = strstr(dexoptFlagsBuf, "m=y");    /* register map */  
  200.         if (opc != NULL) {  
  201.             opt.optionString = "-Xgenregmap";  
  202.             mOptions.add(opt);  
  203.   
  204.             /* turn on precise GC while we're at it */  
  205.             opt.optionString = "-Xgc:precise";  
  206.             mOptions.add(opt);  
  207.         }  
  208.     }  
  209.   
  210.     /* enable debugging; set suspend=y to pause during VM init */  
  211.     /* use android ADB transport */  
  212.     opt.optionString =  
  213.         "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";  
  214.     mOptions.add(opt);  
  215.   
  216.     ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");  
  217.     if (checkJni) {  
  218.         /* extended JNI checking */  
  219.         opt.optionString = "-Xcheck:jni";  
  220.         mOptions.add(opt);  
  221.   
  222.         /* set a cap on JNI global references */  
  223.         opt.optionString = "-Xjnigreflimit:2000";  
  224.         mOptions.add(opt);  
  225.   
  226.         /* with -Xcheck:jni, this provides a JNI function call trace */  
  227.         //opt.optionString = "-verbose:jni";  
  228.         //mOptions.add(opt);  
  229.     }  
  230.   
  231.     char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)];  
  232.     property_get("dalvik.vm.lockprof.threshold", propBuf, "");  
  233.     if (strlen(propBuf) > 0) {  
  234.       strcpy(lockProfThresholdBuf, "-Xlockprofthreshold:");  
  235.       strcat(lockProfThresholdBuf, propBuf);  
  236.       opt.optionString = lockProfThresholdBuf;  
  237.       mOptions.add(opt);  
  238.     }  
  239.   
  240.     /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */  
  241.     char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];  
  242.     property_get("dalvik.vm.jit.op", propBuf, "");  
  243.     if (strlen(propBuf) > 0) {  
  244.         strcpy(jitOpBuf, "-Xjitop:");  
  245.         strcat(jitOpBuf, propBuf);  
  246.         opt.optionString = jitOpBuf;  
  247.         mOptions.add(opt);  
  248.     }  
  249.   
  250.     /* Force interpreter-only mode for selected methods */  
  251.     char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];  
  252.     property_get("dalvik.vm.jit.method", propBuf, "");  
  253.     if (strlen(propBuf) > 0) {  
  254.         strcpy(jitMethodBuf, "-Xjitmethod:");  
  255.         strcat(jitMethodBuf, propBuf);  
  256.         opt.optionString = jitMethodBuf;  
  257.         mOptions.add(opt);  
  258.     }  
  259.   
  260.     if (executionMode == kEMIntPortable) {  
  261.         opt.optionString = "-Xint:portable";  
  262.         mOptions.add(opt);  
  263.     } else if (executionMode == kEMIntFast) {  
  264.         opt.optionString = "-Xint:fast";  
  265.         mOptions.add(opt);  
  266.     } else if (executionMode == kEMJitCompiler) {  
  267.         opt.optionString = "-Xint:jit";  
  268.         mOptions.add(opt);  
  269.     }  
  270.   
  271.     if (checkDexSum) {  
  272.         /* perform additional DEX checksum tests */  
  273.         opt.optionString = "-Xcheckdexsum";  
  274.         mOptions.add(opt);  
  275.     }  
  276.   
  277.     if (logStdio) {  
  278.         /* convert stdout/stderr to log messages */  
  279.         opt.optionString = "-Xlog-stdio";  
  280.         mOptions.add(opt);  
  281.     }  
  282.   
  283.     if (enableAssertBuf[4] != '\0') {  
  284.         /* accept "all" to mean "all classes and packages" */  
  285.         if (strcmp(enableAssertBuf+4, "all") == 0)  
  286.             enableAssertBuf[3] = '\0';  
  287.         ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);  
  288.         opt.optionString = enableAssertBuf;  
  289.         mOptions.add(opt);  
  290.     } else {  
  291.         ALOGV("Assertions disabled\n");  
  292.     }  
  293.   
  294.     if (jniOptsBuf[10] != '\0') {  
  295.         ALOGI("JNI options: '%s'\n", jniOptsBuf);  
  296.         opt.optionString = jniOptsBuf;  
  297.         mOptions.add(opt);  
  298.     }  
  299.   
  300.     if (stackTraceFileBuf[0] != '\0') {  
  301.         static const char* stfOptName = "-Xstacktracefile:";  
  302.   
  303.         stackTraceFile = (char*) malloc(strlen(stfOptName) +  
  304.             strlen(stackTraceFileBuf) +1);  
  305.         strcpy(stackTraceFile, stfOptName);  
  306.         strcat(stackTraceFile, stackTraceFileBuf);  
  307.         opt.optionString = stackTraceFile;  
  308.         mOptions.add(opt);  
  309.     }  
  310.   
  311.     /* extra options; parse this late so it overrides others */  
  312.     property_get("dalvik.vm.extra-opts", extraOptsBuf, "");  
  313.     parseExtraOpts(extraOptsBuf);  
  314.   
  315.     /* Set the properties for locale */  
  316.     {  
  317.         char langOption[sizeof("-Duser.language=") + 3];  
  318.         char regionOption[sizeof("-Duser.region=") + 3];  
  319.         strcpy(langOption, "-Duser.language=");  
  320.         strcpy(regionOption, "-Duser.region=");  
  321.         readLocale(langOption, regionOption);  
  322.         opt.extraInfo = NULL;  
  323.         opt.optionString = langOption;  
  324.         mOptions.add(opt);  
  325.         opt.optionString = regionOption;  
  326.         mOptions.add(opt);  
  327.     }  
  328.   
  329.     /* 
  330.      * We don't have /tmp on the device, but we often have an SD card.  Apps 
  331.      * shouldn't use this, but some test suites might want to exercise it. 
  332.      */  
  333.     opt.optionString = "-Djava.io.tmpdir=/sdcard";  
  334.     mOptions.add(opt);  
  335.   
  336.     initArgs.version = JNI_VERSION_1_4;  
  337.     initArgs.options = mOptions.editArray();  
  338.     initArgs.nOptions = mOptions.size();  
  339.     initArgs.ignoreUnrecognized = JNI_FALSE;  
  340.   
  341.     /* 
  342.      * Initialize the VM. 
  343.      * 
  344.      * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. 
  345.      * If this call succeeds, the VM is ready, and we can start issuing 
  346.      * JNI calls. 
  347.      */  
  348.     if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {  
  349.         ALOGE("JNI_CreateJavaVM failed\n");  
  350.         goto bail;  
  351.     }  
  352.   
  353.     result = 0;  
  354.   
  355. bail:  
  356.     free(stackTraceFile);  
  357.     return result;  
  358. }  
能夠看出這個函數的絕大部分都是在設置Java虛擬機的各項參數,沒有什麼好說。看到下面這一段變量定義,不知道你們有沒有去思考過,這裏爲何用PROPERTY_VALUE_MAX做爲初始大小?
  1. char propBuf[PROPERTY_VALUE_MAX];  
  2. char stackTraceFileBuf[PROPERTY_VALUE_MAX];  
  3. char dexoptFlagsBuf[PROPERTY_VALUE_MAX];  
  4. char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];  
  5. char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];  
  6. char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];  
  7. char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];  
  8. char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];  
  9. char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];  
  10. char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];  
  11. char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];  
  12. char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];  
下面是 PROPERTY_VALUE_MAX的定義:
@system/core/include/cutils/properties.h
  1. /* System properties are *small* name value pairs managed by the 
  2. ** property service.  If your data doesn't fit in the provided 
  3. ** space it is not appropriate for a system property. 
  4. ** 
  5. ** WARNING: system/bionic/include/sys/system_properties.h also defines 
  6. **          these, but with different names.  (TODO: fix that) 
  7. */  
  8. #define PROPERTY_KEY_MAX   PROP_NAME_MAX  
  9. #define PROPERTY_VALUE_MAX  PROP_VALUE_MAX  
因此,沒錯, PROPERTY_VALUE_MAX是Android中屬性value的最大長度,而java虛擬機的這些參數都是經過Android屬性賦值和控制的,因此他們的值得大小確定不能超過屬性的最大長度。下面是個人小米2S手機中的一部分Java參數。Android中全部屬性均可以經過getprop命令來查看。
  1. [dalvik.vm.heapconcurrentstart]: [2097152]  
  2. [dalvik.vm.heapgrowthlimit]: [96m]  
  3. [dalvik.vm.heapidealfree]: [8388608]  
  4. [dalvik.vm.heapsize]: [384m]  
  5. [dalvik.vm.heapstartsize]: [8m]  
  6. [dalvik.vm.heaputilization]: [0.25]  
  7. [dalvik.vm.stack-trace-file]: [/data/anr/traces.txt]  
下面來看一下startVm()中的最後幾句:
  1. /* 
  2.  * Initialize the VM. 
  3.  * 
  4.  * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. 
  5.  * If this call succeeds, the VM is ready, and we can start issuing 
  6.  * JNI calls. 
  7.  */  
  8. if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {  
  9.     ALOGE("JNI_CreateJavaVM failed\n");  
  10.     goto bail;  
  11. }  
startVm()在最後會調用JNI_CreateJavaVM()來建立虛擬機。這裏順便看一下JNI_CreateJavaVM()的這段說明:」Java虛擬機對象JavaVm對象每一個進程有一個,JNI環境變量JNIEnv每一個線程有一個「。這裏也告訴咱們,在寫JNI代碼時要注意: JNIEnv不能在任意線程中使用,必須是本來就是Java線程(Java代碼經過JNI調用native代碼時,發起調用的那個確定是Java線程),或者是讓已有的native線程經過JNI來attach到Java環境。具體這裏不作詳細介紹,感興趣的讀者能夠參考Oracle官方文檔http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html。在JNI_CreateJavaVM()調用成功後虛擬機VM就已經建立好了,接下來就能夠進行JNI相關調用了。

註冊JNI函數

建立好了虛擬機,接下來要給虛擬機註冊一些JNI函數。不知道各位讀者有沒有想過,這裏爲何要註冊JNI函數呢?沒錯,由於在基於虛擬機的Java世界裏,Java並非萬能的,它用到的不少方法(例如:音頻、視頻相關、Binder等)都須要以native的方式實現,而這些方法就須要虛擬機以JNI的方式進行加載。
@/frameworks/base/core/jni/AndroidRuntime.cpp
  1. /* 
  2.  * Register android native functions with the VM. 
  3.  */  
  4. /*static*/ int AndroidRuntime::startReg(JNIEnv* env)  
  5. {  
  6.     /* 
  7.      * This hook causes all future threads created in this process to be 
  8.      * attached to the JavaVM.  (This needs to go away in favor of JNI 
  9.      * Attach calls.) 
  10.      */  
  11. <span style="white-space:pre">    </span>//設置Thread類的線程建立函數爲javaCreateThreadEtc  
  12.     androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);  
  13.   
  14.   
  15.     ALOGV("--- registering native functions ---\n");  
  16.   
  17.   
  18.     /* 
  19.      * Every "register" function calls one or more things that return 
  20.      * a local reference (e.g. FindClass).  Because we haven't really 
  21.      * started the VM yet, they're all getting stored in the base frame 
  22.      * and never released.  Use Push/Pop to manage the storage. 
  23.      */  
  24.     env->PushLocalFrame(200);  
  25.   
  26.   
  27.     if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {  
  28.         env->PopLocalFrame(NULL);  
  29.         return -1;  
  30.     }  
  31.     env->PopLocalFrame(NULL);  
  32.   
  33.   
  34.     //createJavaThread("fubar", quickTest, (void*) "hello");  
  35.   
  36.   
  37.     return 0;  
  38. }  
咱們來看一下register_jni_procs()的代碼:
  1. static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)  
  2. {  
  3.     for (size_t i = 0; i < count; i++) {  
  4.         if (array[i].mProc(env) < 0) {  
  5. #ifndef NDEBUG  
  6.             ALOGD("----------!!! %s failed to load\n", array[i].mName);  
  7. #endif  
  8.             return -1;  
  9.         }  
  10.     }  
  11.     return 0;  
  12. }  
看一下從startReg()傳過來的參數gRegJNI:
  1. static const RegJNIRec gRegJNI[] = {  
  2.     REG_JNI(register_android_debug_JNITest),  
  3.     REG_JNI(register_com_android_internal_os_RuntimeInit),  
  4.     REG_JNI(register_android_os_SystemClock),  
  5.     REG_JNI(register_android_util_EventLog),  
  6.     REG_JNI(register_android_util_Log),  
  7.     REG_JNI(register_android_util_FloatMath),  
  8.     REG_JNI(register_android_text_format_Time),  
  9.     REG_JNI(register_android_content_AssetManager),  
  10.     REG_JNI(register_android_content_StringBlock),  
  11.     REG_JNI(register_android_content_XmlBlock),  
  12.     REG_JNI(register_android_emoji_EmojiFactory),  
  13.     REG_JNI(register_android_text_AndroidCharacter),  
  14.     REG_JNI(register_android_text_AndroidBidi),  
  15.     REG_JNI(register_android_view_InputDevice),  
  16.     REG_JNI(register_android_view_KeyCharacterMap),  
  17.     REG_JNI(register_android_os_Process),  
  18.     REG_JNI(register_android_os_SystemProperties),  
  19.     REG_JNI(register_android_os_Binder),  
  20.     REG_JNI(register_android_os_Parcel),  
  21.     REG_JNI(register_android_view_DisplayEventReceiver),  
  22.     REG_JNI(register_android_nio_utils),  
  23.     REG_JNI(register_android_graphics_Graphics),  
  24.     REG_JNI(register_android_view_GraphicBuffer),  
  25.     REG_JNI(register_android_view_GLES20DisplayList),  
  26.     REG_JNI(register_android_view_GLES20Canvas),  
  27.     REG_JNI(register_android_view_HardwareRenderer),  
  28.     REG_JNI(register_android_view_Surface),  
  29.     REG_JNI(register_android_view_SurfaceControl),  
  30.     REG_JNI(register_android_view_SurfaceSession),  
  31.     REG_JNI(register_android_view_TextureView),  
  32.     REG_JNI(register_com_google_android_gles_jni_EGLImpl),  
  33.     REG_JNI(register_com_google_android_gles_jni_GLImpl),  
  34.     REG_JNI(register_android_opengl_jni_EGL14),  
  35.     REG_JNI(register_android_opengl_jni_EGLExt),  
  36.     REG_JNI(register_android_opengl_jni_GLES10),  
  37.     REG_JNI(register_android_opengl_jni_GLES10Ext),  
  38.     REG_JNI(register_android_opengl_jni_GLES11),  
  39.     REG_JNI(register_android_opengl_jni_GLES11Ext),  
  40.     REG_JNI(register_android_opengl_jni_GLES20),  
  41.     REG_JNI(register_android_opengl_jni_GLES30),  
  42.   
  43.     REG_JNI(register_android_graphics_Bitmap),  
  44.     REG_JNI(register_android_graphics_BitmapFactory),  
  45.     REG_JNI(register_android_graphics_BitmapRegionDecoder),  
  46.     REG_JNI(register_android_graphics_Camera),  
  47.     REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),  
  48.     REG_JNI(register_android_graphics_Canvas),  
  49.     REG_JNI(register_android_graphics_ColorFilter),  
  50.     REG_JNI(register_android_graphics_DrawFilter),  
  51.     REG_JNI(register_android_graphics_Interpolator),  
  52.     REG_JNI(register_android_graphics_LayerRasterizer),  
  53.     REG_JNI(register_android_graphics_MaskFilter),  
  54.     REG_JNI(register_android_graphics_Matrix),  
  55.     REG_JNI(register_android_graphics_Movie),  
  56.     REG_JNI(register_android_graphics_NinePatch),  
  57.     REG_JNI(register_android_graphics_Paint),  
  58.     REG_JNI(register_android_graphics_Path),  
  59.     REG_JNI(register_android_graphics_PathMeasure),  
  60.     REG_JNI(register_android_graphics_PathEffect),  
  61.     REG_JNI(register_android_graphics_Picture),  
  62.     REG_JNI(register_android_graphics_PorterDuff),  
  63.     REG_JNI(register_android_graphics_Rasterizer),  
  64.     REG_JNI(register_android_graphics_Region),  
  65.     REG_JNI(register_android_graphics_Shader),  
  66.     REG_JNI(register_android_graphics_SurfaceTexture),  
  67.     REG_JNI(register_android_graphics_Typeface),  
  68.     REG_JNI(register_android_graphics_Xfermode),  
  69.     REG_JNI(register_android_graphics_YuvImage),  
  70.     REG_JNI(register_android_graphics_pdf_PdfDocument),  
  71.   
  72.     REG_JNI(register_android_database_CursorWindow),  
  73.     REG_JNI(register_android_database_SQLiteConnection),  
  74.     REG_JNI(register_android_database_SQLiteGlobal),  
  75.     REG_JNI(register_android_database_SQLiteDebug),  
  76.     REG_JNI(register_android_os_Debug),  
  77.     REG_JNI(register_android_os_FileObserver),  
  78.     REG_JNI(register_android_os_FileUtils),  
  79.     REG_JNI(register_android_os_MessageQueue),  
  80.     REG_JNI(register_android_os_SELinux),  
  81.     REG_JNI(register_android_os_Trace),  
  82.     REG_JNI(register_android_os_UEventObserver),  
  83.     REG_JNI(register_android_net_LocalSocketImpl),  
  84.     REG_JNI(register_android_net_NetworkUtils),  
  85.     REG_JNI(register_android_net_TrafficStats),  
  86.     REG_JNI(register_android_net_wifi_WifiNative),  
  87.     REG_JNI(register_android_os_MemoryFile),  
  88.     REG_JNI(register_com_android_internal_os_ZygoteInit),  
  89.     REG_JNI(register_android_hardware_Camera),  
  90.     REG_JNI(register_android_hardware_camera2_CameraMetadata),  
  91.     REG_JNI(register_android_hardware_SensorManager),  
  92.     REG_JNI(register_android_hardware_SerialPort),  
  93.     REG_JNI(register_android_hardware_UsbDevice),  
  94.     REG_JNI(register_android_hardware_UsbDeviceConnection),  
  95.     REG_JNI(register_android_hardware_UsbRequest),  
  96.     REG_JNI(register_android_media_AudioRecord),  
  97.     REG_JNI(register_android_media_AudioSystem),  
  98.     REG_JNI(register_android_media_AudioTrack),  
  99.     REG_JNI(register_android_media_JetPlayer),  
  100.     REG_JNI(register_android_media_RemoteDisplay),  
  101.     REG_JNI(register_android_media_ToneGenerator),  
  102.   
  103.     REG_JNI(register_android_opengl_classes),  
  104.     REG_JNI(register_android_server_NetworkManagementSocketTagger),  
  105.     REG_JNI(register_android_server_Watchdog),  
  106.     REG_JNI(register_android_ddm_DdmHandleNativeHeap),  
  107.     REG_JNI(register_android_backup_BackupDataInput),  
  108.     REG_JNI(register_android_backup_BackupDataOutput),  
  109.     REG_JNI(register_android_backup_FileBackupHelperBase),  
  110.     REG_JNI(register_android_backup_BackupHelperDispatcher),  
  111.     REG_JNI(register_android_app_backup_FullBackup),  
  112.     REG_JNI(register_android_app_ActivityThread),  
  113.     REG_JNI(register_android_app_NativeActivity),  
  114.     REG_JNI(register_android_view_InputChannel),  
  115.     REG_JNI(register_android_view_InputEventReceiver),  
  116.     REG_JNI(register_android_view_InputEventSender),  
  117.     REG_JNI(register_android_view_InputQueue),  
  118.     REG_JNI(register_android_view_KeyEvent),  
  119.     REG_JNI(register_android_view_MotionEvent),  
  120.     REG_JNI(register_android_view_PointerIcon),  
  121.     REG_JNI(register_android_view_VelocityTracker),  
  122.   
  123.     REG_JNI(register_android_content_res_ObbScanner),  
  124.     REG_JNI(register_android_content_res_Configuration),  
  125.   
  126.     REG_JNI(register_android_animation_PropertyValuesHolder),  
  127.     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),  
  128.     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),  
  129. };  
REG_JNI是系統定義的一個宏:
  1. #ifdef NDEBUG  
  2.     #define REG_JNI(name)      { name }  
  3.     struct RegJNIRec {  
  4.         int (*mProc)(JNIEnv*);  
  5.     };  
  6. #else  
  7.     #define REG_JNI(name)      { name, #name }  
  8.     struct RegJNIRec {  
  9.         int (*mProc)(JNIEnv*);  
  10.         const char* mName;  
  11.     };  
  12. #endif  
以gRegJNI數組中的一項爲例,REG_JNI(register_android_debug_JNITest) 展開REG_JNI後變爲:
  1. { register_android_debug_JNITest, "register_android_debug_JNITest" }  
因此當register_jni_procs()中調用mProcess時,最終調用的是android_debug_JNITest類中的register_android_debug_JNITest:
  1. int register_android_debug_JNITest(JNIEnv* env)  
  2. {  
  3.     return jniRegisterNativeMethods(env, "android/debug/JNITest",  
  4.         gMethods, NELEM(gMethods));  
  5. }  

到這裏JNI註冊就講完了。

ZygoteInit初始化

在JNI註冊完成後,讓咱們再回頭繼續看AndroidRuntime中start函數:
  1. env->CallStaticVoidMethod(startClass, startMeth, strArray);//經過JNI調用main()方法  
在start()中經過JNI調用ZygoteInit類的main()方法,這個main()方法即便從native世界到Java世界的入口。
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
  1. public static void main(String argv[]) {  
  2.     try {  
  3.         // Start profiling the zygote initialization.  
  4.         SamplingProfilerIntegration.start();//啓動性能統計  
  5.   
  6.         registerZygoteSocket();//註冊zygote用的socket  
  7.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,  
  8.             SystemClock.uptimeMillis());  
  9.         preload();//初始化,主要進行framework中一些類和資源的預加載  
  10.         EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,  
  11.             SystemClock.uptimeMillis());  
  12.   
  13.         // Finish profiling the zygote initialization.  
  14.         SamplingProfilerIntegration.writeZygoteSnapshot();//結束統計並生成結果文件  
  15.   
  16.         // Do an initial gc to clean up after startup  
  17.         gc();//強制進行一次回收  
  18.   
  19.         // Disable tracing so that forked processes do not inherit stale tracing tags from  
  20.         // Zygote.  
  21.         Trace.setTracingEnabled(false);  
  22.   
  23.         // If requested, start system server directly from Zygote  
  24.         if (argv.length != 2) {  
  25.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  26.         }  
  27.   
  28.         if (argv[1].equals("start-system-server")) {  
  29.             startSystemServer();//啓動system_server進程  
  30.         } else if (!argv[1].equals("")) {  
  31.             throw new RuntimeException(argv[0] + USAGE_STRING);  
  32.         }  
  33.   
  34.         Log.i(TAG, "Accepting command socket connections");  
  35.   
  36.         runSelectLoop();//變成守護進程,接收socket信息進行處理  
  37.   
  38.         closeServerSocket();  
  39.     } catch (MethodAndArgsCaller caller) {  
  40.         caller.run();  
  41.     } catch (RuntimeException ex) {  
  42.         Log.e(TAG, "Zygote died with exception", ex);  
  43.         closeServerSocket();  
  44.         throw ex;  
  45.     }  
  46. }  
簡單總結一下ZygoteInit類中main()函數主要作了以下幾件事:
  1. 註冊Zygote用的socket
  2. 類和資源的預加載
  3. 啓動system_server進程
  4. 進入一個死循環,等待接收和處理socket事件
接下來將對它們一一進行分析。

registerZygoteSocket()方法

registerZygoteSocket()方法的實現以下:
  1. /** 
  2.  * Registers a server socket for zygote command connections 
  3.  * 
  4.  * @throws RuntimeException when open fails 
  5.  */  
  6. private static void registerZygoteSocket() {  
  7.     if (sServerSocket == null) {  
  8.         int fileDesc;  
  9.         try {  
  10.             String env = System.getenv(ANDROID_SOCKET_ENV);//從環境變量中獲取socket的fd  
  11.             fileDesc = Integer.parseInt(env);  
  12.         } catch (RuntimeException ex) {  
  13.             throw new RuntimeException(  
  14.                     ANDROID_SOCKET_ENV + " unset or invalid", ex);  
  15.         }  
  16.   
  17.         try {  
  18.             sServerSocket = new LocalServerSocket(  
  19.                     createFileDescriptor(fileDesc));  
  20.         } catch (IOException ex) {  
  21.             throw new RuntimeException(  
  22.                     "Error binding to local socket '" + fileDesc + "'", ex);  
  23.         }  
  24.     }  
  25. }  
registerZygoteSocket()方法比較簡單,就是建立了一個服務端Socket。

類和資源的預加載

在Zygote中經過preload()方法完成類和資源的加載,它的實現以下:api

  1.     static void preload() {  
  2.         preloadClasses();//加載類  
  3.         preloadResources();//加載資源  
  4.         preloadOpenGL();//加載OpenGL  
  5.     }  

先看一下preloadClasses():數組

  1. /** 
  2.   * Performs Zygote process initialization. Loads and initializes 
  3.   * commonly used classes. 
  4.   * 
  5.   * Most classes only cause a few hundred bytes to be allocated, but 
  6.   * a few will allocate a dozen Kbytes (in one case, 500+K). 
  7.   */  
  8.  private static void preloadClasses() {  
  9.      final VMRuntime runtime = VMRuntime.getRuntime();  
  10.   
  11.      InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(  
  12.              PRELOADED_CLASSES);//加載preloaded-classes這個文件中定義的須要預加載的類  
  13.      if (is == null) {  
  14.          Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");  
  15.      } else {  
  16.          Log.i(TAG, "Preloading classes...");  
  17.          long startTime = SystemClock.uptimeMillis();  
  18.   
  19.          // Drop root perms while running static initializers.  
  20.          setEffectiveGroup(UNPRIVILEGED_GID);  
  21.          setEffectiveUser(UNPRIVILEGED_UID);  
  22.   
  23.          // Alter the target heap utilization.  With explicit GCs this  
  24.          // is not likely to have any effect.  
  25.          float defaultUtilization = runtime.getTargetHeapUtilization();  
  26.          runtime.setTargetHeapUtilization(0.8f);  
  27.   
  28.          // Start with a clean slate.  
  29.          System.gc();  
  30.          runtime.runFinalizationSync();  
  31.          Debug.startAllocCounting();  
  32.   
  33.          try {  
  34.              BufferedReader br  
  35.                  = new BufferedReader(new InputStreamReader(is), 256);  
  36.   
  37.              int count = 0;  
  38.              String line;  
  39.              while ((line = br.readLine()) != null) {  
  40.                  // Skip comments and blank lines.  
  41.                  line = line.trim();  
  42.                  if (line.startsWith("#") || line.equals("")) {  
  43.                      continue;  
  44.                  }  
  45.   
  46.                  try {  
  47.                      if (false) {  
  48.                          Log.v(TAG, "Preloading " + line + "...");  
  49.                      }  
  50.                      Class.forName(line);//以反射的方式加載類  
  51.                      if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {  
  52.                          if (false) {  
  53.                              Log.v(TAG,  
  54.                                  " GC at " + Debug.getGlobalAllocSize());  
  55.                          }  
  56.                          System.gc();  
  57.                          runtime.runFinalizationSync();  
  58.                          Debug.resetGlobalAllocSize();  
  59.                      }  
  60.                      count++;  
  61.                  } catch (ClassNotFoundException e) {  
  62.                      Log.w(TAG, "Class not found for preloading: " + line);  
  63.                  } catch (Throwable t) {  
  64.                      Log.e(TAG, "Error preloading " + line + ".", t);  
  65.                      if (t instanceof Error) {  
  66.                          throw (Error) t;  
  67.                      }  
  68.                      if (t instanceof RuntimeException) {  
  69.                          throw (RuntimeException) t;  
  70.                      }  
  71.                      throw new RuntimeException(t);  
  72.                  }  
  73.              }  
  74.   
  75.              Log.i(TAG, "...preloaded " + count + " classes in "  
  76.                      + (SystemClock.uptimeMillis()-startTime) + "ms.");  
  77.          } catch (IOException e) {  
  78.              Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);  
  79.          } finally {  
  80.              IoUtils.closeQuietly(is);  
  81.              // Restore default.  
  82.              runtime.setTargetHeapUtilization(defaultUtilization);  
  83.   
  84.              // Fill in dex caches with classes, fields, and methods brought in by preloading.  
  85.              runtime.preloadDexCaches();  
  86.   
  87.              Debug.stopAllocCounting();  
  88.   
  89.              // Bring back root. We'll need it later.  
  90.              setEffectiveUser(ROOT_UID);  
  91.              setEffectiveGroup(ROOT_GID);  
  92.          }  
  93.      }  
  94.  }  

preloadClasses()的實現很簡單,這裏說一下preloaded-classes文件:服務器

  1. # 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  
  4. # MIN_PROCESSES=10  
  5. android.R$styleable  
  6. android.accounts.Account  
  7. android.accounts.Account$1  
  8. android.accounts.AccountManager  
  9. android.accounts.AccountManager$12  
  10. android.accounts.AccountManager$13  
  11. android.accounts.AccountManager$6  
  12. android.accounts.AccountManager$AmsTask  
  13. android.accounts.AccountManager$AmsTask$1  
  14. android.accounts.AccountManager$AmsTask$Response  

在Android4.4的源代碼中有2782行,也就說這裏在系統啓動時須要預加載兩千多個類,而這僅僅是源代碼,在手機廠商的代碼中,須要進行預加載的類的數量將會超過這個數。preloaded-classes文件時由WritePreloadedClassFile類生成的。WritePreloadedClassFile將某個類加入預加載文件preloaded-classes中的條件時:該類被很多於10個進程使用,而且家中該類好使超過1250微秒。WritePreloadedClassFile裏面的實現很是簡單,感興趣的讀者能夠自行閱讀。oracle

  1. /** 
  2.  * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. 
  3.  */  
  4. static final int MIN_LOAD_TIME_MICROS = 1250;  
  5.   
  6. /** 
  7.  * Preload any class that was loaded by at least MIN_PROCESSES processes. 
  8.  */  
  9. static final int MIN_PROCESSES = 10;  

這裏我簡單估算了一下,在Android4.4中預加載這些類須要4秒鐘做用,這對於系統啓動來講是一個比較長的時間,所以在進行系統啓動速度的優化時,這裏能夠做爲一個優化大點。

在看preloadClass的代碼時有些讀者看的setEffectiveUser的幾句代碼不明白什麼意思:

  1. private static void preloadClasses() {  
  2.         ......  
  3.         // Drop root perms while running static initializers.  
  4.         setEffectiveGroup(UNPRIVILEGED_GID);  
  5.         setEffectiveUser(UNPRIVILEGED_UID);  
  6.         ......  
  7.         } finally {  
  8.             ......  
  9.             // Bring back root. We'll need it later.  
  10.             setEffectiveUser(ROOT_UID);  
  11.             setEffectiveGroup(ROOT_GID);  
  12.         }  
  13.     }  
  14. }  

以setEffectiveUser爲例看一下它的實現:

  1. /** 
  2.  * Sets effective user ID. 
  3.  */  
  4. private static void setEffectiveUser(int uid) {  
  5.     int errno = setreuid(ROOT_UID, uid);  
  6.     if (errno != 0) {  
  7.         Log.e(TAG, "setreuid() failed. errno: " + errno);  
  8.     }  
  9. }  
  1. /** 
  2.  * The Linux syscall "setreuid()" 
  3.  * @param ruid real uid 
  4.  * @param euid effective uid 
  5.  * @return 0 on success, non-zero errno on fail 
  6.  */  
  7. static native int setreuid(int ruid, int euid);  

能夠看出這裏setEffectiveUser這幾句的意思是:在類加載以前臨時下降euid(真實用戶ID)權限,加載完成後恢復。關於Linux各類userid的說明以下:

有效用戶ID

有效用戶IDEffective UID,即EUID)與有效用戶組IDEffective Group ID,即EGID)在建立與訪問文件的時候發揮做用;具體來講,建立文件時,系統內核將根據建立文件的進程的EUID與EGID設定文件的全部者/組屬性,而在訪問文件時,內核亦根據訪問進程的EUID與EGID決定其可否訪問文件。

真實用戶ID

真實用戶IDReal UID,即RUID)與真實用戶組IDReal GID,即RGID)用於辨識進程的真正全部者,且會影響到進程發送信號的權限。沒有超級用戶權限的進程僅在其RUID與目標進程的RUID相匹配時才能向目標進程發送信號,例如在父子進程間,子進程父進程處繼承了認證信息,使得父子進程間能夠互相發送信號。

暫存用戶ID

暫存用戶IDSaved UID,即SUID)於以提高權限運行的進程暫時須要作一些不需特權的操做時使用,這種狀況下進程會暫時將本身的有效用戶ID從特權用戶(常爲root)對應的UID變爲某個非特權用戶對應的UID,然後將原有的特權用戶UID複製爲SUID暫存;以後當進程完成不需特權的操做後,進程使用SUID的值重置EUID以從新得到特權。在這裏須要說明的是,無特權進程的EUID值只能設爲與RUID、SUID與EUID(也即不改變)之一相同的值。

文件系統用戶ID

文件系統用戶IDFile System UID,即FSUID)在Linux中使用,且只用於對文件系統的訪問權限控制,在沒有明確設定的狀況下與EUID相同(若FSUID爲root的UID,則SUID、RUID與EUID必至少有一亦爲root的UID),且EUID改變也會影響到FSUID。設立FSUID是爲了容許程序(如NFS服務器)在不需獲取向給定UID帳戶發送信號的狀況下以給定UID的權限來限定本身的文件系統權限。

這段代碼轉自http://zh.wikipedia.org/wiki/%E7%94%A8%E6%88%B7ID

那這裏這樣作的用意何在?我猜這裏是爲了保證預加載的類是全部的用戶都是可用的。


預加載資源的代碼以下:

  1. /** 
  2.   * Load in commonly used resources, so they can be shared across 
  3.   * processes. 
  4.   * 
  5.   * These tend to be a few Kbytes, but are frequently in the 20-40K 
  6.   * range, and occasionally even larger. 
  7.   */  
  8.  private static void preloadResources() {  
  9.      final VMRuntime runtime = VMRuntime.getRuntime();  
  10.   
  11.      Debug.startAllocCounting();  
  12.      try {  
  13.          System.gc();  
  14.          runtime.runFinalizationSync();  
  15.          mResources = Resources.getSystem();  
  16.          mResources.startPreloading();  
  17.          if (PRELOAD_RESOURCES) {  
  18.              Log.i(TAG, "Preloading resources...");  
  19.   
  20.              long startTime = SystemClock.uptimeMillis();  
  21.              TypedArray ar = mResources.obtainTypedArray(  
  22.                      com.android.internal.R.array.preloaded_drawables);  
  23.              int N = preloadDrawables(runtime, ar);//預加載Drawable  
  24.              ar.recycle();  
  25.              Log.i(TAG, "...preloaded " + N + " resources in "  
  26.                      + (SystemClock.uptimeMillis()-startTime) + "ms.");  
  27.   
  28.              startTime = SystemClock.uptimeMillis();  
  29.              ar = mResources.obtainTypedArray(  
  30.                      com.android.internal.R.array.preloaded_color_state_lists);  
  31.              N = preloadColorStateLists(runtime, ar);//預加載Color  
  32.              ar.recycle();  
  33.              Log.i(TAG, "...preloaded " + N + " resources in "  
  34.                      + (SystemClock.uptimeMillis()-startTime) + "ms.");  
  35.          }  
  36.          mResources.finishPreloading();  
  37.      } catch (RuntimeException e) {  
  38.          Log.w(TAG, "Failure preloading resources", e);  
  39.      } finally {  
  40.          Debug.stopAllocCounting();  
  41.      }  
  42.  }  

preloadResources的加載過程又分爲加載Drawable和加載Color。

除了加載類和資源,還會加載OpenGL的一些東西:

  1. private static void preloadOpenGL() {  
  2.     if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {  
  3.         EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);  
  4.     }  
  5. }  

在建立socket和資源加載先後有這麼兩句:

  1. // Start profiling the zygote initialization.  
  2. SamplingProfilerIntegration.start();//啓動性能統計  
  3.   
  4. registerZygoteSocket();//註冊zygote用的socket  
  5. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,  
  6.     SystemClock.uptimeMillis());  
  7. preload();//初始化,主要進行framework中一些類和資源的預加載  
  8. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,  
  9.     SystemClock.uptimeMillis());  
  10.   
  11. // Finish profiling the zygote initialization.  
  12. SamplingProfilerIntegration.writeZygoteSnapshot();//結束統計並生成結果文件  

因此,這裏SamplingProfilerIntegration統計的是建立socket和類及資源初始化的時間。

啓動system_server

  1. /** 
  2.  * Prepare the arguments and fork for the system server process. 
  3.  */  
  4. private static boolean startSystemServer()  
  5.         throws MethodAndArgsCaller, RuntimeException {  
  6.     long capabilities = posixCapabilitiesAsBits(  
  7.         OsConstants.CAP_KILL,  
  8.         OsConstants.CAP_NET_ADMIN,  
  9.         OsConstants.CAP_NET_BIND_SERVICE,  
  10.         OsConstants.CAP_NET_BROADCAST,  
  11.         OsConstants.CAP_NET_RAW,  
  12.         OsConstants.CAP_SYS_MODULE,  
  13.         OsConstants.CAP_SYS_NICE,  
  14.         OsConstants.CAP_SYS_RESOURCE,  
  15.         OsConstants.CAP_SYS_TIME,  
  16.         OsConstants.CAP_SYS_TTY_CONFIG  
  17.     );  
  18.     /* Hardcoded command line to start the system server */  
  19.     String args[] = {  
  20.         "--setuid=1000",  
  21.         "--setgid=1000",  
  22.         "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",  
  23.         "--capabilities=" + capabilities + "," + capabilities,  
  24.         "--runtime-init",  
  25.         "--nice-name=system_server",  
  26.         "com.android.server.SystemServer",  
  27.     };  
  28.     ZygoteConnection.Arguments parsedArgs = null;  
  29.   
  30.     int pid;  
  31.   
  32.     try {  
  33.         parsedArgs = new ZygoteConnection.Arguments(args);  
  34.         ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);  
  35.         ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);  
  36.   
  37.         /* Request to fork the system server process */  
  38.         pid = Zygote.forkSystemServer(//以fork的方式建立system_server進程  
  39.                 parsedArgs.uid, parsedArgs.gid,  
  40.                 parsedArgs.gids,  
  41.                 parsedArgs.debugFlags,  
  42.                 null,  
  43.                 parsedArgs.permittedCapabilities,  
  44.                 parsedArgs.effectiveCapabilities);  
  45.     } catch (IllegalArgumentException ex) {  
  46.         throw new RuntimeException(ex);  
  47.     }  
  48.   
  49.     /* For child process */  
  50.     if (pid == 0) {//pid==0說明在子進程中,父進程爲Zygote  
  51.         handleSystemServerProcess(parsedArgs);  
  52.     }  
  53.   
  54.     return true;  
  55. }  

這裏前面的一大段代碼主要是在爲fork準備參數parsedArgs,而後Zygote會forkSystemServer來建立system_server,forkSystemServer()方法最終會調用Linux中的fork()。

runSelectLoop()方法

在建立system_server後,Zygote調用runSelectLoop()進入到一個死循環中:

  1. /** 
  2.  * Runs the zygote process's select loop. Accepts new connections as 
  3.  * they happen, and reads commands from connections one spawn-request's 
  4.  * worth at a time. 
  5.  * 
  6.  * @throws MethodAndArgsCaller in a child process when a main() should 
  7.  * be executed. 
  8.  */  
  9. private static void runSelectLoop() throws MethodAndArgsCaller {  
  10.     ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();  
  11.     ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();  
  12.     FileDescriptor[] fdArray = new FileDescriptor[4];  
  13.   
  14.     fds.add(sServerSocket.getFileDescriptor());//registerZygoteSocket中建立的socket的描述符  
  15.     peers.add(null);  
  16.   
  17.     int loopCount = GC_LOOP_COUNT;  
  18.     while (true) {//死循環  
  19.         int index;//selectReadable方法監控的句柄的下標(fdArray中的下標)  
  20.   
  21.         /* 
  22.          * Call gc() before we block in select(). 
  23.          * It's work that has to be done anyway, and it's better 
  24.          * to avoid making every child do it.  It will also 
  25.          * madvise() any free memory as a side-effect. 
  26.          * 
  27.          * Don't call it every time, because walking the entire 
  28.          * heap is a lot of overhead to free a few hundred bytes. 
  29.          */  
  30.         if (loopCount <= 0) {//Zygote每循環GC_LOOP_COUNT(這裏的值是10)次就會進行一次內存回收  
  31.             gc();  
  32.             loopCount = GC_LOOP_COUNT;  
  33.         } else {  
  34.             loopCount--;  
  35.         }  
  36.   
  37.   
  38.         try {  
  39.             fdArray = fds.toArray(fdArray);  
  40.             index = selectReadable(fdArray);//內部由select()實現,在沒有客戶端事件時會堵塞  
  41.         } catch (IOException ex) {  
  42.             throw new RuntimeException("Error in select()", ex);  
  43.         }  
  44.   
  45.         if (index < 0) {  
  46.             throw new RuntimeException("Error in select()");  
  47.         } else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件  
  48.             ZygoteConnection newPeer = acceptCommandPeer();  
  49.             peers.add(newPeer);  
  50.             fds.add(newPeer.getFileDesciptor());  
  51.         } else {//調用ZygoteConnection對象的runOnce方法,ZygoteConnection是在index == 0時被添加到peers的  
  52.             boolean done;  
  53.             done = peers.get(index).runOnce();  
  54.   
  55.             if (done) {  
  56.                 peers.remove(index);  
  57.                 fds.remove(index);  
  58.             }  
  59.         }  
  60.     }  
  61. }  


下面是selcetReadable方法的代碼:

  1. /** 
  2.  * Invokes select() on the provider array of file descriptors (selecting 
  3.  * for readability only). Array elements of null are ignored. 
  4.  * 
  5.  * @param fds non-null; array of readable file descriptors 
  6.  * @return index of descriptor that is now readable or -1 for empty array. 
  7.  * @throws IOException if an error occurs 
  8.  */  
  9. static native int selectReadable(FileDescriptor[] fds) throws IOException;  

selectReadable的native實如今com_android_internal_os_ZygoteInit.cpp中。
Zygote接收到socket客戶端的連接後會將其(客戶端Socket)保存到一個ZygoteConnection對象中,而後保存到peers

  1. /** 
  2.  * Waits for and accepts a single command connection. Throws 
  3.  * RuntimeException on failure. 
  4.  */  
  5. private static ZygoteConnection acceptCommandPeer() {  
  6.     try {  
  7.         return new ZygoteConnection(sServerSocket.accept());  
  8.     } catch (IOException ex) {  
  9.         throw new RuntimeException(  
  10.                 "IOException during accept()", ex);  
  11.     }  
  12. }  

最後,客戶端的請求會有ZygoteConnection的runOnce來處理。

相關文章
相關標籤/搜索