http://blog.csdn.net/xichangbao/article/details/53104810
一 app_process64Zygote所对应的可执行文件是/system/bin/app_process64 Zygote的代码路径frameworks/base/cmds/app_process
1.0 app_process64 init.rc中import /init.${ro.zygote}.rc,而ro.zygote=zygote64_32 init.zygote64_32 .rc的内容如下 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main socket zygote stream 660 root system // 套接字 名称 类型 权限 用户 组 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
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 writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
64位系统为了兼容32位应用程序,将同时启动zygote64和zygote,下面以zygote64为例分析。
1.1 app_process64的main函数 app_process64的入口函数是:app_main.cpp的main函数 参数是: -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote 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)); // 创建AppRuntime,android运行时环境 // Process command line arguments // ignore argv[0] argc--; // argv[0]等程序名称,不需要解析,因此跳过 argv++;
// 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] != '-') { // i=1时,argv[1]=/system/bin // 跳出for循环 break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); // 当i=0时,将-Xzygote加入到runtime的mOptions中 }
// 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. // 执行++i后i=2 while (i < argc) { // 解析启动参数 // /init.${ro.zygote}.rc文件中为zygote进程设置的启动参数是-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; // 对于64位系统nice_name为zygote64 } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { application = true; } else if (strncmp(arg, "--nice-name=", 12) == 0) { niceName.setTo(arg + 12); } else if (strncmp(arg, "--", 2) != 0) { className.setTo(arg); break; } else { --i; break; } }
// 从while循环出来后,i等于4,zygote为true,niceName为zygote64,startSystemServer为true,application为false,className为null
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")); runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { // Zygote // We're in zygote mode. maybeCreateDalvikCache(); // 创建/data/dalvik-cache
if (startSystemServer) { args.add(String8("start-system-server")); // 将start-system-server添加到args中 }
char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { // ro.product.cpu.abilist64=arm64-v8a 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); // --abi-list=arm64-v8a args.add(abiFlag); // 将--abi-list=arm64-v8a添加到args中
// In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); // 将--socket-name=zygote添加到args中 } }
if (!niceName.isEmpty()) { // 修改程序名称 runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); // 对Zygote而言就是将程序名称app_process64改为zygote64 }
// 调用AppRuntime的start方法
if (zygote) { // zygote InitializeNativeLoader(); // system/core/libnativeloader/native_loader.cpp runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 调用AndroidRuntime的start()方法 } else if (className) { // 普通应用程序 runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } 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_process64的main函数比较简单,注释也比较详细。
1.2 maybeCreateDalvikCache
static void maybeCreateDalvikCache() {#if defined(__aarch64__) static const char kInstructionSet[] = "arm64"; // 指令集arm64#elif defined(__x86_64__) static const char kInstructionSet[] = "x86_64";#elif defined(__arm__) static const char kInstructionSet[] = "arm";#elif defined(__i386__) static const char kInstructionSet[] = "x86";#elif defined (__mips__) && !defined(__LP64__) static const char kInstructionSet[] = "mips";#elif defined (__mips__) && defined(__LP64__) static const char kInstructionSet[] = "mips64";#else#error "Unknown instruction set"#endif const char* androidRoot = getenv("ANDROID_DATA"); // ANDROID_DATA=/data LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");
char dalvikCacheDir[PATH_MAX]; const int numChars = snprintf(dalvikCacheDir, PATH_MAX, "%s/dalvik-cache/%s", androidRoot, kInstructionSet); // dalvikCacheDir=/data/dalvik-cache/arm64 LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0), "Error constructing dalvik cache : %s", strerror(errno));
int result = mkdir(dalvikCacheDir, 0711); // 创建虚拟机的cache目录/data/dalvik-cache/arm64,权限0711 LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST), "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
// We always perform these steps because the directory might // already exist, with wider permissions and a different owner // than we'd like. result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT); // 改变/data/dalvik-cache/arm64的所有权,将owner和group都设为root LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));
result = chmod(dalvikCacheDir, 0711); // 设置权限0711 LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache permissions : %s", strerror(errno));}
1.3 InitializeNativeLoader
定义在system/core/libnativeloader/native_loader.cpp中 static std::mutex g_namespaces_mutex;static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
void InitializeNativeLoader() {#if defined(__ANDROID__) std::lock_guard<std::mutex> guard(g_namespaces_mutex); g_namespaces->Initialize();#endif}
二 AndroidRuntime
2.0 start
AndroidRuntime::start主要完成两项工作:1 启动虚拟机 ,2 调用className类的static void main(String args[])方法 定义在frameworks/base/core/jni/AndroidRuntime.cpp中 void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) // className为com.android.internal.os.ZygoteInit,options为start-system-server,--abi-list=arm64-v8a,--socket-name=zygote,zygote为true{ 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"); // 设置环境变量ANDROID_ROOT=/system 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); // 初始化jni接口 JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { // 启动虚拟机 return; } onVmCreated(env); // 空函数
/* * Register android functions. */ if (startReg(env) < 0) { // 注册JNI方法 ALOGE("Unable to register all android natives\n"); return; }
/* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr;
stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); // 新建对象数组 assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); // strArray[0] = "com.android.internal.os.ZygoteInit"
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); } // strArray[1] = "start-system-server",strArray[2] = "--abi-list=arm64-v8a",strArray[3] = "--socket-name=zygote" /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); // 将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit" jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); // 查找ZygoteInit类的main()方法 if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); // 调用ZygoteInit的main()方法,进入Java世界
#if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env);#endif } } free(slashClassName); // 释放slashClassName的内存空间
ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) // 取消线程与jvm关联 ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) // 销毁Java虚拟机并回收资源 ALOGW("Warning: VM did not shut down cleanly\n");}
2.1 startVm
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote){ JavaVMInitArgs initArgs; char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[sizeof("-Xstacktracefile:")-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 usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX]; char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX]; char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX]; char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX]; char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-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 cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + 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 dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; char dex2oat_isa_features[sizeof("--instruction-set-features=") -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 localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX]; char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX]; char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX]; char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX]; char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX]; char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX]; char fingerprintBuf[sizeof("-Xfingerprint:") + PROPERTY_VALUE_MAX];
bool checkJni = false; property_get("dalvik.vm.checkjni", propBuf, ""); // JNI检测功能,用于native层调用jni函数时进行常规检测 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 */ addOption("-Xcheck:jni");
/* with -Xcheck:jni, this provides a JNI function call trace */ //addOption("-verbose:jni"); }
property_get("dalvik.vm.execution-mode", propBuf, ""); if (strcmp(propBuf, "int:portable") == 0) { executionMode = kEMIntPortable; } else if (strcmp(propBuf, "int:fast") == 0) { executionMode = kEMIntFast; } else if (strcmp(propBuf, "int:jit") == 0) { executionMode = kEMJitCompiler; }
parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:"); // -Xstacktracefile:/data/anr/traces.txt // Java虚拟机接收到SIGQUIT(Ctrl-\或者kill -3)信号之后,会将所有线程的调用堆栈输出输出到/data/anr/traces.txt
strcpy(jniOptsBuf, "-Xjniopts:"); if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) { // JNI检测选项 ALOGI("JNI options: '%s'\n", jniOptsBuf); }
/* route exit() to our handler */ addOption("exit", (void*) runtime_exit); // 添加Java虚拟机选项,当Java虚拟机退出时执行runtime_exit方法
/* route fprintf() to our handler */ addOption("vfprintf", (void*) runtime_vfprintf); // 当Java虚拟机调用vfprintf时,调用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. */ parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); // 设置虚拟机的heapsize,默认为16M
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=");
/* * JIT related options. */ parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:"); parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:"); parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:"); parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:"); parseRuntimeOption("dalvik.vm.jitprithreadweight", jitprithreadweightOptBuf, "-Xjitprithreadweight:");
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 debugging only for apps forked from zygote. * Set suspend=y to pause during VM init and use android ADB transport. */ if (zygote) { addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y"); // }
parseRuntimeOption("dalvik.vm.lockprof.threshold", lockProfThresholdBuf, "-Xlockprofthreshold:");
if (executionMode == kEMIntPortable) { addOption("-Xint:portable"); } else if (executionMode == kEMIntFast) { addOption("-Xint:fast"); } else if (executionMode == kEMJitCompiler) { addOption("-Xint:jit"); }
// If we are 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)); return -1; } 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");
// We skip compilation when a minimal runtime is brought up for decryption. In that case // /data is temporarily backed by a tmpfs, which is usually small. // If the system image contains prebuilts, they will be relocated into the tmpfs. In this // specific situation it is acceptable to *not* relocate and run out of the prebuilts // directly instead. addOption("--runtime-arg"); addOption("-Xnorelocate"); } else { parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf, "--compiler-filter=", "-Xcompiler-option"); } parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option"); parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j", "-Ximage-compiler-option");
// The runtime will compile a boot image, when necessary, not using installd. Thus, we need to // pass the instruction-set-features/variant as an image-compiler-option. // TODO: Find a better way for the instruction-set.#if defined(__arm__) constexpr const char* instruction_set = "arm";#elif defined(__aarch64__) constexpr const char* instruction_set = "arm64";#elif defined(__mips__) && !defined(__LP64__) constexpr const char* instruction_set = "mips";#elif defined(__mips__) && defined(__LP64__) constexpr const char* instruction_set = "mips64";#elif defined(__i386__) constexpr const char* instruction_set = "x86";#elif defined(__x86_64__) constexpr const char* instruction_set = "x86_64";#else constexpr const char* instruction_set = "unknown";#endif // Note: it is OK to reuse the buffer, as the values are exactly the same between // * compiler-option, used for runtime compilation (DexClassLoader) // * image-compiler-option, used for boot-image compilation on device
// Copy the variant. sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Xcompiler-option"); // Copy the features. sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, "--instruction-set-features=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, "--instruction-set-features=", "-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(localeOption, "-Duser.locale="); const std::string locale = readLocale(); strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX); addOption(localeOption); }
// Trace files are stored in /data/misc/trace which is writable only in debug mode. property_get("ro.debuggable", propBuf, "0"); if (strcmp(propBuf, "1") == 0) { property_get("dalvik.vm.method-trace", propBuf, "false"); if (strcmp(propBuf, "true") == 0) { addOption("-Xmethod-trace"); parseRuntimeOption("dalvik.vm.method-trace-file", methodTraceFileBuf, "-Xmethod-trace-file:"); parseRuntimeOption("dalvik.vm.method-trace-file-siz", methodTraceFileSizeBuf, "-Xmethod-trace-file-size:"); property_get("dalvik.vm.method-trace-stream", propBuf, "false"); if (strcmp(propBuf, "true") == 0) { addOption("-Xmethod-trace-stream"); } } }
// 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); }
#if defined(__LP64__) const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";#else const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";#endif // defined(__LP64__) property_get(cpu_abilist_property_name, propBuf, ""); if (propBuf[0] == '\0') { ALOGE("%s is not expected to be empty", cpu_abilist_property_name); return -1; } snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf); addOption(cpuAbiListBuf); // ABI: arm64-v8a
// Dalvik-cache pruning counter. parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf, "-Xzygote-max-boot-retry=");
/* * When running with debug.generate-debug-info, add --generate-debug-info to * the compiler options so that the boot image, if it is compiled on device, * will include native debugging information. */ property_get("debug.generate-debug-info", propBuf, ""); if (strcmp(propBuf, "true") == 0) { addOption("-Xcompiler-option"); addOption("--generate-debug-info"); addOption("-Ximage-compiler-option"); addOption("--generate-debug-info"); }
/* * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will * contain the fingerprint and can be parsed. */ parseRuntimeOption("ro.build.fingerprint", fingerprintBuf, "-Xfingerprint:"); // 以上代码主要是在读取dalvik.vm.*属性然后设置Java虚拟机参数
initArgs.version = JNI_VERSION_1_4; initArgs.options = mOptions.editArray(); initArgs.nOptions = mOptions.size(); initArgs.ignoreUnrecognized = JNI_FALSE;
/* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { // 创建Java虚拟机 // 最终调用的是art/runtime/java_vm_ext.cc中的JNI_CreateJavaVM函数 ALOGE("JNI_CreateJavaVM failed\n"); return -1; }
return 0;}
// art/runtime/java_vm_ext.cc中的JNI_CreateJavaVM函数extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { ScopedTrace trace(__FUNCTION__); const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args); if (IsBadJniVersion(args->version)) { LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version; return JNI_EVERSION; } RuntimeOptions options; for (int i = 0; i < args->nOptions; ++i) { JavaVMOption* option = &args->options[i]; options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo)); } bool ignore_unrecognized = args->ignoreUnrecognized; if (!Runtime::Create(options, ignore_unrecognized)) { // 创建Runtime return JNI_ERR; } Runtime* runtime = Runtime::Current(); bool started = runtime->Start(); // Runtime::start() if (!started) { delete Thread::Current()->GetJniEnv(); delete runtime->GetJavaVM(); LOG(WARNING) << "CreateJavaVM failed"; return JNI_ERR; } *p_env = Thread::Current()->GetJniEnv(); *p_vm = runtime->GetJavaVM(); return JNI_OK;}
2.2 startReg
/*static*/ int AndroidRuntime::startReg(JNIEnv* env){ ATRACE_NAME("RegisterAndroidNatives"); /* * 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); // 设置线程创建方法为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); // 为200个局部引用创建堆栈
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { // 注册JNI函数,gRegJNI是一个全局数组,存放上百个需要注册的jni函数 env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); // 销毁堆栈
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;}
三 ZygoteInit
3.0 main
定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中 public static void main(String argv[]) { try { Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit"); // 开始Systrace追踪ZygoteInit RuntimeInit.enableDdms(); // 使能DDMS功能 // Dalvik Debug Monitor Service虚拟机调试服务 // 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]); } } // 从for循环出来后,startSystemServer为true,abiList为arm64-v8a,socketName为zygote
if (abiList == null) { throw new RuntimeException("No ABI list supplied."); }
registerZygoteSocket(socketName); // 注册zygote使用的socket Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload"); // 开始Systrace追踪ZygotePreload EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(); // 预加载类和资源 // 这里可以进行优化以提升开机速度 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); // 停止Systrace追踪ZygotePreload
// Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // 结束性能统计并生成结果文件,保存在/data/snapshots
// Do an initial gc to clean up after startup Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC"); // 开始Systrace追踪PostZygoteInitGC gcAndFinalize(); // 强制垃圾回收 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); // 停止Systrace追踪PostZygoteInitGC
Trace.traceEnd(Trace.TRACE_TAG_DALVIK); // 停止Systrace追踪ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); // 禁止Systrace追踪
// Zygote process unmounts root storage spaces. Zygote.nativeUnmountStorageOnInit(); // 空函数
if (startSystemServer) { startSystemServer(abiList, socketName); // 启动system_server进程 // 单独分析 }
Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); // Zygote无限循环等待创建进程的请求
closeServerSocket(); // 退出时关闭服务器端Socket } catch (MethodAndArgsCaller caller) { caller.run(); // 在system_serer进程中,以反射方式调用SystemServer类的main方法 } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; }}
3.1 registerZygoteSocket
private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; // 获取socket描述字符串 // ANDROID_SOCKET_zygote try { String env = System.getenv(fullSocketName); // 从环境变量中获取ANDROID_SOCKET_zygote fileDesc = Integer.parseInt(env); // 获取socket文件描述符 } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); }
try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); sServerSocket = new LocalServerSocket(fd); // 创建服务端Socket } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } }}
public LocalServerSocket(FileDescriptor fd) throws IOException{ impl = new LocalSocketImpl(fd); impl.listen(LISTEN_BACKLOG); localAddress = impl.getSockAddress();}
3.2 preload
static void preload() { Log.d(TAG, "begin preload"); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses"); preloadClasses(); // 预加载/system/etc/preloaded-classes文件中的类 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources"); preloadResources(); //预加载drawable和color资源 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL"); preloadOpenGL(); // 预加载OpenGL Trace.traceEnd(Trace.TRACE_TAG_DALVIK); preloadSharedLibraries(); // 预加载"android","compiler_rt","jnigraphics"共享库 preloadTextResources(); //预加载text资源 // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); // 预加载WebView库 Log.d(TAG, "end preload");}
3.3 gcAndFinalize
/*package*/ static void gcAndFinalize() { final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote, * which doesn't have a HeapWorker thread. */ System.gc(); runtime.runFinalizationSync(); System.gc();}
3.4 runSelectLoop
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor()); // sServerSocket就是之前registerZygoteSocket建立的服务器端Socket peers.add(null);
while (true) { // 循环等待请求 StructPollfd[] pollFds = new StructPollfd[fds.size()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); pollFds[i].events = (short) POLLIN; // POLLIN表示有数据可读 } try { Os.poll(pollFds, -1); // 监视pollFds中的文件描述符 } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } for (int i = pollFds.length - 1; i >= 0; --i) { if ((pollFds[i].revents & POLLIN) == 0) { // 判断是否有数据可读 continue; } if (i == 0) { // i等于0时,建立连接 ZygoteConnection newPeer = acceptCommandPeer(abiList); // 接受新的socket连接并创建一个ZygoteConnection peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); // 将socket连接的文件描述符添加到fds,再下一个while循环开始监视 } else { // i不等于0时,接收数据,并处理 boolean done = peers.get(i).runOnce(); // 调用对应ZygoteConnection的runOnce if (done) { peers.remove(i); fds.remove(i); } } } }}
3.5 closeServerSocket
static void closeServerSocket() { try { if (sServerSocket != null) { FileDescriptor fd = sServerSocket.getFileDescriptor(); sServerSocket.close(); if (fd != null) { Os.close(fd); } } } catch (IOException ex) { Log.e(TAG, "Zygote: error closing sockets", ex); } catch (ErrnoException ex) { Log.e(TAG, "Zygote: error closing descriptor", ex); }
sServerSocket = null;}
以下内容摘录自《深入理解 Android 卷I》关于 Zygote的总结 Zygote是创建Android系统中Java世界的盘古,它创建了第一个Java虚拟机,同时它又是女娲,它成功地繁殖了framework的核心system_server进程。做为Java语言的受益者,我们理应回顾一下Zygote创建Java世界的步骤: · 第一天:创建AppRuntime对象,并调用它的start。此后的活动则由AppRuntime来控制。 · 第二天:调用startVm创建Java虚拟机,然后调用startReg来注册JNI函数。 · 第三天:通过JNI调用com.android.internal.os.ZygoteInit类的main函数,从此进入了Java世界。然而在这个世界刚开创的时候,什么东西都没有。 · 第四天:调用registerZygoteSocket。通过这个函数,它可以响应子孙后代的请求。同时Zygote调用preloadClasses和preloadResources,为Java世界添砖加瓦。 · 第五天:Zygote觉得自己工作压力太大,便通过调用startSystemServer分裂一个子进程system_server来为Java世界服务。 · 第六天:Zygote完成了Java世界的初创工作,它已经很满足了。下一步该做的就是调用runSelectLoopMode后,便沉沉地睡去了。 · 以后的日子:Zygote随时守护在我们的周围,当接收到子孙后代的请求时,它会随时醒来,为它们工作。
如果让我来做对比,我更愿意将Init比作盘古,Zygote比作女娲,SystemServer比作伏羲。