Zygnote如何创建?
Zygnote的作用是什么?
SystemServer如何创建?
有源码对着源码(4.4之后的源码),花点时间看;没有源码,看流程即可,代码实现带过去就好了。
文章写给懂的人看,我转载的最后也进行一定的总结。
本文转载自:
http://blog.csdn.net/zhgxhuaa/article/details/24201127
http://blog.csdn.net/zhgxhuaa/article/details/24584807
http://blog.csdn.net/zhgxhuaa/article/details/24744601
在Android中存在着C和Java两个完全不同的世界,前者直接建立在Linux的基础上,后者直接建立在JVM的基础上。zygote的中文名字为“受精卵”,这个名字很好的诠释了zygote进程的作用。作为java世界的孵化者,zygote本身是一个native程序,是由init根据init.rc文件中的配置项创建的。
@/system/core/rootdir/init.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media 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
int main(int argc, char* const argv[]) { //针对ARM平台的特殊逻辑 #ifdef __arm__ /* * b/7188322 - Temporarily revert to the compat memory layout * to avoid breaking third party apps. * * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. * * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 * changes the kernel mapping from bottom up to top-down. * This breaks some programs which improperly embed * an out of date copy of Android‘s linker. */ char value[PROPERTY_VALUE_MAX]; property_get("ro.kernel.qemu", value, ""); bool is_qemu = (strcmp(value, "1") == 0); if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) { int current = personality(0xFFFFFFFF); if ((current & ADDR_COMPAT_LAYOUT) == 0) { personality(current | ADDR_COMPAT_LAYOUT); setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1); execv("/system/bin/app_process", argv); return -1; } } unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP"); #endif // These are global variables in ProcessState.cpp mArgC = argc; mArgV = argv; mArgLen = 0; for (int i=0; i<argc; i++) { mArgLen += strlen(argv[i]) + 1; } mArgLen--; AppRuntime runtime; const char* argv0 = argv[0]; // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to ‘--‘ or first non ‘-‘ arg goes to the vm int i = runtime.addVmArguments(argc, argv); // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; const char* parentDir = NULL; const char* niceName = NULL; const char* className = NULL; while (i < argc) {//根据传入的参数,初始化启动zygote所需的参数 const char* arg = argv[i++]; if (!parentDir) { parentDir = arg; } else if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName = arg + 12; } else { className = arg; break; } } if (niceName && *niceName) { setArgv0(argv0, niceName); set_process_name(niceName);//设置本进程的名称为zygote,至此进程有app_process变为了zygote } runtime.mParentDir = parentDir; if (zygote) {//根据我们传入的参考,这里的zygote值为TRUE runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : ""); } else if (className) {//可以看出除了zygote,RuntimeInit也是在这里启动的 // Remainder of args get passed to startup class main() runtime.mClassName = className; runtime.mArgC = argc - i; runtime.mArgV = argv + i; runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool"); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } }
通过对main()函数的分析,可以看出main()主要根据传入的参数初始化启动参数,具体的启动过程是由AppRuntime完成的。AppRuntime的声明和实现都在app_main.cpp中,它继承自AndroidRuntime,AppRuntime的实现如下:
可以看出start是AndroidRuntime中的方法。通过start函数前面的注释我们了解到它的主要作用是:启动Android运行时环境,包括启动虚拟机和调用className参数所指定的类的main()方法(即:Java中的main方法)。
/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ void AndroidRuntime::start(const char* className, const char* options) { ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", className != NULL ? className : "(unknown)"); /* * ‘startSystemServer == true‘ means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ if (strcmp(options, "start-system-server") == 0) { /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } //环境变量ANDROID_ROOT是否已经设置,如果未设置,则设置其值为"/system" const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /android does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); } //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); //ALOGD("Found LD_ASSUME_KERNEL=‘%s‘\n", kernelHack); /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) {//启动Java虚拟机 return; } onVmCreated(env);//空函数 /* * Register android functions. */ if (startReg(env) < 0) {//注册Android JNI函数 ALOGE("Unable to register all android natives\n"); return; } /* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; jstring optionsStr; stringClass = env->FindClass("java/lang/String");//JNI中调用java中的String类 assert(stringClass != NULL); //创建包含2个元素的String数组,这里相当于Java中的String strArray[] = new String[2] strArray = env->NewObjectArray(2, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className);//classNameStr的值为"com.android.internal.os.ZygoteInit" assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); optionsStr = env->NewStringUTF(options);//optionsStr的值为"start-system-server" env->SetObjectArrayElement(strArray, 1, optionsStr); /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className);//将"com.android.internal.os.ZygoteInit"中的"."替换成"/"供JNI调用 jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class ‘%s‘\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");//ZygoteInit类中的main()方法 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in ‘%s‘\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过JNI调用main()方法 #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } free(slashClassName); //如果JVM退出。这两句代码一般来说执行不到 ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); }
通过上面对start()函数的分析可以发现,在start()中主要完成了如下三项工作:
- 启动JVM。
- 注册Android JNI函数。
- 调用ZygoteInit的main()方法。
创建Java虚拟机
start()中与创建虚拟机相关的代码如下:
/* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) {//启动Java虚拟机 return; } onVmCreated(env);//空函数
这里代码中 创建一个JniInvocation实例,并且调用它的成员函数init来初始化JNI环境:
@/libnativehelper/jniInvocation.cpp
bool JniInvocation::Init(const char* library) { #ifdef HAVE_ANDROID_OS char default_library[PROPERTY_VALUE_MAX]; property_get("persist.sys.dalvik.vm.lib", default_library, "libdvm.so"); #else const char* default_library = "libdvm.so"; #endif if (library == NULL) { library = default_library; } handle_ = dlopen(library, RTLD_NOW); if (handle_ == NULL) { ALOGE("Failed to dlopen %s: %s", library, dlerror()); return false; } if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), "JNI_GetDefaultJavaVMInitArgs")) { return false; } if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true; }
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
/* * Start the Dalvik Virtual Machine. * * Various arguments, most determined by system properties, are passed in. * The "mOptions" vector is updated. * * Returns 0 on success. */ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) { int result = -1; JavaVMInitArgs initArgs; JavaVMOption opt; char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[PROPERTY_VALUE_MAX]; char dexoptFlagsBuf[PROPERTY_VALUE_MAX]; char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX]; char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX]; char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX]; char extraOptsBuf[PROPERTY_VALUE_MAX]; char* stackTraceFile = NULL; bool checkJni = false; bool checkDexSum = false; bool logStdio = false; enum { kEMDefault, kEMIntPortable, kEMIntFast, kEMJitCompiler, } executionMode = kEMDefault; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkJni = true; } else if (strcmp(propBuf, "false") != 0) { /* property is neither true nor false; fall back on kernel parameter */ property_get("ro.kernel.android.checkjni", propBuf, ""); if (propBuf[0] == ‘1‘) { checkJni = true; } } property_get("dalvik.vm.execution-mode", propBuf, ""); if (strcmp(propBuf, "int:portable") == 0) { executionMode = kEMIntPortable; } else if (strcmp(propBuf, "int:fast") == 0) { executionMode = kEMIntFast; } else if (strcmp(propBuf, "int:jit") == 0) { executionMode = kEMJitCompiler; } property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, ""); property_get("dalvik.vm.check-dex-sum", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkDexSum = true; } property_get("log.redirect-stdio", propBuf, ""); if (strcmp(propBuf, "true") == 0) { logStdio = true; } strcpy(enableAssertBuf, "-ea:"); property_get("dalvik.vm.enableassertions", enableAssertBuf+4, ""); strcpy(jniOptsBuf, "-Xjniopts:"); property_get("dalvik.vm.jniopts", jniOptsBuf+10, ""); /* route exit() to our handler */ opt.extraInfo = (void*) runtime_exit; opt.optionString = "exit"; mOptions.add(opt); /* route fprintf() to our handler */ opt.extraInfo = (void*) runtime_vfprintf; opt.optionString = "vfprintf"; mOptions.add(opt); /* register the framework-specific "is sensitive thread" hook */ opt.extraInfo = (void*) runtime_isSensitiveThread; opt.optionString = "sensitiveThread"; mOptions.add(opt); opt.extraInfo = NULL; /* enable verbose; standard options are { jni, gc, class } */ //options[curOpt++].optionString = "-verbose:jni"; opt.optionString = "-verbose:gc"; mOptions.add(opt); //options[curOpt++].optionString = "-verbose:class"; /* * The default starting and maximum size of the heap. Larger * values should be specified in a product property override. */ strcpy(heapstartsizeOptsBuf, "-Xms"); property_get("dalvik.vm.heapstartsize", heapstartsizeOptsBuf+4, "4m"); opt.optionString = heapstartsizeOptsBuf; mOptions.add(opt); strcpy(heapsizeOptsBuf, "-Xmx"); property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m"); opt.optionString = heapsizeOptsBuf; mOptions.add(opt); // Increase the main thread‘s interpreter stack size for bug 6315322. opt.optionString = "-XX:mainThreadStackSize=24K"; mOptions.add(opt); // Set the max jit code cache size. Note: size of 0 will disable the JIT. strcpy(jitcodecachesizeOptsBuf, "-Xjitcodecachesize:"); property_get("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf+19, NULL); if (jitcodecachesizeOptsBuf[19] != ‘\0‘) { opt.optionString = jitcodecachesizeOptsBuf; mOptions.add(opt); } strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, ""); if (heapgrowthlimitOptsBuf[20] != ‘\0‘) { opt.optionString = heapgrowthlimitOptsBuf; mOptions.add(opt); } strcpy(heapminfreeOptsBuf, "-XX:HeapMinFree="); property_get("dalvik.vm.heapminfree", heapminfreeOptsBuf+16, ""); if (heapminfreeOptsBuf[16] != ‘\0‘) { opt.optionString = heapminfreeOptsBuf; mOptions.add(opt); } strcpy(heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); property_get("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf+16, ""); if (heapmaxfreeOptsBuf[16] != ‘\0‘) { opt.optionString = heapmaxfreeOptsBuf; mOptions.add(opt); } strcpy(heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization="); property_get("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf+26, ""); if (heaptargetutilizationOptsBuf[26] != ‘\0‘) { opt.optionString = heaptargetutilizationOptsBuf; mOptions.add(opt); } property_get("ro.config.low_ram", propBuf, ""); if (strcmp(propBuf, "true") == 0) { opt.optionString = "-XX:LowMemoryMode"; mOptions.add(opt); } /* * Enable or disable dexopt features, such as bytecode verification and * calculation of register maps for precise GC. */ property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, ""); if (dexoptFlagsBuf[0] != ‘\0‘) { const char* opc; const char* val; opc = strstr(dexoptFlagsBuf, "v="); /* verification */ if (opc != NULL) { switch (*(opc+2)) { case ‘n‘: val = "-Xverify:none"; break; case ‘r‘: val = "-Xverify:remote"; break; case ‘a‘: val = "-Xverify:all"; break; default: val = NULL; break; } if (val != NULL) { opt.optionString = val; mOptions.add(opt); } } opc = strstr(dexoptFlagsBuf, "o="); /* optimization */ if (opc != NULL) { switch (*(opc+2)) { case ‘n‘: val = "-Xdexopt:none"; break; case ‘v‘: val = "-Xdexopt:verified"; break; case ‘a‘: val = "-Xdexopt:all"; break; case ‘f‘: val = "-Xdexopt:full"; break; default: val = NULL; break; } if (val != NULL) { opt.optionString = val; mOptions.add(opt); } } opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */ if (opc != NULL) { opt.optionString = "-Xgenregmap"; mOptions.add(opt); /* turn on precise GC while we‘re at it */ opt.optionString = "-Xgc:precise"; mOptions.add(opt); } } /* enable debugging; set suspend=y to pause during VM init */ /* use android ADB transport */ opt.optionString = "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"; mOptions.add(opt); ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { /* extended JNI checking */ opt.optionString = "-Xcheck:jni"; mOptions.add(opt); /* set a cap on JNI global references */ opt.optionString = "-Xjnigreflimit:2000"; mOptions.add(opt); /* with -Xcheck:jni, this provides a JNI function call trace */ //opt.optionString = "-verbose:jni"; //mOptions.add(opt); } char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)]; property_get("dalvik.vm.lockprof.threshold", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(lockProfThresholdBuf, "-Xlockprofthreshold:"); strcat(lockProfThresholdBuf, propBuf); opt.optionString = lockProfThresholdBuf; mOptions.add(opt); } /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX]; property_get("dalvik.vm.jit.op", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(jitOpBuf, "-Xjitop:"); strcat(jitOpBuf, propBuf); opt.optionString = jitOpBuf; mOptions.add(opt); } /* Force interpreter-only mode for selected methods */ char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX]; property_get("dalvik.vm.jit.method", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(jitMethodBuf, "-Xjitmethod:"); strcat(jitMethodBuf, propBuf); opt.optionString = jitMethodBuf; mOptions.add(opt); } if (executionMode == kEMIntPortable) { opt.optionString = "-Xint:portable"; mOptions.add(opt); } else if (executionMode == kEMIntFast) { opt.optionString = "-Xint:fast"; mOptions.add(opt); } else if (executionMode == kEMJitCompiler) { opt.optionString = "-Xint:jit"; mOptions.add(opt); } if (checkDexSum) { /* perform additional DEX checksum tests */ opt.optionString = "-Xcheckdexsum"; mOptions.add(opt); } if (logStdio) { /* convert stdout/stderr to log messages */ opt.optionString = "-Xlog-stdio"; mOptions.add(opt); } if (enableAssertBuf[4] != ‘\0‘) { /* accept "all" to mean "all classes and packages" */ if (strcmp(enableAssertBuf+4, "all") == 0) enableAssertBuf[3] = ‘\0‘; ALOGI("Assertions enabled: ‘%s‘\n", enableAssertBuf); opt.optionString = enableAssertBuf; mOptions.add(opt); } else { ALOGV("Assertions disabled\n"); } if (jniOptsBuf[10] != ‘\0‘) { ALOGI("JNI options: ‘%s‘\n", jniOptsBuf); opt.optionString = jniOptsBuf; mOptions.add(opt); } if (stackTraceFileBuf[0] != ‘\0‘) { static const char* stfOptName = "-Xstacktracefile:"; stackTraceFile = (char*) malloc(strlen(stfOptName) + strlen(stackTraceFileBuf) +1); strcpy(stackTraceFile, stfOptName); strcat(stackTraceFile, stackTraceFileBuf); opt.optionString = stackTraceFile; mOptions.add(opt); } /* extra options; parse this late so it overrides others */ property_get("dalvik.vm.extra-opts", extraOptsBuf, ""); parseExtraOpts(extraOptsBuf); /* Set the properties for locale */ { char langOption[sizeof("-Duser.language=") + 3]; char regionOption[sizeof("-Duser.region=") + 3]; strcpy(langOption, "-Duser.language="); strcpy(regionOption, "-Duser.region="); readLocale(langOption, regionOption); opt.extraInfo = NULL; opt.optionString = langOption; mOptions.add(opt); opt.optionString = regionOption; mOptions.add(opt); } /* * We don‘t have /tmp on the device, but we often have an SD card. Apps * shouldn‘t use this, but some test suites might want to exercise it. */ opt.optionString = "-Djava.io.tmpdir=/sdcard"; mOptions.add(opt); initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; /* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); goto bail; } result = 0; bail: free(stackTraceFile); return result; }
可以看出这个函数的绝大部分都是在设置Java虚拟机的各项参数,没有什么好说。看到下面这一段变量定义,不知道大家有没有去思考过,这里为什么用PROPERTY_VALUE_MAX作为初始大小?
char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[PROPERTY_VALUE_MAX]; char dexoptFlagsBuf[PROPERTY_VALUE_MAX]; char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX]; char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX]; char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
下面是PROPERTY_VALUE_MAX的定义:
@system/core/include/cutils/properties.h
/* System properties are *small* name value pairs managed by the ** property service. If your data doesn‘t fit in the provided ** space it is not appropriate for a system property. ** ** WARNING: system/bionic/include/sys/system_properties.h also defines ** these, but with different names. (TODO: fix that) */ #define PROPERTY_KEY_MAX PROP_NAME_MAX #define PROPERTY_VALUE_MAX PROP_VALUE_MAX
所以,没错,PROPERTY_VALUE_MAX是Android中属性value的最大长度,而java虚拟机的这些参数都是通过Android属性赋值和控制的,所以他们的值得大小肯定不能超过属性的最大长度。下面是我的小米2S手机中的一部分Java参数。Android中所有属性都可以通过getprop命令来查看。
[dalvik.vm.heapconcurrentstart]: [2097152] [dalvik.vm.heapgrowthlimit]: [96m] [dalvik.vm.heapidealfree]: [8388608] [dalvik.vm.heapsize]: [384m] [dalvik.vm.heapstartsize]: [8m] [dalvik.vm.heaputilization]: [0.25] [dalvik.vm.stack-trace-file]: [/data/anr/traces.txt]
下面来看一下startVm()中的最后几句:
/* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); goto bail; }
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
/* * Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ <span style="white-space:pre"> </span>//设置Thread类的线程创建函数为javaCreateThreadEtc androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ALOGV("--- registering native functions ---\n"); /* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven‘t really * started the VM yet, they‘re all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200); if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); //createJavaThread("fubar", quickTest, (void*) "hello"); return 0; }
我们来看一下register_jni_procs()的代码:
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) { for (size_t i = 0; i < count; i++) { if (array[i].mProc(env) < 0) { #ifndef NDEBUG ALOGD("----------!!! %s failed to load\n", array[i].mName); #endif return -1; } } return 0; }
看一下从startReg()传过来的参数gRegJNI:
static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_debug_JNITest), REG_JNI(register_com_android_internal_os_RuntimeInit), REG_JNI(register_android_os_SystemClock), REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_FloatMath), REG_JNI(register_android_text_format_Time), REG_JNI(register_android_content_AssetManager), REG_JNI(register_android_content_StringBlock), REG_JNI(register_android_content_XmlBlock), REG_JNI(register_android_emoji_EmojiFactory), REG_JNI(register_android_text_AndroidCharacter), REG_JNI(register_android_text_AndroidBidi), REG_JNI(register_android_view_InputDevice), REG_JNI(register_android_view_KeyCharacterMap), REG_JNI(register_android_os_Process), REG_JNI(register_android_os_SystemProperties), REG_JNI(register_android_os_Binder), REG_JNI(register_android_os_Parcel), REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_nio_utils), REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_GLES20DisplayList), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_HardwareRenderer), REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_SurfaceControl), REG_JNI(register_android_view_SurfaceSession), REG_JNI(register_android_view_TextureView), REG_JNI(register_com_google_android_gles_jni_EGLImpl), REG_JNI(register_com_google_android_gles_jni_GLImpl), REG_JNI(register_android_opengl_jni_EGL14), REG_JNI(register_android_opengl_jni_EGLExt), REG_JNI(register_android_opengl_jni_GLES10), REG_JNI(register_android_opengl_jni_GLES10Ext), REG_JNI(register_android_opengl_jni_GLES11), REG_JNI(register_android_opengl_jni_GLES11Ext), REG_JNI(register_android_opengl_jni_GLES20), REG_JNI(register_android_opengl_jni_GLES30), REG_JNI(register_android_graphics_Bitmap), REG_JNI(register_android_graphics_BitmapFactory), REG_JNI(register_android_graphics_BitmapRegionDecoder), REG_JNI(register_android_graphics_Camera), REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor), REG_JNI(register_android_graphics_Canvas), REG_JNI(register_android_graphics_ColorFilter), REG_JNI(register_android_graphics_DrawFilter), REG_JNI(register_android_graphics_Interpolator), REG_JNI(register_android_graphics_LayerRasterizer), REG_JNI(register_android_graphics_MaskFilter), REG_JNI(register_android_graphics_Matrix), REG_JNI(register_android_graphics_Movie), REG_JNI(register_android_graphics_NinePatch), REG_JNI(register_android_graphics_Paint), REG_JNI(register_android_graphics_Path), REG_JNI(register_android_graphics_PathMeasure), REG_JNI(register_android_graphics_PathEffect), REG_JNI(register_android_graphics_Picture), REG_JNI(register_android_graphics_PorterDuff), REG_JNI(register_android_graphics_Rasterizer), REG_JNI(register_android_graphics_Region), REG_JNI(register_android_graphics_Shader), REG_JNI(register_android_graphics_SurfaceTexture), REG_JNI(register_android_graphics_Typeface), REG_JNI(register_android_graphics_Xfermode), REG_JNI(register_android_graphics_YuvImage), REG_JNI(register_android_graphics_pdf_PdfDocument), REG_JNI(register_android_database_CursorWindow), REG_JNI(register_android_database_SQLiteConnection), REG_JNI(register_android_database_SQLiteGlobal), REG_JNI(register_android_database_SQLiteDebug), REG_JNI(register_android_os_Debug), REG_JNI(register_android_os_FileObserver), REG_JNI(register_android_os_FileUtils), REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_SELinux), REG_JNI(register_android_os_Trace), REG_JNI(register_android_os_UEventObserver), REG_JNI(register_android_net_LocalSocketImpl), REG_JNI(register_android_net_NetworkUtils), REG_JNI(register_android_net_TrafficStats), REG_JNI(register_android_net_wifi_WifiNative), REG_JNI(register_android_os_MemoryFile), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), REG_JNI(register_android_media_AudioRecord), REG_JNI(register_android_media_AudioSystem), REG_JNI(register_android_media_AudioTrack), REG_JNI(register_android_media_JetPlayer), REG_JNI(register_android_media_RemoteDisplay), REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_opengl_classes), REG_JNI(register_android_server_NetworkManagementSocketTagger), REG_JNI(register_android_server_Watchdog), REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_FileBackupHelperBase), REG_JNI(register_android_backup_BackupHelperDispatcher), REG_JNI(register_android_app_backup_FullBackup), REG_JNI(register_android_app_ActivityThread), REG_JNI(register_android_app_NativeActivity), REG_JNI(register_android_view_InputChannel), REG_JNI(register_android_view_InputEventReceiver), REG_JNI(register_android_view_InputEventSender), REG_JNI(register_android_view_InputQueue), REG_JNI(register_android_view_KeyEvent), REG_JNI(register_android_view_MotionEvent), REG_JNI(register_android_view_PointerIcon), REG_JNI(register_android_view_VelocityTracker), REG_JNI(register_android_content_res_ObbScanner), REG_JNI(register_android_content_res_Configuration), REG_JNI(register_android_animation_PropertyValuesHolder), REG_JNI(register_com_android_internal_content_NativeLibraryHelper), REG_JNI(register_com_android_internal_net_NetworkStatsFactory), };
REG_JNI是系统定义的一个宏:
#ifdef NDEBUG #define REG_JNI(name) { name } struct RegJNIRec { int (*mProc)(JNIEnv*); }; #else #define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); const char* mName; }; #endif
以gRegJNI数组中的一项为例,REG_JNI(register_android_debug_JNITest) 展开REG_JNI后变为:
{ register_android_debug_JNITest, "register_android_debug_JNITest" }
所以当register_jni_procs()中调用mProcess时,最终调用的是android_debug_JNITest类中的register_android_debug_JNITest:
int register_android_debug_JNITest(JNIEnv* env) { return jniRegisterNativeMethods(env, "android/debug/JNITest", gMethods, NELEM(gMethods)); }
到这里JNI注册就讲完了。
ZygoteInit初始化
在JNI注册完成后,让我们再回头继续看AndroidRuntime中start函数:
env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过JNI调用main()方法
在start()中通过JNI调用ZygoteInit类的main()方法,这个main()方法即使从native世界到Java世界的入口。
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start();//启动性能统计 registerZygoteSocket();//注册zygote用的socket EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload();//初始化,主要进行framework中一些类和资源的预加载 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot();//结束统计并生成结果文件 // Do an initial gc to clean up after startup gc();//强制进行一次回收 // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (argv[1].equals("start-system-server")) { startSystemServer();//启动system_server进程 } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); runSelectLoop();//变成守护进程,接收socket信息进行处理 closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
简单总结一下ZygoteInit类中main()函数主要做了如下几件事:
- 注册Zygote用的socket
- 类和资源的预加载
- 启动system_server进程
- 进入一个死循环,等待接收和处理socket事件
接下来将对它们一一进行分析。
registerZygoteSocket()方法
registerZygoteSocket()方法的实现如下:
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ private static void registerZygoteSocket() { if (sServerSocket == null) { int fileDesc; try { String env = System.getenv(ANDROID_SOCKET_ENV);//从环境变量中获取socket的fd fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException( ANDROID_SOCKET_ENV + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket ‘" + fileDesc + "‘", ex); } } }
registerZygoteSocket()方法比较简单,就是创建了一个服务端Socket。
类和资源的预加载
在Zygote中通过preload()方法完成类和资源的加载,它的实现如下:
static void preload() { preloadClasses();//加载类 preloadResources();//加载资源 preloadOpenGL();//加载OpenGL }
先看一下preloadClasses():
/** * Performs Zygote process initialization. Loads and initializes * commonly used classes. * * Most classes only cause a few hundred bytes to be allocated, but * a few will allocate a dozen Kbytes (in one case, 500+K). */ private static void preloadClasses() { final VMRuntime runtime = VMRuntime.getRuntime(); InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream( PRELOADED_CLASSES);//加载preloaded-classes这个文件中定义的需要预加载的类 if (is == null) { Log.e(TAG, "Couldn‘t find " + PRELOADED_CLASSES + "."); } else { Log.i(TAG, "Preloading classes..."); long startTime = SystemClock.uptimeMillis(); // Drop root perms while running static initializers. setEffectiveGroup(UNPRIVILEGED_GID); setEffectiveUser(UNPRIVILEGED_UID); // Alter the target heap utilization. With explicit GCs this // is not likely to have any effect. float defaultUtilization = runtime.getTargetHeapUtilization(); runtime.setTargetHeapUtilization(0.8f); // Start with a clean slate. System.gc(); runtime.runFinalizationSync(); Debug.startAllocCounting(); try { BufferedReader br = new BufferedReader(new InputStreamReader(is), 256); int count = 0; String line; while ((line = br.readLine()) != null) { // Skip comments and blank lines. line = line.trim(); if (line.startsWith("#") || line.equals("")) { continue; } try { if (false) { Log.v(TAG, "Preloading " + line + "..."); } Class.forName(line);//以反射的方式加载类 if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) { if (false) { Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); } System.gc(); runtime.runFinalizationSync(); Debug.resetGlobalAllocSize(); } count++; } catch (ClassNotFoundException e) { Log.w(TAG, "Class not found for preloading: " + line); } catch (Throwable t) { Log.e(TAG, "Error preloading " + line + ".", t); if (t instanceof Error) { throw (Error) t; } if (t instanceof RuntimeException) { throw (RuntimeException) t; } throw new RuntimeException(t); } } Log.i(TAG, "...preloaded " + count + " classes in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } catch (IOException e) { Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e); } finally { IoUtils.closeQuietly(is); // Restore default. runtime.setTargetHeapUtilization(defaultUtilization); // Fill in dex caches with classes, fields, and methods brought in by preloading. runtime.preloadDexCaches(); Debug.stopAllocCounting(); // Bring back root. We‘ll need it later. setEffectiveUser(ROOT_UID); setEffectiveGroup(ROOT_GID); } } }
preloadClasses()的实现很简单,这里说一下preloaded-classes文件:
# Classes which are preloaded by com.android.internal.os.ZygoteInit. # Automatically generated by frameworks/base/tools/preload/WritePreloadedClassFile.java. # MIN_LOAD_TIME_MICROS=1250 # MIN_PROCESSES=10 android.R$styleable android.accounts.Account android.accounts.Account$1 android.accounts.AccountManager android.accounts.AccountManager$12 android.accounts.AccountManager$13 android.accounts.AccountManager$6 android.accounts.AccountManager$AmsTask android.accounts.AccountManager$AmsTask$1 android.accounts.AccountManager$AmsTask$Response
在Android4.4的源代码中有2782行,也就说这里在系统启动时需要预加载两千多个类,而这仅仅是源代码,在手机厂商的代码中,需要进行预加载的类的数量将会超过这个数。preloaded-classes文件时由WritePreloadedClassFile类生成的。WritePreloadedClassFile将某个类加入预加载文件preloaded-classes中的条件时:该类被不少于10个进程使用,并且家中该类好使超过1250微秒。WritePreloadedClassFile里面的实现非常简单,感兴趣的读者可以自行阅读。
/** * Preload any class that take longer to load than MIN_LOAD_TIME_MICROS us. */ static final int MIN_LOAD_TIME_MICROS = 1250; /** * Preload any class that was loaded by at least MIN_PROCESSES processes. */ static final int MIN_PROCESSES = 10;
这里我简单估算了一下,在Android4.4中预加载这些类需要4秒钟作用,这对于系统启动来说是一个比较长的时间,因此在进行系统启动速度的优化时,这里可以作为一个优化大点。
在看preloadClass的代码时有些读者看的setEffectiveUser的几句代码不明白什么意思:
private static void preloadClasses() { ...... // Drop root perms while running static initializers. setEffectiveGroup(UNPRIVILEGED_GID); setEffectiveUser(UNPRIVILEGED_UID); ...... } finally { ...... // Bring back root. We‘ll need it later. setEffectiveUser(ROOT_UID); setEffectiveGroup(ROOT_GID); } } }
以setEffectiveUser为例看一下它的实现:
/** * Sets effective user ID. */ private static void setEffectiveUser(int uid) { int errno = setreuid(ROOT_UID, uid); if (errno != 0) { Log.e(TAG, "setreuid() failed. errno: " + errno); } }
/** * The Linux syscall "setreuid()" * @param ruid real uid * @param euid effective uid * @return 0 on success, non-zero errno on fail */ static native int setreuid(int ruid, int euid);
可以看出这里setEffectiveUser这几句的意思是:在类加载之前临时降低euid(真实用户ID)权限,加载完成后恢复。关于Linux各种userid的说明如下:
有效用户ID
有效用户ID(Effective UID,即EUID)与有效用户组ID(Effective Group ID,即EGID)在创建与访问文件的时候发挥作用;具体来说,创建文件时,系统内核将根据创建文件的进程的EUID与EGID设定文件的所有者/组属性,而在访问文件时,内核亦根据访问进程的EUID与EGID决定其能否访问文件。
真实用户ID
真实用户ID(Real UID,即RUID)与真实用户组ID(Real GID,即RGID)用于辨识进程的真正所有者,且会影响到进程发送信号的权限。没有超级用户权限的进程仅在其RUID与目标进程的RUID相匹配时才能向目标进程发送信号,例如在父子进程间,子进程从父进程处继承了认证信息,使得父子进程间可以互相发送信号。
暂存用户ID
暂存用户ID(Saved UID,即SUID)于以提升权限运行的进程暂时需要做一些不需特权的操作时使用,这种情况下进程会暂时将自己的有效用户ID从特权用户(常为root)对应的UID变为某个非特权用户对应的UID,而后将原有的特权用户UID复制为SUID暂存;之后当进程完成不需特权的操作后,进程使用SUID的值重置EUID以重新获得特权。在这里需要说明的是,无特权进程的EUID值只能设为与RUID、SUID与EUID(也即不改变)之一相同的值。
文件系统用户ID
文件系统用户ID(File 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
那这里这样做的用意何在?我猜这里是为了保证预加载的类是所有的用户都是可用的。
预加载资源的代码如下:
/** * Load in commonly used resources, so they can be shared across * processes. * * These tend to be a few Kbytes, but are frequently in the 20-40K * range, and occasionally even larger. */ private static void preloadResources() { final VMRuntime runtime = VMRuntime.getRuntime(); Debug.startAllocCounting(); try { System.gc(); runtime.runFinalizationSync(); mResources = Resources.getSystem(); mResources.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources..."); long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar);//预加载Drawable ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar);//预加载Color ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } mResources.finishPreloading(); } catch (RuntimeException e) { Log.w(TAG, "Failure preloading resources", e); } finally { Debug.stopAllocCounting(); } }
preloadResources的加载过程又分为加载Drawable和加载Color。
除了加载类和资源,还会加载OpenGL的一些东西:
private static void preloadOpenGL() { if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) { EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); } }
在创建socket和资源加载前后有这么两句:
// Start profiling the zygote initialization. SamplingProfilerIntegration.start();//启动性能统计 registerZygoteSocket();//注册zygote用的socket EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload();//初始化,主要进行framework中一些类和资源的预加载 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot();//结束统计并生成结果文件
所以,这里SamplingProfilerIntegration统计的是创建socket和类及资源初始化的时间。
启动system_server
/** * Prepare the arguments and fork for the system server process. */ private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_RESOURCE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG ); /* Hardcoded command line to start the system server */ String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ pid = Zygote.forkSystemServer(//以fork的方式创建system_server进程 parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) {//pid==0说明在子进程中,父进程为Zygote handleSystemServerProcess(parsedArgs); } return true; }
这里前面的一大段代码主要是在为fork准备参数parsedArgs,然后Zygote会forkSystemServer来创建system_server,forkSystemServer()方法最终会调用Linux中的fork()。
runSelectLoop()方法
在创建system_server后,Zygote调用runSelectLoop()进入到一个死循环中:
/** * Runs the zygote process‘s select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request‘s * worth at a time. * * @throws MethodAndArgsCaller in a child process when a main() should * be executed. */ private static void runSelectLoop() throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor());//registerZygoteSocket中创建的socket的描述符 peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) {//死循环 int index;//selectReadable方法监控的句柄的下标(fdArray中的下标) /* * Call gc() before we block in select(). * It‘s work that has to be done anyway, and it‘s better * to avoid making every child do it. It will also * madvise() any free memory as a side-effect. * * Don‘t call it every time, because walking the entire * heap is a lot of overhead to free a few hundred bytes. */ if (loopCount <= 0) {//Zygote每循环GC_LOOP_COUNT(这里的值是10)次就会进行一次内存回收 gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; } try { fdArray = fds.toArray(fdArray); index = selectReadable(fdArray);//内部由select()实现,在没有客户端事件时会堵塞 } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); } if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件 ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else {//调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index == 0时被添加到peers的 boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }
下面是selectReadable方法的代码:
/** * Invokes select() on the provider array of file descriptors (selecting * for readability only). Array elements of null are ignored. * * @param fds non-null; array of readable file descriptors * @return index of descriptor that is now readable or -1 for empty array. * @throws IOException if an error occurs */ static native int selectReadable(FileDescriptor[] fds) throws IOException;
selectReadable的native实现在com_android_internal_os_ZygoteInit.cpp中。
Zygote接收到socket客户端的链接后会将其(客户端Socket)保存到一个ZygoteConnection对象中,然后保存到peers
/** * Waits for and accepts a single command connection. Throws * RuntimeException on failure. */ private static ZygoteConnection acceptCommandPeer() { try { return new ZygoteConnection(sServerSocket.accept()); } catch (IOException ex) { throw new RuntimeException( "IOException during accept()", ex); } }
最后,客户端的请求会有ZygoteConnection的runOnce来处理。
在ZygoteInit的main()方法中做了几件大事,其中一件便是启动Systemserver进程,代码如下:
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) { try { ...... if (argv[1].equals("start-system-server")) { startSystemServer();//启动system_server进程 } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } ...... }
startSystemServer方法的实现如下:
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/** * Prepare the arguments and fork for the system server process. */ private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_RESOURCE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG ); /* Hardcoded command line to start the system server */ String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ pid = Zygote.forkSystemServer(//以fork的方式创建system_server进程 parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) {//pid==0说明在子进程中,父进程为Zygote handleSystemServerProcess(parsedArgs); } return true; }
在startSystemServer中先设置了fork SystemServer所需的参数,然后通过forkSystemServer方法fork出SystemServer进程,最后通过handleSystemServerProcess处理新进程中的善后事宜。
首先看一下参数:
1、setuid=1000,这里1000代表SYSTEM_UID,即系统进程,关于进程ID的说明可以参见:/frameworks/base/core/java/android/os/Process.java。
2、nice-name=system_server表示制定进程的名字为“system_server”
3、com.android.server.SystemServer表示SystemServer类的位置。
接下来看一下forkSystemServer的实现:
@/libcore/dalvik/src/main/java/dalvik/system/Zygote.java
/** * Special method to start the system server process. In addition to the * common actions performed in forkAndSpecialize, the pid of the child * process is recorded such that the death of the child process will cause * zygote to exit. * * @param uid the UNIX uid that the new process should setuid() to after * fork()ing and and before spawning any threads. * @param gid the UNIX gid that the new process should setgid() to after * fork()ing and and before spawning any threads. * @param gids null-ok; a list of UNIX gids that the new process should * setgroups() to after fork and before spawning any threads. * @param debugFlags bit flags that enable debugging features. * @param rlimits null-ok an array of rlimit tuples, with the second * dimension having a length of 3 and representing * (resource, rlim_cur, rlim_max). These are set via the posix * setrlimit(2) call. * @param permittedCapabilities argument for setcap() * @param effectiveCapabilities argument for setcap() * * @return 0 if this is the child, pid of the child * if this is the parent, or -1 on error. */ public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { preFork(); int pid = nativeForkSystemServer( uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities); postFork(); return pid; } native public static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
nativeForkSystemServer最终通过JNI实现,代码为:
@/dalvik/vm/native/dalvik_system_Zygote.cpp
/* * native public static int nativeForkSystemServer(int uid, int gid, * int[] gids, int debugFlags, int[][] rlimits, * long permittedCapabilities, long effectiveCapabilities); */ static void Dalvik_dalvik_system_Zygote_forkSystemServer( const u4* args, JValue* pResult) { pid_t pid; pid = forkAndSpecializeCommon(args, true); /* The zygote process checks whether the child process has died or not. */ if (pid > 0) {//pid大于0,说明是在父进程中 int status; ALOGI("System server process %d has been created", pid); gDvm.systemServerPid = pid; /* There is a slight window that the system server process has crashed * but it went unnoticed because we haven‘t published its pid yet. So * we recheck here just to make sure that all is well. */ if (waitpid(pid, &status, WNOHANG) == pid) {//堵塞,等待system_server进程 ALOGE("System server process %d has died. Restarting Zygote!", pid); kill(getpid(), SIGKILL);//一旦上面的等待返回,说明进程pid(system_server)已终止,此时Zygote杀死自己 } } RETURN_INT(pid); }
可以看出Dalvik_dalvik_system_Zygote_forkSystemServer会调用forkAndSpecializeCommon来fork出system_server进程。这里要注意最后几句,在fork出system_server以后,Zygote会调用waitpid等待system_server的终止,一旦发现system_server终止,Zygote则马上自杀。
接下来看一下handleSystemServerProcess的实现:
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/** * Finish remaining work for the newly forked system server process. */ private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller { closeServerSocket();//关闭从Zygote复制过来的socket // set umask to 0077 so new files and directories will default to owner-only permissions. Libcore.os.umask(S_IRWXG | S_IRWXO);//设置文件的默认权限,去除所有者之外的权限 if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName);//system_server } if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, null, parsedArgs.remainingArgs); } else { /* * Pass the remaining arguments to SystemServer. */ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } /* should never reach here */ }
上面的代码中用到了Linux中的umask这个函数,不明白的读者可以参考:http://hi.baidu.com/fengyun409/item/82cd158ffe7f67c8b17154e7。
下面继续看RuntimeInit.zygoteInit方法的实现:
@/frameworks/base/core/java/com/android/internel/os/RuntimeInit.java
/** * The main function called when started through the zygote process. This * could be unified with main(), if the native code in nativeFinishInit() * were rationalized with Zygote startup.<p> * * Current recognized args: * <ul> * <li> <code> [--] <start class name> <args> * </ul> * * @param targetSdkVersion target SDK version * @param argv arg strings */ public static final void zygoteInit(int targetSdkVersion, String[] argv) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams();//将System.out 和 System.err 输出重定向到Android 的Log系统 /* * 初始化了一些系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler, * 当代码有任何未知异常,就会执行它, * 调试过Android代码的同学经常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自这里 */ commonInit(); /* * 最终会调用app_main的onZygoteInit函数 * 这里的作用是在新进程中引入Binder,也就说通过nativeZygoteInit以后,新的进程就可以使用Binder进程通信了 */ nativeZygoteInit(); applicationInit(targetSdkVersion, argv);//应用初始化 }
Zygote进程在接收到ActivityManagerService请求创建进程的请求时就调用的该方法来处理创建子进程的后续工作。
private static void applicationInit(int targetSdkVersion, String[] argv) throws ZygoteInit.MethodAndArgsCaller { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the // Android runtime shutdown hooks close the Binder driver, which can cause // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn‘t needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } // Remaining arguments are passed to the start class‘s static main invokeStaticMain(args.startClass, args.startArgs); }
所以,这里与Zygote分裂时不同的是:这里的args.startClass的值为com.android.server.SystemServer。接下来大家都知道了,SystemServer类的main函数将会被调用。
@/frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) { if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { // If a device‘s clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it // shortly. Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);//初始化系统时间 } if (SamplingProfilerIntegration.isEnabled()) { SamplingProfilerIntegration.start(); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // Mmmmmm... more memory! dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); Environment.setUserRequired(true); System.loadLibrary("android_servers");//加载android_servers库 Slog.i(TAG, "Entered the Android system server!"); // Initialize native services. nativeInit();//初始化native service // This used to be its own separate thread, but now it is // just the loop we run on the main thread. ServerThread thr = new ServerThread(); thr.initAndLoop(); }
在main中会加载libandroid_servers.so库,然后调用nativeInit初始化native层的Service。
/** * Called to initialize native system services. */ private static native void nativeInit();
@/frameworks/base/services/jni/com_android_server_SystemServer.cpp
static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) { char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsensorservice", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the sensor service SensorService::instantiate(); } }
可以看出这里只初始化了传感器service,这与之前的代码有所不同,在比较早的Android版本中,服务的初始化分为init1和init2两个过程,其中init主要负责native层service的初始化(SurfaceFlinger、AudioFlinger等),init2负责java层service的初始化。
在main方法最后会调用ServerThread类的initAndLoop来初始化系统服务,这个函数比较长,这里就不复制代码了。
到这里SystemServer的诞生过程就完了。
在完成Java世界的初创工作以后,Zygote并没有死去,它只是暂时的沉睡(socket事件堵塞)在那里,一旦有需要(有客户端请求的到来),它便马上起来工作。本文接下来就将分析一下Zygote是如何监听和处理socket事件的。
首先让我们一起来回忆一下Zygote的main方法:
@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) { try { registerZygoteSocket();//注册zygote用的socket ...... runSelectLoop();//变成守护进程,接收socket信息进行处理 closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
main()方法首先在registerZygoteSocket中注册了Zygote的 服务端Socket对象,然后在完成一系列初创工作后调用runSelectLoop进入到死循环中,等待客户端事件的到来。到了这里我们不禁会问,Zygote进程作为服务端,那客户端是谁呢?Zygote接收到客户端连接以后又是如何处理的呢?下面我们就带着这两个问题一起来分析。
客户端请求
@/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { ...... try { ...... // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, null); ....... }
@/frameworks/base/core/java/android/os/Process.java
/** * Start a new process. * * <p>If processes are enabled, a new process is created and the * static main() function of a <var>processClass</var> is executed there. * The process will continue running after this function returns. * * <p>If processes are not enabled, a new thread in the caller‘s * process is created and main() of <var>processClass</var> called there. * * <p>The niceName parameter, if not an empty string, is a custom name to * give to the process instead of using processClass. This allows you to * make easily identifyable processes even if you are using the same base * <var>processClass</var> to start them. * * @param processClass The class to use as the process‘s main entry * point. * @param niceName A more readable name to use for the process. * @param uid The user-id under which the process will run. * @param gid The group-id under which the process will run. * @param gids Additional group-ids associated with the process. * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SE Android information for the new process. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure * * {@hide} */ public static final ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); throw new RuntimeException( "Starting VM process through Zygote failed", ex); } }
startViaZygote()方法的实现如下:
/** * Starts a new process via the zygote mechanism. * * @param processClass Class name whose static main() to run * @param niceName ‘nice‘ process name to appear in ps * @param uid a POSIX uid that the new process should setuid() to * @param gid a POSIX gid that the new process shuold setgid() to * @param gids null-ok; a list of supplementary group IDs that the * new process should setgroup() to. * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SE Android information for the new process. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason */ private static ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-init, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add("--runtime-init"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) { argsForZygote.add("--enable-jni-logging"); } if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { argsForZygote.add("--enable-safemode"); } if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { argsForZygote.add("--enable-debugger"); } if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { argsForZygote.add("--enable-checkjni"); } if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { argsForZygote.add("--enable-assert"); } if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) { argsForZygote.add("--mount-external-multiuser"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) { argsForZygote.add("--mount-external-multiuser-all"); } argsForZygote.add("--target-sdk-version=" + targetSdkVersion); //TODO optionally enable debuger //argsForZygote.add("--enable-debugger"); // --setgroups is a comma-separated list if (gids != null && gids.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--setgroups="); int sz = gids.length; for (int i = 0; i < sz; i++) { if (i != 0) { sb.append(‘,‘); } sb.append(gids[i]); } argsForZygote.add(sb.toString()); } if (niceName != null) { argsForZygote.add("--nice-name=" + niceName); } if (seInfo != null) { argsForZygote.add("--seinfo=" + seInfo); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } return zygoteSendArgsAndGetResult(argsForZygote); } }
startViaZygote的绝大部分代码都在处理传递到Zygote中的参数,与Zygote通信通过zygoteSendArgsAndGetResult()方法完成:
/** * Sends an argument list to the zygote process, which starts a new child * and returns the child‘s pid. Please note: the present implementation * replaces newlines in the argument list with spaces. * @param args argument list * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason */ private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args) throws ZygoteStartFailedEx { openZygoteSocketIfNeeded();//确保和Zygote通信的socket已被打开 try { /** * See com.android.internal.os.ZygoteInit.readArgumentList() * Presently the wire format to the zygote process is: * a) a count of arguments (argc, in essence) * b) a number of newline-separated argument strings equal to count * * After the zygote process reads these it will write the pid of * the child or -1 on failure, followed by boolean to * indicate whether a wrapper process was used. */ sZygoteWriter.write(Integer.toString(args.size())); sZygoteWriter.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) {//发送请求参数到Zygote String arg = args.get(i); if (arg.indexOf(‘\n‘) >= 0) { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } sZygoteWriter.write(arg); sZygoteWriter.newLine(); } sZygoteWriter.flush(); // Should there be a timeout on this? ProcessStartResult result = new ProcessStartResult(); result.pid = sZygoteInputStream.readInt();//Zygote处理完成会返回子进程的pid(即要创建的进程) if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } result.usingWrapper = sZygoteInputStream.readBoolean(); return result; } catch (IOException ex) { try { if (sZygoteSocket != null) { sZygoteSocket.close(); } } catch (IOException ex2) { // we‘re going to fail anyway Log.e(LOG_TAG,"I/O exception on routine close", ex2); } sZygoteSocket = null; throw new ZygoteStartFailedEx(ex); } }
到这里位置,客户端请求Zygote创建进程的请求就发送出去了,Zygote会返回进行的pid给客户端(ActivityMangerService)。由于ActivityMangerService在SystemServer进程中,所以这里即SystemServer进程通过socket向Zygote发送了信息。
接下来,我们看一下看一下Zygote是如何处理客户端请求的。
处理客户端请求
/** * Runs the zygote process‘s select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request‘s * worth at a time. * * @throws MethodAndArgsCaller in a child process when a main() should * be executed. */ private static void runSelectLoop() throws MethodAndArgsCaller { ...... while (true) {//死循环 ...... if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) {//index==0表示selcet接收到的是Zygote的socket的事件 ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else {//调用ZygoteConnection对象的runOnce方法,ZygoteConnection是在index == 0时被添加到peers的 boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }
每当有请求过来时,Zygote都会调用ZygoteConnection的runOnce()方法处理:
@/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
/** * Reads one start command from the command socket. If successful, * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} * exception is thrown in that child while in the parent process, * the method returns normally. On failure, the child is not * spawned and messages are printed to the log and stderr. Returns * a boolean status value indicating whether an end-of-file on the command * socket has been encountered. * * @return false if command socket should continue to be read from, or * true if an end-of-file has been encountered. * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() * method in child process */ boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { args = readArgumentList();//读取客户端发送过来的参数 descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; } if (args == null) { // EOF reached. closeSocket(); return true; } /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); } int pid = -1; FileDescriptor childPipeFd = null; FileDescriptor serverPipeFd = null; try { parsedArgs = new Arguments(args); applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { FileDescriptor[] pipeFds = Libcore.os.pipe(); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; ZygoteInit.setCloseOnExec(serverPipeFd, true); } //fork一个新进程 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName); } catch (IOException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex); } try { if (pid == 0) {//子进程 // in child IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else {//父进程 // in parent...pid of < 0 means failure IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
Zygote在处理客户端请求时会fork一个新的进程,接下来首先看一下handleChildProc()方法:
/** * Handles post-fork setup of child proc, closing sockets as appropriate, * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller * if successful or returning if failed. * * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. * @param newStderr null-ok; stream to use for stderr until stdio * is reopened. * * @throws ZygoteInit.MethodAndArgsCaller on success to * trampoline to code that invokes static main. */ private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { closeSocket();//关闭子进程中,从Zygote fork过来的服务端socket ZygoteInit.closeServerSocket(); ..... if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); } if (parsedArgs.runtimeInit) {//从startViaZygote可知传入了--runtime-init参数,所以这里为true if (parsedArgs.invokeWith != null) {//没有传入--invoke-with,所以这里走的是else的逻辑 WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs); } } else { ...... } }
zygoteInit()方法的实现在RuntimeInit类中:
@/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/** * The main function called when started through the zygote process. This * could be unified with main(), if the native code in nativeFinishInit() * were rationalized with Zygote startup.<p> * * Current recognized args: * <ul> * <li> <code> [--] <start class name> <args> * </ul> * * @param targetSdkVersion target SDK version * @param argv arg strings */ public static final void zygoteInit(int targetSdkVersion, String[] argv) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams();//将System.out 和 System.err 输出重定向到Android 的Log系统 /* * 初始化了一些系统属性,其中最重要的一点就是设置了一个未捕捉异常的handler, * 当代码有任何未知异常,就会执行它, * 调试过Android代码的同学经常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自这里 */ commonInit(); /* * 最终会调用app_main的onZygoteInit函数 * 这里的作用是在新进程中引入Binder,也就说通过nativeZygoteInit以后,新的进程就可以使用Binder进程通信了 */ nativeZygoteInit(); applicationInit(targetSdkVersion, argv);//应用初始化 }
接下来继续分析applicationInit(),走完进程启动的整个过程,然后再回头分析一下commonInit和nativeZygoteInit的实现。applicationInit的实现如下:
private static void applicationInit(int targetSdkVersion, String[] argv) throws ZygoteInit.MethodAndArgsCaller { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the // Android runtime shutdown hooks close the Binder driver, which can cause // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn‘t needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } // Remaining arguments are passed to the start class‘s static main invokeStaticMain(args.startClass, args.startArgs); }
在applicationInit()的最后,会通过调用invokeStaticMain来调用args.startClass这个类的main()方法。在前面介绍socket的客户端代码时,在startProcessLocked()中传入的这个类为"android.app.ActivityThread"。所以接下来invokeStaticMain()的功能相信大家都已经知道了,就是调用ActivityThread类的main(),下面是代码:
/** * Invokes a static "main(argv[]) method on class "className". * Converts various failing exceptions into RuntimeExceptions, with * the assumption that they will then cause the VM instance to exit. * * @param className Fully-qualified class name * @param argv Argument vector for main() */ private static void invokeStaticMain(String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className); } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className, ex); } Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex); } int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception‘s run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv); }
这个方法本身功能就是调用ActivityThread类的main(),没什么可说的。不过需要注意一下的是这里的调用方式十分特别,并没有采取常规的反射调用,而是通过抛出异常的方式调用ActivityThread的main()函数。这里抛出的ZygoteInit.MethodAndArgsCaller异常会在ZygoteInit.main()中被捕获处理。
public static void main(String argv[]) { try { ...... } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { ...... } }
这里需要注意的是:捕获异常是在子进程(即新的进程,不是Zygote进程)中的动作。还记得前面介绍的runOnce()方法吗?我们在runOnce中创建了一个新的进程。如果读者还有不明白这里为什么是在子进程,可以自行学习Linux fork()的原理。好了,继续..... 看一下MethodAndArgsCaller的代码:
@/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/** * Helper exception class which holds a method and arguments and * can call them. This is used as part of a trampoline to get rid of * the initial process setup stack frames. */ public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) { mMethod = method; mArgs = args; } public void run() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } }
可以看出最后还是会调用invoke方法通过反射的方式调用ActivityThread的main方法。
到了这里,相信大家都会有一个疑问:既然最后还是通过invoke来反射调用main方法,那绕这一大圈子到底在折腾什么?
有疑问的读者,有没有去思考过另外一个问题:我们为什么要通过Zygote去创建进程,而不是直接创建一个新的进程出来呢?这就要从Zygote创建进程的机制来解释。相信我们还记得在ZygoteInit的main函数中我们通过preload来预加载类和资源。所以这些被预加载的类和资源都存在于Zygote进程中。在通过Zygote创建进程时,我们是通过fork来创建的。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同,相当于克隆了一个自己。所以,Zygote通过fork的方式创建新的应用进程的同时,会将对系统的(主要是framework中的)一些类和资源的引用同时复制给子进程,这样子进程中就可以使用这些资源了。这也是为什么所有的应用程序可以共享Framework中的类和资源的原因。
在明白了Zygote机制后,对应为什么这里会以抛出异常的方式调用ActivityThread(应用程序入口)的main()方法,就变得容易理解了。在Java中,我们进行一些列的方法调用的时候,系统会为我们在内存中维护一个调用栈,栈底是发起调用的方法,栈顶是当前正在被调用的方法。在栈顶的方法调用完成后,会逐级返回调用它的方法,最后调用会回到最开始的方法中,然后调用栈就被销毁了。在Zygote处理客户端事件的时候,沿着各种方法一路调用下来,如果在调用ActivityThread中的main()时,直接使用invoke,那么在invoke结束后,整个调用过程会递归返回,最后发起方得到调用结果,调用栈被销毁。然后每次的调用都会重复刚才的那个过程,这就造成了极大的浪费。
采用异常的方式,可以保证调用栈不会被销毁,这样每次fork时就可以共享。
关于zygote的总结:
zygote是整个系统创建新进程的核心装置
如果fork()出的新进程是system server,那么其最终执行的就是SystemServer类的main()函数,而如果fork()出的新进程是普通的用户进程的话,那么其最终执行的就是ActivityThread类的main()函数。
zygote进程在内部会先启动Dalvik虚拟机,继而加载一些必要的系统资源和系统类,最后进入一种监听状态。在后续的运作中,当其他系统模块(比如AMS)希望创建新进程时,只需向zygote进程发出请求,zygote进程监听到该请求后,会相应地“分裂”出新的进程,于是这个新进程在初生之时,就先天具有了自己的Dalvik虚拟机以及系统资源。