一、第一个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<String8> 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<String8>& 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 (<span style="color:#3333ff;">startVm</span>(&mJavaVM, &env) != 0) {return;}/* 开启虚拟机后执行的工作,这里是空函数体,什么都没做。运行时实际调用的是AppRuntime的onVmCreated函数,保存了类的全局引用。*/onVmCreated(env);/** Register android functions.注册Android JNI函数*/if (<span style="color:#3333ff;">startReg</span>(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-><span style="color:#3333ff;">CallStaticVoidMethod</span>(startClass, startMeth, strArray);#if 0if (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 dataparseRuntimeOption("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++世界的桥梁。
<span style="font-size:12px;">/** 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;
}</span>
在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 NDEBUGALOGD("----------!!! %s failed to load\n", array[i].mName);
#endifreturn -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 startupgc();/* 强制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.<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, 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() {@Overridepublic 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<ProcessState> 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和publicif (! (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 Exceptionimplements 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/11463182SystemProperties.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() {@Overridepublic 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 serviceSensorService::instantiate();}
}