Android开机流程分析 -- Zygote
一、第一个Dalvik虚拟机Zygote
为什么将Zygote叫做受精卵呢?是因为在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的。
Android应用程序是由java语言编写的,运行于各自独立的Dalvik虚拟机中。那么Android的处理机制是什么呢?Android首先创建一个Zygote虚拟机,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高了应用程序启动和运行速度。
1、Zygote配置
zygote是在init.rc中定义的守护进程服务(Daemon Service),在Android5.0中,Zygote的启动发生了一些变化,以前直接放在init.rc中的代码块放到了单独的文件中,在init.rc中通过import的方式引入文件,如下:
import /init.${ro.zygote}.rc
从上面的语句可以看出,init.rc并不是直接引入某个固定的文件,而是根据属性“ro.zygote”的内容来引入不同的文件。这是因为Android从5.0开始,Android开始支持64位的编译,Zygote本身也会有32位和64位版本的区别,因此,这里通过ro.zygote属性来控制启动不同版本的Zygote进程。该文件位于system/core/init/下,目录下有Init.zygote64.rc,Init.zygote32.rc,Init.zygote32_64.rc,Init.zygot64_32.rc,至于调用哪个是由硬件决定的,这里以Init.zygote64_32.rc为例,代码如下:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main #class是一个Option,指定zygote服务的类型是main
socket zygote stream 660 root system #socket是一个Option,创建一个Socket名为dev/socket/zygote,Socket类型是stream,权限为660
onrestart write /sys/android_power/request_state wake #onrestart是一个Option,设置zygote重启时需要执行的Command
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin--zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
onrestart restart zygote
从代码中我们可以看出,系统定义了两个Zygote服务:zygote和zygote_secondary。这两个服务最大的区别是启动的可执行文件不同,一个是app_process64,另一个是app_process32。由关键字service告诉init进程创建一个名为“zygote”的进程,这个zygote进程要执行的程序是/system/bin/app_process64(可执行文件),给这个zygote进程传递了5个参数,分别是-Xzygote,/system/bin,--zygote,--start-system-server,--socket-name=zygote;另外zygote服务需要开启一个Socket,并且zygote重启时,需要执行下面的命令:
修改/sys/android_power/request_state;修改/sys/power/state;重启media;重启netd。
2、zygote的执行
我们先看下Zygote进程的初始化过程,如下:
从上面的分析中可以看出zygote要执行的程序是/system/bin/app_process,它的源码位于frameworks/base/cmds/app_process/App_main.cpp文件中,入口函数是main。
main函数的主要功能是解析启动参数。
在源码中提供了app_process的启动方式,参数如下:
app_process [java-options(虚拟机参数)] cmd-dir(运行目录) start-calss-name(java类) [options(参数)]
[java-options]:指定启动dalvik虚拟机时传递给虚拟机的参数,以“-”开头;
cmd-dir:要运行的进程所在的目录,通常是/system/bin;
start-class-name:指定要加载到虚拟机的类,而后调用其main方法;使用参数“--zygote”时会直接执行ZygoteInit类。
[options]:指定传递给类的参数;以符号“--”开头。参数“--zygote”表示要启动zygote进程。参数“--application”表示要以普通进程的方式执行java代码。
我们看下App_main中main函数的代码,AppRuntime是在app_process中定义的类,继承了系统的AndroidRuntime类。AndroidRuntime类的主要作用是创建和初始化虚拟机。
int main(int argc, char* const argv[]){ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return // EINVAL. Don't die on such kernels. if (errno != EINVAL) { LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); return 12; } } AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; /* 因为argv[0]不是参数,所以忽略argv[0],并将argc减1*/ // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { /* 如果参数中指定了--zygote,则启动zygote,niceName设置为“zygote” */ zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; /* 是否启动System Server */ } else if (strcmp(arg, "--application") == 0) { application = true; /* 是否启动application */ } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); /* 是否指定了nice name */ } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } } Vector args; if (!className.isEmpty()) { // We're not in zygote mode, the only argument we need to pass // to RuntimeInit is the application argument. // // The Remainder of args get passed to startup class main(). Make // copies of them before we overwrite them with the process name. args.add(application ? String8("application") : String8("tool"));//非zygote模式 runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop); args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string());/* 根据nicename调用系统函数prctl,open,write修改进程名,由于启动过程中指定了--zygote参数,所以这里的进程名是zygote */ } /* if-else用于匹配两种启动类型,启动zygote或者是启动application */ if (zygote) { /* 如果参数中指定了--zygote,则启动zygote */ runtime.start("com.android.internal.os.ZygoteInit", args); } else if (className) { /* 启动应用程序 */ runtime.start("com.android.internal.os.RuntimeInit", args); } 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; }}
从App_main的main函数中可以看出调用AppRuntime的start方法启动ZygoteInit。
二、ZygoteInit启动过程
AppRuntime的实现代码位于frameworks\base\cmds\app_process\App_main.cpp中,它是AndroidRuntime的派生类,其start方法便是继承自AndroidRuntime。
AndroidRuntime负责开启Android运行时环境,代码位于framewroks\base\core\jni\AndroidRuntime.cpp,定位到start方法,代码如下:
/* * 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. */ /* 根据上面的分析,init.rc中指定了参数--zygote,那么传入到这个函数的参数分别是:classname=“com.android.internal.os.ZygoteInit;options=start-system-server” */void AndroidRuntime::start(const char* className, const Vector& options){ ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); static const String8 startSystemServer("start-system-server"); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { /* 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))); } } 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) { return; } /* 开启虚拟机后执行的工作,这里是空函数体,什么都没做。运行时实际调用的是AppRuntime的onVmCreated函数,保存了类的全局引用。*/ onVmCreated(env); /* * Register android functions.注册Android JNI函数 */ if (startReg(env) < 0) { 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.调用指定类的main函数,并传入参数classname和options。在这之前需要将参数classname和options通过JNI函数转化为JAVA可识别的参数类型。 */ jclass stringClass; jobjectArray strArray; jstring classNameStr; /* 用于转换classname为java可识别类型的字符串 */ stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);/* 调用JNI函数生成一个对象数组,数组大小为options.size()+1(这里为2,只有一个参数start-system-server),存放字符串类型的元素 */ assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); /* 将转化后的classname存入数组 */ for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr);/* 将转化后的options存入数组 */ } /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ /* 将classname转化为slash格式的字符串,以符合JNI的命名规则。这里将com.android.internal.os.ZygoteInit转化为com/android/internal/os/ZygoteInit,用于通过JNI函数findClass找到这个JAVA类。 */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { /* 得到指定类ZygoteInit的main方法的方法ID */ jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { /* 通过调用JNI函数CallStaticVoidMethod调用JAVA类ZygoteInit的main方法,并传入参数com.android.internal.os.ZygoteInit和参数true */ env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env);#endif } } free(slashClassName);/* 将转化后的classname存入数组 */ /* detach当前线程,释放JNI资源并关闭虚拟机 */ 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");}
AndroidRuntime的start方法开启了Android运行时,start方法主要做了三部分工作:
- 创建Dalvik虚拟机:startVm;
- 注册JNI方法:startReg;
- 开启java世界:JNIEnv.CallStaticVoidMethod。
1、创建Dalvik虚拟机
首先分析start工作的第一步,Dalvik虚拟机是调用startVM函数创建的,该函数位于AndroidRuntime.cpp中。代码如下:
/* * Start the Dalvik Virtual Machine. * * Various arguments, most determined by system properties, are passed in. * The "mOptions" vector is updated. * * CAUTION: when adding options in here, be careful not to put the * char buffer inside a nested scope. Adding the buffer to the * options using mOptions.add() does not copy the buffer, so if the * buffer goes out of scope the option may be overwritten. It's best * to put the buffer at the top of the function so that it is more * unlikely that someone will surround it in a scope at a later time * and thus introduce a bug. * * Returns 0 on success. */int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv){ int result = -1; JavaVMInitArgs initArgs; char propBuf[PROPERTY_VALUE_MAX];/* 虚拟机的配置参数 */ char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + 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 gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX]; char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX]; char dalvikVmLibBuf[PROPERTY_VALUE_MAX]; char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatFlagsBuf[PROPERTY_VALUE_MAX]; char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX]; char extraOptsBuf[PROPERTY_VALUE_MAX]; char voldDecryptBuf[PROPERTY_VALUE_MAX]; enum { kEMDefault, kEMIntPortable, kEMIntFast, kEMJitCompiler, } executionMode = kEMDefault; char profilePeriod[sizeof("-Xprofile-period:")-1 + PROPERTY_VALUE_MAX]; char profileDuration[sizeof("-Xprofile-duration:")-1 + PROPERTY_VALUE_MAX]; char profileInterval[sizeof("-Xprofile-interval:")-1 + PROPERTY_VALUE_MAX]; char profileBackoff[sizeof("-Xprofile-backoff:")-1 + PROPERTY_VALUE_MAX]; char profileTopKThreshold[sizeof("-Xprofile-top-k-threshold:")-1 + PROPERTY_VALUE_MAX]; char profileTopKChangeThreshold[sizeof("-Xprofile-top-k-change-threshold:")-1 + PROPERTY_VALUE_MAX]; char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX]; char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX]; char langOption[sizeof("-Duser.language=") + 3]; char regionOption[sizeof("-Duser.region=") + 3]; char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX]; char jitOpBuf[sizeof("-Xjitop:")-1 + PROPERTY_VALUE_MAX]; char jitMethodBuf[sizeof("-Xjitmethod:")-1 + PROPERTY_VALUE_MAX]; char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX]; /* 通过属性系统获得dalvik.vm.checkjni的配置参数,checkjni是开发阶段一个非常重要的属性 * 通过它可以对JNI调用参数进行自动检查,还可以定位一些JNI产生的异常,比如JNI内存泄露。 * 如果checkjni设置为true,JNI调用过程就可以由dalvikvm记录并显示在logcat上。 * JNI检查会大幅度降低性能,只能在eng或userDebug版本上进行配置。 */ bool checkJni = false; 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; } } ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { /* extended JNI checking 选项“-Xcheck:jni”,用来启动JNI方法检查。*/ addOption("-Xcheck:jni"); /* set a cap on JNI global references,设定JNI全局引用的个数不能超过2000 */ addOption("-Xjnigreflimit:2000"); /* with -Xcheck:jni, this provides a JNI function call trace */ //addOption("-verbose:jni"); } /* 指定虚拟机的执行模式,Dalvik虚拟机支持三种运行模式,分别为Portable、Fast、Jit */ property_get("dalvik.vm.execution-mode", propBuf, ""); if (strcmp(propBuf, "int:portable") == 0) { executionMode = kEMIntPortable;/* Dalvik虚拟机以可移植的方式进行编译,即编译出来的虚拟机可以在任何平台上运行 */ } else if (strcmp(propBuf, "int:fast") == 0) { executionMode = kEMIntFast;/* Fast是针对当前平台对Dalvik虚拟机进行编译,这样编译出来的Dalvik虚拟机可以进行特殊的优化,从而使得它能更快的运行程序 */ } else if (strcmp(propBuf, "int:jit") == 0) { executionMode = kEMJitCompiler;/* Jit不是解释执行代码,二是将代码动态编译成本地语言后再执行 */ } /* -Xstacktracefile:用来指定调用堆栈输出文件。 * 当虚拟机收到SIGQUIT(Ctrl-\或者kill -3)信号时,会将所有线程的堆栈信息写入指定文件。 * 可以通过dalvik.vm.stack-trace-file系统属性来指定调用堆栈输出文件。 * 这样可以保留异常发生时的现场,方便调试定位出错原因。*/ parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:"); /* 对优化过的DEX文件进行检测的配置参数,关闭后会提升性能,但如果文件损坏会导致虚拟机崩溃。 */ property_get("dalvik.vm.check-dex-sum", propBuf, ""); if (strcmp(propBuf, "true") == 0) { /* perform additional DEX checksum tests */ addOption("-Xcheckdexsum"); } property_get("log.redirect-stdio", propBuf, ""); if (strcmp(propBuf, "true") == 0) { /* convert stdout/stderr to log messages */ addOption("-Xlog-stdio"); } /* 设置是否支持java的断言表达式 */ strcpy(enableAssertBuf, "-ea:"); property_get("dalvik.vm.enableassertions", enableAssertBuf+sizeof("-ea:")-1, ""); if (enableAssertBuf[sizeof("-ea:")-1] != '\0') { /* accept "all" to mean "all classes and packages" */ if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0) enableAssertBuf[3] = '\0'; // truncate to "-ea" ALOGI("Assertions enabled: '%s'\n", enableAssertBuf); addOption(enableAssertBuf); } else { ALOGV("Assertions disabled\n"); } strcpy(jniOptsBuf, "-Xjniopts:"); if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) { ALOGI("JNI options: '%s'\n", jniOptsBuf); } /* route exit() to our handler */ addOption("exit", (void*) runtime_exit); /* route fprintf() to our handler */ addOption("vfprintf", (void*) runtime_vfprintf); /* register the framework-specific "is sensitive thread" hook */ addOption("sensitiveThread", (void*) runtime_isSensitiveThread); /* enable verbose; standard options are { jni, gc, class } */ //addOption("-verbose:jni"); addOption("-verbose:gc"); //addOption("-verbose:class"); /* * The default starting and maximum size of the heap. Larger * values should be specified in a product property override. * 设置虚拟机heap的大小,包括启动值(heapstartsize)和最大值(heapsize)*/ parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); // Increase the main thread's interpreter stack size for bug 6315322. addOption("-XX:mainThreadStackSize=24K"); // Set the max jit code cache size. Note: size of 0 will disable the JIT. parseRuntimeOption("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:"); parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit="); parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree="); parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); parseRuntimeOption("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization="); property_get("ro.config.low_ram", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-XX:LowMemoryMode"); } parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:"); parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC="); /* * 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) { addOption(val); } } 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) { addOption(val); } } opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */ if (opc != NULL) { addOption("-Xgenregmap"); /* turn on precise GC while we're at it */ addOption("-Xgc:precise"); } } /* enable debugging; set suspend=y to pause during VM init */ /* use android ADB transport */ addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"); parseRuntimeOption("dalvik.vm.lockprof.threshold", lockProfThresholdBuf, "-Xlockprofthreshold:"); /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:"); /* Force interpreter-only mode for selected methods */ parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:"); if (executionMode == kEMIntPortable) { addOption("-Xint:portable"); } else if (executionMode == kEMIntFast) { addOption("-Xint:fast"); } else if (executionMode == kEMJitCompiler) { addOption("-Xint:jit"); } // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart. property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so"); bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0); if (libart) { // If we booting without the real /data, don't spend time compiling. property_get("vold.decrypt", voldDecryptBuf, ""); bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) || (strcmp(voldDecryptBuf, "1") == 0)); // Extra options for boot.art/boot.oat image generation. parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf, "-Xms", "-Ximage-compiler-option"); parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf, "-Xmx", "-Ximage-compiler-option"); if (skip_compilation) { addOption("-Ximage-compiler-option"); addOption("--compiler-filter=verify-none"); } else { parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf, "--compiler-filter=", "-Ximage-compiler-option"); } // Make sure there is a preloaded-classes file. if (!hasFile("/system/etc/preloaded-classes")) { ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n", strerror(errno)); goto bail; } addOption("-Ximage-compiler-option"); addOption("--image-classes=/system/etc/preloaded-classes"); // If there is a compiled-classes file, push it. if (hasFile("/system/etc/compiled-classes")) { addOption("-Ximage-compiler-option"); addOption("--compiled-classes=/system/etc/compiled-classes"); } property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, ""); parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option"); // Extra options for DexClassLoader. parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf, "-Xms", "-Xcompiler-option"); parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf, "-Xmx", "-Xcompiler-option"); if (skip_compilation) { addOption("-Xcompiler-option"); addOption("--compiler-filter=verify-none"); } else { parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf, "--compiler-filter=", "-Xcompiler-option"); } property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, ""); parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option"); } /* extra options; parse this late so it overrides others */ property_get("dalvik.vm.extra-opts", extraOptsBuf, ""); parseExtraOpts(extraOptsBuf, NULL); /* Set the properties for locale */ { strcpy(langOption, "-Duser.language="); strcpy(regionOption, "-Duser.region="); readLocale(langOption, regionOption); addOption(langOption); addOption(regionOption); } /* * Set profiler options */ if (libart) { // Whether or not the profiler should be enabled. property_get("dalvik.vm.profiler", propBuf, "0"); if (propBuf[0] == '1') { addOption("-Xenable-profiler"); } // Whether the profile should start upon app startup or be delayed by some random offset // (in seconds) that is bound between 0 and a fixed value. property_get("dalvik.vm.profile.start-immed", propBuf, "0"); if (propBuf[0] == '1') { addOption("-Xprofile-start-immediately"); } // Number of seconds during profile runs. parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:"); // Length of each profile run (seconds). parseRuntimeOption("dalvik.vm.profile.duration-secs", profileDuration, "-Xprofile-duration:"); // Polling interval during profile run (microseconds). parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:"); // Coefficient for period backoff. The the period is multiplied // by this value after each profile run. parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:"); // Top K% of samples that are considered relevant when // deciding if the app should be recompiled. parseRuntimeOption("dalvik.vm.profile.top-k-thr", profileTopKThreshold, "-Xprofile-top-k-threshold:"); // The threshold after which a change in the structure of the // top K% profiled samples becomes significant and triggers // recompilation. A change in profile is considered // significant if X% (top-k-change-threshold) of the top K% // (top-k-threshold property) samples has changed. parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr", profileTopKChangeThreshold, "-Xprofile-top-k-change-threshold:"); // Type of profile data. parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:"); // Depth of bounded stack data parseRuntimeOption("dalvik.vm.profile.stack-depth", profileMaxStackDepth, "-Xprofile-max-stack-depth:"); // Native bridge library. "0" means that native bridge is disabled. property_get("ro.dalvik.vm.native.bridge", propBuf, ""); if (propBuf[0] == '\0') { ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty"); } else if (strcmp(propBuf, "0") != 0) { snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX, "-XX:NativeBridge=%s", propBuf); addOption(nativeBridgeLibrary); } } initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE; /* * Initialize the VM.创建java虚拟机对象。 * 执行成功后,虚拟机便准备就绪,这时候java世界就可以分发JNI调用了。 * 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: return result;}
根据代码可以看出startVM主要做了两部分工作:一是通过属性系统获取大量虚拟机配置信息,以此设置虚拟机参数;二是调用JNI_CreateJavaVM函数创建虚拟机实例。 虚拟机参数很多,可以通过adb命令查看:adb shell dalvikvm。
JNI_CreateJavaVM不再向下跟踪,可以参考:点击打开链接
2、注册JNI方法
上面我们分析了是如何创建Dalvik虚拟机的,下面我们接着分析start方法的第二步重要工作:注册Android核心类的JNI函数。这些函数是java世界调用native方法的基础,是连接java世界和C/C++世界的桥梁。
/* * 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.) */ 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;}
在startReg函数中首先调用了androidSetCerateThreadFunc函数,这个函数用来设置一个线程创建钩子javaCreateThreadEtc。这个线程创建钩子是用来干什么的呢?是用来初始化一个Native线程的JNI环境的,也就是说当我们在C++代码中创建一个Native线程的时候,会调用javaCreateThreadEtc函数来初始化该Native线程的JNI环境。
调用register_jni_procs函数来注册Android核心类的JNI方法。在注册JNI方法的过程中,需要在Native代码中引用到一些JAVA对象,这些Java对象引用需要记录在当前线程的一个Native堆栈中。但是此时Dalvik虚拟机还没有真正运行起来,也就是当前线程的Native堆栈还没有准备就绪。那么在这种情况下,Android是如何处理的呢?在注册JNI方法之前,调用JNIEnv对象的PushLocalFrame函数在当前线程的Native堆栈中压入一个帧(Frame),这个帧是一个本地帧,只是用来保存java对象在Native代码中的本地引用;并且在注册JNI方法之后,调用JNIEnv对象的PopLocalFrame函数将帧弹出堆栈。在本地函数的入口处调用PushLocalFrame,在函数返回前调用PopLocalFrame,这样在两个函数之间创建的局部引用都会有效管理和释放,也就高效管理了局部引用的生命周期。
startReg函数的关键是调用register_jni_procs函数注册JNI方法。
注意:在Android应用框架层有很多地方调用Native方法,这些方法的实现都借助于本地方法。这里便是注册Native方法的JNI实现方法,Android是采用注册方式实现Native方法和JNI方法的关联。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;}
从前面的调用过程可以知道 ,参数array指向的是全局变量gRegJNI所描述的一个JNI方法注册函数表,其中,每一个表项都用一个RegJNIRec对象来描述,而每一个RegJNIRec对象都有一个成员变量mProc,指向一个JNI方法注册函数。通过依次调用这些注册函数,就可以将Android核心类的JNI方法注册到前面的所创建的Dalvik虚拟机中去。 那么我们看一下RegJNIRec到底是什么呢,代码如下:
#ifdef NDEBUG #define REG_JNI(name) { name } /* 定义REG_JNI宏,宏以name为参数*/ struct RegJNIRec { /* 定义一个结构体RegJNIRec,结构体的元素是一个函数指针,参数类型是(JNIEnv*) */ int (*mProc)(JNIEnv*); };#else #define REG_JNI(name) { name, #name } struct RegJNIRec { int (*mProc)(JNIEnv*); const char* mName; };#endif
从代码中可以看出RegJNIRec是一个结构体,结构体的元素是一个函数指针。我们看一下gRegJNI描述的JNI方法注册函数表都注册了哪些Android核心类的JNI方法,代码如下:
static const RegJNIRec gRegJNI[] = { 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_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_StaticLayout), 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_nio_utils), REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_HardwareLayer), REG_JNI(register_android_view_ThreadedRenderer), 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_android_internal_view_animation_NativeInterpolatorFactoryHelper), 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_opengl_jni_GLES31), REG_JNI(register_android_opengl_jni_GLES31Ext), 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_CanvasProperty), REG_JNI(register_android_graphics_ColorFilter), REG_JNI(register_android_graphics_DrawFilter), REG_JNI(register_android_graphics_FontFamily), 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_graphics_pdf_PdfEditor), REG_JNI(register_android_graphics_pdf_PdfRenderer), 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_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_os_MemoryFile), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_os_Zygote), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement), REG_JNI(register_android_hardware_camera2_DngCreator), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_SoundTrigger), REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), REG_JNI(register_android_hardware_location_ActivityRecognitionHardware), 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_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,将函数名传递给结构体RegJNIRec的mProc函数指针。这些函数最终调用了jniRegisterNativeMethods方法注册JNI方法。
至此,JNI方法注册就分析到这里。
3、开启java世界
在AndroidRuntime的start方法中是通过CallStaticVoidMethod这个JNI函数调用ZygoteInit文件的main函数来开启java世界的。ZygoteInit文件位于frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,定位到main方法,代码如下:
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { socketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } registerZygoteSocket(socketName);/* 注册zygote服务所需的Socket,用来接收请求 */ EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload();/* 加载class资源和resource资源 */ 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();/* 强制gc */ // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); if (startSystemServer) { startSystemServer(abiList, socketName);/* 启动system_server */ } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket();/* zygote异常退出 */ throw ex; } }
ZygoteInit的main方法主要做了5部分工作: - 注册zygote的Socket;
- 预加载Class资源和Resource资源;
- 启动system_server;
- 执行runSelectLoop方法;
- 执行MethodAndArgsCaller的run方法,该方法将执行SystemServer的main函数。
三、Zygote开启java世界
1、注册Zygote的Socket
注册zygote服务所需要的Socket,是通过registerZygoteSocket函数来实现的,该函数绑定了zygote中的Socket,用于接收ActivityManagerService中启动应用程序的请求。
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
这里的socketName是在main函数中定义的“zygote”,因此fullSocketName为“ANDROID_SOCKET_zygote”,通过调用System.getenv(fullSocketName)函数,返回在系统环境变量值定义的变量的字符串值;最后根据对应的文件描述符生成一个LocalServerSocket对象,即zygote服务端的Socket,最终该Socket将与ActivityManagerService通信,是java世界启动新进程的通道。 2、预加载Class资源和Resource资源
在ZygoteInit的main方法中创建完Socket后,便进行预加载资源,这部分功能是通过preload函数完成的,在preload函数中封装了对preloadClasses()和preloadResource()等函数的调用。
static void preload() { Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); preloadSharedLibraries(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); Log.d(TAG, "end preload"); }
2.1、preloadClasses() 该函数用于加载preloaded-classes文件中指定的java类,代码如下:
/** * 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; try { is = new FileInputStream(PRELOADED_CLASSES); } catch (FileNotFoundException e) { Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + "."); return; } 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.使用VMRuntime的setTargetHeapUtilization函数可以增强程序堆内存的处理效率。 float defaultUtilization = runtime.getTargetHeapUtilization(); runtime.setTargetHeapUtilization(0.8f); // Start with a clean slate. System.gc(); runtime.runFinalizationSync(); Debug.startAllocCounting();//统计两点间的内存分配情况,使用Debug.startAllocCounting()、Debug.stopAllocCounting() 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 (UnsatisfiedLinkError e) { Log.w(TAG, "Problem preloading " + line + ": " + e); } 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); } }
其中,PRELOADED_CLASSES是被定义的全局变量“/system/etc/preloaded-classes”,这是一个文件,用来存放预加载的类;根据该文件的内容,我们可以得知函数中读取出来的line便是一个类,通过反射机制加载读取出来的类。preloaded-classes文件中有2000行以上,读取每一行并加载每一行指定的类需要花费较长的时间,这也是影响系统启动速度慢的原因。不过这些类预先加载到内存中,当新的应用程序启动时,可以共享这部分资源,这样便加快了应用程序启动和运行速度。 2.2、preloadResources()
preloadResources函数用于加载框架层定义的资源,代码如下:
/** * 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*/ mResources.startPreloading();/*设置初始状态,防止重复加载资源*/ if (PRELOAD_RESOURCES) {/*PRELOAD_RESOURCES设置在zygote初始化时是否加载Resource,初始值为true*/ 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); 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); 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共加载了两种资源:drawables和color。这些资源定义在frameworks/base/core/res/res/values/array.xml文件中,最终会被编译进frameworks-res.apk中。 3、启动system_server进程
ZygoteInit的main函数中加载完共享资源后,便开始启动system_server进程,该进程是理解框架层的基础。Android中所有的系统服务都是由该进程启动的,它的异常退出会直接导致zygote“自杀”,这样整个java世界便会崩溃。system_server进程的启动入口是startSystemServer,代码如下:
/** * Prepare the arguments and fork for the system server process. */ private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_BLOCK_SUSPEND, 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启动system_server的命令行参数 */ String args[] = { "--setuid=1000",/*设置用户ID为1000,即SYSTEM_UID,系统进程*/ "--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);/*将args数组分解成Arguments类型的对象*/ ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process.调用系统函数fork()创建子进程system_server */ pid = Zygote.forkSystemServer( 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) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } handleSystemServerProcess(parsedArgs);/*在子进程中调用handleSystemServerProcess*/ } return true;/*在父进程中返回*/ }
到这里zygote做了第一次分裂,fork出系统服务的总管system_server进程。这个过程分为以下两个重要的步骤:通过forkSystemServer创建system_server子进程;在子进程中调用handleSystemServerProcess方法。 3.1、调用forkSystemServer创建system_server子进程。
创建system_server的第一步便是调用Zygote类的forkSystemServer方法,该方法位于frameworks/base/core/java/com/android/internal/os/Zygote.java类中,在forkSystemServer方法中通过调用Native方法nativeForkSystemServer来完成启动system_server进程的任务。代码如下:
/** * 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) { VM_HOOKS.preFork(); int pid = nativeForkSystemServer( uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities); VM_HOOKS.postForkCommon(); return pid; }
native private 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中,函数名为Dalvik_dalvik_system_Zygote_forkSystemServer,代码如下: static void Dalvik_dalvik_system_Zygote_forkSystemServer( const u4* args, JValue* pResult) { pid_t pid; pid = forkAndSpecializeCommon(args, true); //启动system_server进程 /* 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; //在虚拟机中记录system_server进程的ID /* 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); }
该函数的功能主要分为两部分:一是启动system_server进程;二是监控system_server进程的启动结果。system_server进程的启动是由forkAndSpecializeCommon完成的,在forkAndSpecializeCommon函数中调用系统函数fork创建子进程,并且在创建前设置信号处理函数setSignalHandler(),在setSignalHandler方法中调用系统函数sigaction处理SIGCHLD信号(子进程退出信号),指定处理函数sigchldHandler,如果system_server出现异常,就会自杀。 3.2、在子进程中调用handleSystemServerProcess方法
system_server进程启动之后,便开始执行handleSystemServerProcess方法,代码如下:
/** * Finish remaining work for the newly forked system server process. */ private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller { closeServerSocket();//关闭fork时从zygote继承下来的socket // set umask to 0077 so new files and directories will default to owner-only permissions. Os.umask(S_IRWXG | S_IRWXO);//设置文件的默认权限 if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName);//system_server } final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); if (systemServerClasspath != null) { performSystemServerDexOpt(systemServerClasspath); } if (parsedArgs.invokeWith != null) { String[] args = parsedArgs.remainingArgs; // If we have a non-null system server class path, we'll have to duplicate the // existing arguments and append the classpath to it. ART will handle the classpath // correctly when we exec a new process. if (systemServerClasspath != null) { String[] amendedArgs = new String[args.length + 2]; amendedArgs[0] = "-cp"; amendedArgs[1] = systemServerClasspath; System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length); } WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, null, args); } else { ClassLoader cl = null; if (systemServerClasspath != null) { cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader()); Thread.currentThread().setContextClassLoader(cl); } /* * Pass the remaining arguments to SystemServer. */ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); } /* should never reach here */ }
在handleSystemServerProcess方法中做了一些清理和初始化工作,接着调用RuntimeInit.zygoteInit方法。
/** * 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. * * Current recognized args: *
* -
[--] *
* * @param targetSdkVersion target SDK version * @param argv arg strings */ public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit(); nativeZygoteInit(); applicationInit(targetSdkVersion, argv, classLoader); }
在zygoteInit方法中封装了四个方法的调用,对应四个步骤实现不同的初始化操作,分别介绍如下: 1)、redirectLogStreams方法重定向标准I/O操作,重定向到Android标准的日志系统。
/** * Redirect System.out and System.err to the Android log. */ public static void redirectLogStreams() { System.out.close(); System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.err.close(); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); }
2)、commonInit方法初始化一些通用设置
private static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());//设置未捕获异常的默认处理函数 /* * Install a TimezoneGetter subclass for ZoneInfo.db */ TimezoneGetter.setInstance(new TimezoneGetter() { @Override public String getId() { return SystemProperties.get("persist.sys.timezone"); } }); TimeZone.setDefault(null); /* * Sets handler for java.util.logging to use Android log facilities. * The odd "new instance-and-then-throw-away" is a mirror of how * the "java.util.logging.config.class" system property works. We * can't use the system property here since the logger has almost * certainly already been initialized. */ LogManager.getLogManager().reset();//Android log配置 new AndroidConfig(); /* * Sets the default HTTP User-Agent used by HttpURLConnection. */ String userAgent = getDefaultUserAgent(); System.setProperty("http.agent", userAgent); /* * Wire socket tagging to traffic stats. */ NetworkManagementSocketTagger.install(); /* * If we're running in an emulator launched with "-trace", put the * VM into emulator trace profiling mode so that the user can hit * F9/F10 at any time to capture traces. This has performance * consequences, so it's not something you want to do always. */ String trace = SystemProperties.get("ro.kernel.android.tracing"); if (trace.equals("1")) { Slog.i(TAG, "NOTE: emulator trace profiling enabled"); Debug.enableEmulatorTraceOutput(); } initialized = true; }
3)、nativeZygoteInit方法开启Binder通信 nativeZygoteInit是一个native方法,其JNI实现方法位于AndroidRuntime.cpp中,方法名为com_android_internal_os_RuntimeInit_nativiZygoteInit,代码如下:
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz){ gCurRuntime->onZygoteInit();}
这里调用onZygoteInit方法,这里onZygoteInit是一个虚函数,直接调用子类AppRuntime.onZygoteInit,代码位于frameworks/base/cmd/app_process/App_main.cpp中。
virtual void onZygoteInit() { // Re-enable tracing now that we're no longer in Zygote. atrace_set_tracing_enabled(true); sp proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool();//创建PoolThread对象,用于Binder通信 }
4)、invokeStaticMain方法抛出异常 applicationInit方法做了虚拟机设置,并转化了参数后,直接调用invokeStaticMain方法,这里直接分析invokeStaticMain,代码如下:
/** * 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() * @param classLoader the classLoader to load {@className} with */ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl; try { cl = Class.forName(className, true, classLoader);//利用java反射机制加载类信息,className是com.android.server.SystemServer } 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 });//加载SystemServer类的main函数 } 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();//利用java的反射机制,判断main函数的修饰符是否是static和public 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);//抛出异常 }
invokeStaticMain方法利用java的反射机制加载类的信息后,最后抛出一个MethodAndArgsCaller异常,那么在哪里进行的异常捕获呢? 4、执行MethodAndArgsCaller的run方法
在ZygoteInit的main方法中捕获了MethodAndArgsCaller异常,便执行run方法。
public static void main(String argv[]) { try { ...... registerZygoteSocket(socketName); ...... preload(); ...... if (startSystemServer) { startSystemServer(abiList, socketName); } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
分析下MethodAndArgsCaller类中都做了哪些事情。
/** * 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 });//利用java反射机制调用这个方法 } 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); } } }
MethodAndArgsCaller类既是一个异常类又是一个线程,异常处理代码中直接调用了这个线程的run方法,并执行了传入的com.android.server.SystemServer类的main方法。invokeStaticMain方法抛出异常的目的是执行com.android.server.SystemServer类的main方法,通过这种方式,可以直接从调用栈中跳出,并返回到ZygoteInit的main方法中。 system_server绕了一大圈执行了SystemServer的main方法,那么SystemServer又承担了什么使命呢?首先分析一下com.android.server.SystemServer类的main方法中做了哪些事情,代码位于:\frameworks\base\services\java\com\android\server\SystemServer.java,如下:
/** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); }
private void run() { // 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. if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } // Here we go! Slog.i(TAG, "Entered the Android system server!"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); // In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system // property so that it is in sync. We can't do this in // libnativehelper's JniInvocation::Init code where we already // had to fallback to a different runtime because it is // running as root and we need to be the system user to set // the property. http://b/11463182 SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary()); // Enable the sampling profiler. if (SamplingProfilerIntegration.isEnabled()) {//判断是否开启性能统计 SamplingProfilerIntegration.start();//启动性能统计 mProfilerSnapshotTimer = new Timer(); mProfilerSnapshotTimer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null);//结束统计并生成结果文件 } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // Mmmmmm... more memory!申请更多的内存 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); // Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty(); // Within the system server, it is an error to access Environment paths without // explicitly specifying a user. Environment.setUserRequired(true); // Ensure binder calls into the system always run at foreground priority. BinderInternal.disableBackgroundScheduling(true); // Prepare the main looper thread (this thread). android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper(); // Initialize native services.加载libandroid_servers.so库文件 System.loadLibrary("android_servers"); nativeInit(); // Check whether we failed to shut down last time we tried. // This call may not return. performPendingShutdown(); // Initialize the system context. createSystemContext(); // Create the system service manager. mSystemServiceManager = new SystemServiceManager(mSystemContext); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Start services. try { startBootstrapServices(); startCoreServices(); startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } // For debug builds, log event loop stalls to dropbox for analysis. if (StrictMode.conditionallyEnableDebugLogging()) { Slog.i(TAG, "Enabled StrictMode for system server main thread."); } // Loop forever. Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
nativeInit是本地方法,具体实现位于\frameworks\base\services\core\jni\com_android_server_SystemServer.cpp,只是启动Sensor Service。SensorService是C语言实现的系统服务,因此成为Native System Service。
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(); }}
更多相关文章
- Android在线更新SDK的方法(使用国内镜像)
- 详解Android应用开发中Intent的作用及使用方法
- 使用SourceInsight查看android中的native方法
- Android设置背景色为透明的两种方法
- [置顶] android软键盘弹出,会把原来的界面挤上去的问题 处理方法
- Android Button控件 的简单使用(button监听和onClick触发函数使用
- android 关于Location of the Android SDK has not been setup i