• Zygote进程【1】——Zygote的诞生


    Android中存在着C和Java两个完全不同的世界,前者直接建立在Linux的基础上,后者直接建立在JVM的基础上。zygote的中文名字为“受精卵”,这个名字很好的诠释了zygote进程的作用。作为java世界的孵化者,zygote本身是一个native程序,是由init根据init.rc文件中的配置项创建的。

    @/system/core/rootdir/init.rc

    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则表示传入的参数。

    zygote的实现在app_main.cpp中:

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

    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. ");  
    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的实现如下:


    可以看出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(" >>>>>> AndroidRuntime START %s <<<<<< ",  
    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' ", 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 ");  
    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' ", 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' ", 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 ");  
    105.     if (mJavaVM->DetachCurrentThread() != JNI_OK)  
    106.         ALOGW("Warning: unable to detach main thread ");  
    107.     if (mJavaVM->DestroyJavaVM() != 0)  
    108.         ALOGW("Warning: VM did not shut down cleanly ");  
    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] != '') {  
    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] != '') {  
    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] != '') {  
    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] != '') {  
    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] != '') {  
    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] != '') {  
    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 ", 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] != '') {  
    284.         /* accept "all" to mean "all classes and packages" */  
    285.         if (strcmp(enableAssertBuf+4, "all") == 0)  
    286.             enableAssertBuf[3] = '';  
    287.         ALOGI("Assertions enabled: '%s' ", enableAssertBuf);  
    288.         opt.optionString = enableAssertBuf;  
    289.         mOptions.add(opt);  
    290.     } else {  
    291.         ALOGV("Assertions disabled ");  
    292.     }  
    293.   
    294.     if (jniOptsBuf[10] != '') {  
    295.         ALOGI("JNI options: '%s' ", jniOptsBuf);  
    296.         opt.optionString = jniOptsBuf;  
    297.         mOptions.add(opt);  
    298.     }  
    299.   
    300.     if (stackTraceFileBuf[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 ");  
    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 ");  
    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 --- ");  
    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 ", 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()方法完成类和资源的加载,它的实现如下:

    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里面的实现非常简单,感兴趣的读者可以自行阅读。

    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来处理。

  • 相关阅读:
    redis配置文件redis.conf总结
    react井字棋小游戏实现及优化
    springboot 如何在请求进入controller之前改变body中的值
    记录一个Springboot启动的问题->sprinboot正常启动但是tomcat却没有启动
    websocket-基于springboot的简单实现
    JVM-垃圾回收
    gRPC-Java实践
    Protocol Buffers—-java
    串口通信学习-基础
    Modbus通信协议学习
  • 原文地址:https://www.cnblogs.com/ldq2016/p/6232005.html
Copyright © 2020-2023  润新知