Bootstrap

Android13 Zygote源码解析

源码地址参考:Search (aospxref.com)

一. 简介

Zygote 是 Android 系统中的一个关键进程,由init进程通过解析init.zygotexx.rc文件而创建的,所对应的可执行程序app_process,用于启动所有应用程序进程。它通过预加载常见的类和资源,在启动新的应用时通过进程复制(fork)快速创建新的进程,所对应的源文件是App_main.cpp,进程名为zygote。

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
     onrestart restart audioserver
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart media.tuner
     onrestart restart netd
     onrestart restart wificond
     task_profiles ProcessCapacityHigh
     critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

二、Zygote启动过程

2.1 App_main.main

int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }
    /传到的参数argv为“-Xzygote /system/bin --zygote --start-system-server”
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
	//忽略第一个参数
    argc--;
    argv++;

    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        ALOGV("app_process main add option '%s'", 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 = true;
			//对于64位系统nice_name为zygote64; 32位系统为zygote
            niceName = ZYGOTE_NICE_NAME;
        } 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;
        }
    }

    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);

        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } 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(), true /* setProcName */);
    }

    if (zygote) {
		// 启动AppRuntime 【见小节2.2】
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } 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.");
    }
}

2.2 AndroidRuntime.start

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
    bool primary_zygote = false;

    /*
     * '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) {
            primary_zygote = true;
           /* 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 /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
  	// 虚拟机创建
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
	 // JNI方法注册
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;
	//等价 strArray= new String[options.size() + 1];
    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);

    for (size_t i = 0; i < options.size(); ++i) {
		//等价 strArray[0] = "com.android.internal.os.ZygoteInit"
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    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");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            // 调用ZygoteInit.main()方法【见3.1小节】
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
	//释放相应对象的内存空间
    free(slashClassName);

    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");
}

2.3 AndroidRuntime.startVm

创建Java虚拟机方法的主要篇幅是关于虚拟机参数的设置

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)

   JavaVMInitArgs initArgs;
   char propBuf[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 jitpthreadpriorityOptsBuf[sizeof("-Xjitpthreadpriority:")-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 useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
   char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
   char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
   char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
   char saveResolvedClassesDelayMsOptsBuf[
           sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
   char profileMinSavePeriodOptsBuf[sizeof("-Xps-min-save-period-ms:")-1 + PROPERTY_VALUE_MAX];
   char profileMinFirstSaveOptsBuf[
           sizeof("-Xps-min-first-save-ms:")-1 + PROPERTY_VALUE_MAX];
   char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
   char madviseWillNeedFileSizeVdex[
           sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];
   char madviseWillNeedFileSizeOdex[
           sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX];
   char madviseWillNeedFileSizeArt[
           sizeof("-XMadviseWillNeedArtFileSize:")-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 foregroundHeapGrowthMultiplierOptsBuf[
           sizeof("-XX:ForegroundHeapGrowthMultiplier=")-1 + PROPERTY_VALUE_MAX];
   char finalizerTimeoutMsOptsBuf[sizeof("-XX:FinalizerTimeoutMs=")-1 + PROPERTY_VALUE_MAX];
   char threadSuspendTimeoutOptsBuf[sizeof("-XX:ThreadSuspendTimeout=")-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 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 dex2oatCpuSetBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX];
   char dex2oatCpuSetImageBuf[sizeof("--cpu-set=")-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];
   char perfettoHprofOptBuf[sizeof("-XX:PerfettoHprof=") + PROPERTY_VALUE_MAX];
   char perfettoJavaHeapStackOptBuf[
           sizeof("-XX:PerfettoJavaHeapStackProf=") + 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 corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX];
   char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
   char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
   std::string fingerprintBuf;
   char javaZygoteForkLoopBuf[sizeof("-XX:ForceJavaZygoteForkLoop=") + PROPERTY_VALUE_MAX];
   char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
   char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX];
   char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];

   // Read if we are using the profile configuration, do this at the start since the last ART args
   // take precedence.
   property_get("dalvik.vm.profilebootclasspath", propBuf, "");
   std::string profile_boot_class_path_flag = propBuf;
   // Empty means the property is unset and we should default to the phenotype property.
   // The possible values are {"true", "false", ""}
   if (profile_boot_class_path_flag.empty()) {
       profile_boot_class_path_flag = server_configurable_flags::GetServerConfigurableFlag(
               RUNTIME_NATIVE_BOOT_NAMESPACE,
               PROFILE_BOOT_CLASS_PATH,
               /*default_value=*/ "");
   }
   const bool profile_boot_class_path = (profile_boot_class_path_flag == "true");
   if (profile_boot_class_path) {
       addOption("-Xcompiler-option");
       addOption("--count-hotness-in-compiled-code");
       addOption("-Xps-profile-boot-class-path");
       addOption("-Xps-profile-aot-code");
       addOption("-Xjitsaveprofilinginfo");
   }

   std::string use_jitzygote_image_flag =
           server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                                ENABLE_JITZYGOTE_IMAGE,
                                                                /*default_value=*/"");
   // Use the APEX boot image for boot class path profiling to get JIT samples on BCP methods.
   // Also use the APEX boot image if it's explicitly enabled via configuration flag.
   const bool use_apex_image = profile_boot_class_path || (use_jitzygote_image_flag == "true");
   if (use_apex_image) {
       ALOGI("Using JIT Zygote image: '%s'\n", kJitZygoteImageOption);
       addOption(kJitZygoteImageOption);
   } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
       ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf);
   } else {
       ALOGI("Using default boot image");
   }

   std::string disable_lock_profiling =
       server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                            DISABLE_LOCK_PROFILING,
                                                            /*default_value=*/ "");
   if (disable_lock_profiling == "true") {
       addOption(kLockProfThresholdRuntimeOption);
       ALOGI("Disabling lock profiling: '%s'\n", kLockProfThresholdRuntimeOption);
   } else {
       ALOGI("Leaving lock profiling enabled");
   }

   const bool checkJni = GetBoolProperty("dalvik.vm.checkjni", false);
   if (checkJni) {
       ALOGD("CheckJNI is ON");

       /* extended JNI checking */
       addOption("-Xcheck:jni");

       /* with -Xcheck:jni, this provides a JNI function call trace */
       //addOption("-verbose:jni");
   }

   const bool odsignVerificationSuccess = GetBoolProperty("odsign.verification.success", false);
   if (!odsignVerificationSuccess) {
       addOption("-Xdeny-art-apex-data-files");
   }

   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;
   }

   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");

   // On Android, we always want to allow loading the PerfettoHprof plugin.
   // Even with this option set, we will still only actually load the plugin
   // if we are on a userdebug build or the app is debuggable or profileable.
   // This is enforced in art/runtime/runtime.cc.
   //
   // We want to be able to disable this, because this does not work on host,
   // and we do not want to enable it in tests.
   parseRuntimeOption("dalvik.vm.perfetto_hprof", perfettoHprofOptBuf, "-XX:PerfettoHprof=",
                      "true");

   // Enable PerfettoJavaHeapStackProf in the zygote
   parseRuntimeOption("dalvik.vm.perfetto_javaheap", perfettoJavaHeapStackOptBuf,
                      "-XX:PerfettoJavaHeapStackProf=", "true");

   if (primary_zygote) {
       addOption("-Xprimaryzygote");
   }

   /*
    * 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");

   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=");

   /* Foreground heap growth multiplier option */
   parseRuntimeOption("dalvik.vm.foreground-heap-growth-multiplier",
                      foregroundHeapGrowthMultiplierOptsBuf,
                      "-XX:ForegroundHeapGrowthMultiplier=");
   /*
    * Finalizer and thread suspend timeouts.
    */
   parseRuntimeOption("dalvik.vm.finalizer-timeout-ms",
                      finalizerTimeoutMsOptsBuf,
                      "-XX:FinalizerTimeoutMs=");
   parseRuntimeOption("dalvik.vm.thread-suspend-timeout-ms",
                      threadSuspendTimeoutOptsBuf,
                      "-XX:ThreadSuspendTimeout=");
   /*
    * 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.jitpthreadpriority",
                      jitpthreadpriorityOptsBuf,
                      "-Xjitpthreadpriority:");
   property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
   if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
       addOption("-Xjitsaveprofilinginfo");
   }

   parseRuntimeOption("dalvik.vm.jitprithreadweight",
                      jitprithreadweightOptBuf,
                      "-Xjitprithreadweight:");

   parseRuntimeOption("dalvik.vm.jittransitionweight",
                      jittransitionweightOptBuf,
                      "-Xjittransitionweight:");
   /*
    * Madvise related options.
    */
   parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");

   /*
    * Use default platform configuration as limits for madvising,
    * when no properties are specified.
    */
   parseRuntimeOption("dalvik.vm.madvise.vdexfile.size",
                      madviseWillNeedFileSizeVdex,
                      "-XMadviseWillNeedVdexFileSize:");

   parseRuntimeOption("dalvik.vm.madvise.odexfile.size",
                      madviseWillNeedFileSizeOdex,
                      "-XMadviseWillNeedOdexFileSize:");

   parseRuntimeOption("dalvik.vm.madvise.artfile.size",
                      madviseWillNeedFileSizeArt,
                      "-XMadviseWillNeedArtFileSize:");

   /*
    * Profile related options.
    */
   parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
           "-Xps-hot-startup-method-samples:");

   parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf,
           "-Xps-save-resolved-classes-delay-ms:");

   parseRuntimeOption("dalvik.vm.ps-min-save-period-ms", profileMinSavePeriodOptsBuf,
           "-Xps-min-save-period-ms:");

   parseRuntimeOption("dalvik.vm.ps-min-first-save-ms", profileMinFirstSaveOptsBuf,
           "-Xps-min-first-save-ms:");

   property_get("ro.config.low_ram", propBuf, "");
   if (strcmp(propBuf, "true") == 0) {
     addOption("-XX:LowMemoryMode");
   }

   /*
    * Garbage-collection related options.
    */
   parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");

   // If it set, honor the "enable_generational_cc" device configuration;
   // otherwise, let the runtime use its default behavior.
   std::string enable_generational_cc =
       server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
                                                            ENABLE_GENERATIONAL_CC,
                                                            /*default_value=*/ "");
   if (enable_generational_cc == "true") {
       addOption(kGenerationalCCRuntimeOption);
   } else if (enable_generational_cc == "false") {
       addOption(kNoGenerationalCCRuntimeOption);
   }

   parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");

   /*
    * Enable/disable zygote native fork loop.
    */
   parseRuntimeOption("dalvik.vm.force-java-zygote-fork-loop",
                      javaZygoteForkLoopBuf,
                      "-XX:ForceJavaZygoteForkLoop=");

   /*
    * Enable debugging only for apps forked from zygote.
    */
   if (zygote) {
     // Set the JDWP provider and required arguments. By default let the runtime choose how JDWP is
     // implemented. When this is not set the runtime defaults to not allowing JDWP.
     addOption("-XjdwpOptions:suspend=n,server=y");
     parseRuntimeOption("dalvik.vm.jdwp-provider",
                        jdwpProviderBuf,
                        "-XjdwpProvider:",
                        "default");
   }

   // Only pass an explicit opaque-jni-ids to apps forked from zygote
   if (zygote) {
     parseRuntimeOption("dalvik.vm.opaque-jni-ids",
                       opaqueJniIds,
                       "-Xopaque-jni-ids:",
                       "swapable");
   }

   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 JIT.
   if (skip_compilation) {
       addOption("-Xcompiler-option");
       addOption("--compiler-filter=assume-verified");
   } else {
       parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
                           "--compiler-filter=", "-Xcompiler-option");
   }
   parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
   parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=",
                       "-Xcompiler-option");

   // Copy the variant.
   sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING);
   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", ABI_STRING);
   parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                       "--instruction-set-features=", "-Xcompiler-option");

   /*
    * When running with debug.generate-debug-info, add --generate-debug-info to the compiler
    * options so that both JITted code and the boot image, if it is compiled on device, will
    * include native debugging information.
    */
   property_get("debug.generate-debug-info", propBuf, "");
   bool generate_debug_info = (strcmp(propBuf, "true") == 0);
   if (generate_debug_info) {
       addOption("-Xcompiler-option");
       addOption("--generate-debug-info");
   }

   // The mini-debug-info makes it possible to backtrace through compiled code.
    bool generate_mini_debug_info = property_get_bool("dalvik.vm.minidebuginfo", 0);
    if (generate_mini_debug_info) {
        addOption("-Xcompiler-option");
        addOption("--generate-mini-debug-info");
    }

    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);

    // Extra options for boot image generation.
    if (skip_compilation) {
        addOption("-Xnoimage-dex2oat");
    } else {
        parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
                                   "-Xms", "-Ximage-compiler-option");
        parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
                                   "-Xmx", "-Ximage-compiler-option");

        parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                            "--compiler-filter=", "-Ximage-compiler-option");

        // If there is a dirty-image-objects file, push it.
        if (hasFile("/system/etc/dirty-image-objects")) {
            addOption("-Ximage-compiler-option");
            addOption("--dirty-image-objects=/system/etc/dirty-image-objects");
        }

        parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
                            "-Ximage-compiler-option");
        parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
                            "-Ximage-compiler-option");

        // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
        // to pass the instruction-set-features/variant as an image-compiler-option.
        // 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
        parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
                            "--instruction-set-variant=", "-Ximage-compiler-option");
        parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
                            "--instruction-set-features=", "-Ximage-compiler-option");

        if (generate_debug_info) {
            addOption("-Ximage-compiler-option");
            addOption("--generate-debug-info");
        }

        if (generate_mini_debug_info) {
            addOption("-Ximage-compiler-option");
            addOption("--generate-mini-debug-info");
        }

        property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
        parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
    }

    /* 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.
    //
    // Note: bridging is only enabled for the zygote. Other runs of
    //       app_process may not have the permissions to mount etc.
    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 (zygote && 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);

    // Dalvik-cache pruning counter.
    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
                       "-Xzygote-max-boot-retry=");

    // If set, the property below can be used to enable core platform API violation reporting.
    property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, "");
    if (propBuf[0] != '\0') {
      snprintf(corePlatformApiPolicyBuf,
               sizeof(corePlatformApiPolicyBuf),
               "-Xcore-platform-api-policy:%s",
               propBuf);
      addOption(corePlatformApiPolicyBuf);
    }

    /*
     * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
     * contain the fingerprint and can be parsed.
     * Fingerprints are potentially longer than PROPERTY_VALUE_MAX, so parseRuntimeOption() cannot
     * be used here.
     * Do not ever re-assign fingerprintBuf as its c_str() value is stored in mOptions.
     */
    std::string fingerprint = GetProperty("ro.build.fingerprint", "");
    if (!fingerprint.empty()) {
        fingerprintBuf = "-Xfingerprint:" + fingerprint;
        addOption(fingerprintBuf.c_str());
    }

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

2.4 AndroidRuntime.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.)
     */
    //设置线程创建方法为javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
    env->PushLocalFrame(200);
    //进程NI方法的注册
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}

三. 进入Java层

前面2.2,AndroidRuntime.start()执行到最后通过反射调用到ZygoteInit.main(),解析如下:

3.1 ZygoteInit.main

pubilc static void main(String[] argv) {
    ZygoteServer zygoteServer = null;

    // Mark zygote start. This ensures that thread creation will throw
    // an error.
    ZygoteHooks.startZygoteNoThreadCreation();

    // Zygote goes into its own process group.
    try {
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }

    Runnable caller;
    try {
        // Store now for StatsLogging later.
        final long startTime = SystemClock.elapsedRealtime();
        final boolean isRuntimeRestarted = "1".equals(
                SystemProperties.get("sys.boot_completed"));

        String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
        TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                Trace.TRACE_TAG_DALVIK);
        bootTimingsTraceLog.traceBegin("ZygoteInit");
        RuntimeInit.preForkInit();

        boolean startSystemServer = false;
        String zygoteSocketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = 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)) {
                zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
        if (!isRuntimeRestarted) {
            if (isPrimaryZygote) {
                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                        BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                        startTime);
            } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                        BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                        startTime);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }

        // In some configurations, we avoid preloading resources and classes eagerly.
        // In such cases, we will preload things prior to our first fork.
        if (!enableLazyPreload) {
            bootTimingsTraceLog.traceBegin("ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
			// 预加载类和资源,开机阶段Zygote主要这里耗时较长		
            preload(bootTimingsTraceLog);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
            bootTimingsTraceLog.traceEnd(); // ZygotePreload
        }

        // Do an initial gc to clean up after startup
        bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
		    //GC操作
        gcAndFinalize();
        bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

        bootTimingsTraceLog.traceEnd(); // ZygoteInit

        Zygote.initNativeState(isPrimaryZygote);

        ZygoteHooks.stopZygoteNoThreadCreation();

        zygoteServer = new ZygoteServer(isPrimaryZygote);
		//如果startSystemServer为true,通过forkSystemServer启动system_server,【见3.3小节】
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

            // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
            // child (system_server) process.
            if (r != null) {
                r.run();
                return;
            }
        }

        Log.i(TAG, "Accepting command socket connections");

        // The select loop returns early in the child process after a fork and
        // loops forever in the zygote.
		//进入循环模式[见3.4小节]
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with fatal exception", ex);
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }

    // We're in the child process and have exited the select loop. Proceed to execute the
    // command.
    if (caller != null) {
        caller.run();//启动system_server中会讲到。
    }
}

3.2 ZygoteInit.preload

ZygoteInit.java

static void preload() {
    //预加载位于/system/etc/preloaded-classes文件中的类
    preloadClasses();

    //预加载资源,包含drawable和color资源
    preloadResources();

    //预加载OpenGL
    preloadOpenGL();

    //通过System.loadLibrary()方法,
    //预加载"android","compiler_rt","jnigraphics"这3个共享库
    preloadSharedLibraries();

    //预加载 文本连接符资源
    preloadTextResources();

    //仅用于zygote进程,用于内存共享的进程
    WebViewFactory.prepareWebViewInZygote();
}
static void preload(TimingsTraceLog bootTimingsTraceLog) {
    Log.d(TAG, "begin preload");
    bootTimingsTraceLog.traceBegin("BeginPreload");
    beginPreload();
    bootTimingsTraceLog.traceEnd(); // BeginPreload
    bootTimingsTraceLog.traceBegin("PreloadClasses");
    //预加载位于/system/etc/preloaded-classes文件中的类,耗时较长
    preloadClasses();
    bootTimingsTraceLog.traceEnd(); // PreloadClasses
    bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
    cacheNonBootClasspathClassLoaders();
    bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
    bootTimingsTraceLog.traceBegin("PreloadResources");
    //预加载资源,包含drawable和color资源
    preloadResources();
    bootTimingsTraceLog.traceEnd(); // PreloadResources
    Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
    nativePreloadAppProcessHALs();
    Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
    maybePreloadGraphicsDriver();
    Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    //预加载"android","compiler_rt","jnigraphics"这3个共享库
    preloadSharedLibraries();
    //预加载 文本连接符资源
    preloadTextResources();
    // Ask the WebViewFactory to do any initialization that must run in the zygote process,
    // for memory sharing purposes.
    WebViewFactory.prepareWebViewInZygote();
    endPreload();
    warmUpJcaProviders();
    Log.d(TAG, "end preload");

    sPreloadComplete = true;
}
165  

执行Zygote进程的初始化,对于类加载,采用反射机制Class.forName()方法来加载。对于资源加载,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的。

3.3 ZygoteInit.forkSystemServer

private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_IPC_LOCK,
            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_PTRACE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG,
            OsConstants.CAP_WAKE_ALARM,
            OsConstants.CAP_BLOCK_SUSPEND
    );
    /* Containers run without some capabilities, so drop any caps that are not available. */
    StructCapUserHeader header = new StructCapUserHeader(
            OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
    StructCapUserData[] data;
    try {
        data = Os.capget(header);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to capget()", ex);
    }
    capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);

    /* Hardcoded command line to start the system server */
	//准备参数
    String[] args = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                    + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
    };
    ZygoteArguments parsedArgs;

    int pid;

    try {
        ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
        try {
            parsedArgs = ZygoteArguments.getInstance(commandBuffer);
        } catch (EOFException e) {
            throw new AssertionError("Unexpected argument error for forking system server", e);
        }
        commandBuffer.close();
        Zygote.applyDebuggerSystemProperty(parsedArgs);
        Zygote.applyInvokeWithSystemProperty(parsedArgs);

        if (Zygote.nativeSupportsMemoryTagging()) {
            String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
            if (mode.isEmpty()) {
              /* The system server has ASYNC MTE by default, in order to allow
               * system services to specify their own MTE level later, as you
               * can't re-enable MTE once it's disabled. */
              mode = SystemProperties.get("persist.arm64.memtag.default", "async");
            }
            if (mode.equals("async")) {
                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
            } else if (mode.equals("sync")) {
                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
            } else if (!mode.equals("off")) {
                /* When we have an invalid memory tag level, keep the current level. */
                parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
                Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
            }
        } else if (Zygote.nativeSupportsTaggedPointers()) {
            /* Enable pointer tagging in the system server. Hardware support for this is present
             * in all ARMv8 CPUs. */
            parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
        }

        /* Enable gwp-asan on the system server with a small probability. This is the same
         * policy as applied to native processes and system apps. */
        parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;

        if (shouldProfileSystemServer()) {
            parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
        }

        /* Request to fork the system server process */
		// fork子进程,用于运行system_server
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid, parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
	//进入子进程system_server
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        zygoteServer.closeServerSocket();
		// 完成system_server进程剩余的工作
        return handleSystemServerProcess(parsedArgs);
    }

    return null;
}

准备参数并fork新进程,从上面可以看出system server进程参数信息为uid=1000,gid=1000,进程名为sytem_server,从zygote进程fork新进程后,需要关闭zygote原有的socket。另外,对于有两个zygote进程情况,需等待第2个zygote创建完成。

3.4 ZygoteServer.runSelectLoop

Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
        ArrayList<ZygoteConnection> peers = new ArrayList<>();
		//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
        socketFDs.add(mZygoteSocket.getFileDescriptor());
        peers.add(null);

        mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;

        while (true) {
            fetchUsapPoolPolicyPropsWithMinInterval();
            mUsapPoolRefillAction = UsapPoolRefillAction.NONE;

            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs;

            // Allocate enough space for the poll structs, taking into account
            // the state of the USAP pool for this Zygote (could be a
            // regular Zygote, a WebView Zygote, or an AppZygote).
            if (mUsapPoolEnabled) {
                usapPipeFDs = Zygote.getUsapPipeFDs();
                pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
            } else {
                pollFDs = new StructPollfd[socketFDs.size()];
            }

            /*
             * For reasons of correctness the USAP pool pipe and event FDs
             * must be processed before the session and server sockets.  This
             * is to ensure that the USAP pool accounting information is
             * accurate when handling other requests like API deny list
             * exemptions.
             */

            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;
            }

            final int usapPoolEventFDIndex = pollIndex;

            if (mUsapPoolEnabled) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = mUsapPoolEventFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;

                // The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
                assert usapPipeFDs != null;
                for (int usapPipeFD : usapPipeFDs) {
                    FileDescriptor managedFd = new FileDescriptor();
                    managedFd.setInt$(usapPipeFD);

                    pollFDs[pollIndex] = new StructPollfd();
                    pollFDs[pollIndex].fd = managedFd;
                    pollFDs[pollIndex].events = (short) POLLIN;
                    ++pollIndex;
                }
            }

            int pollTimeoutMs;

            if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
                pollTimeoutMs = -1;
            } else {
                long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;

                if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
                    // The refill delay has elapsed during the period between poll invocations.
                    // We will now check for any currently ready file descriptors before refilling
                    // the USAP pool.
                    pollTimeoutMs = 0;
                    mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                    mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

                } else if (elapsedTimeMs <= 0) {
                    // This can occur if the clock used by currentTimeMillis is reset, which is
                    // possible because it is not guaranteed to be monotonic.  Because we can't tell
                    // how far back the clock was set the best way to recover is to simply re-start
                    // the respawn delay countdown.
                    pollTimeoutMs = mUsapPoolRefillDelayMs;

                } else {
                    pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
                }
            }

            int pollReturnValue;
            try {
				//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
                pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            if (pollReturnValue == 0) {
                // The poll returned zero results either when the timeout value has been exceeded
                // or when a non-blocking poll is issued and no FDs are ready.  In either case it
                // is time to refill the pool.  This will result in a duplicate assignment when
                // the non-blocking poll returns zero results, but it avoids an additional
                // conditional in the else branch.
                mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

            } else {
                boolean usapPoolFDRead = false;
				//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
				// 否则进入continue,跳出本次循环。
                while (--pollIndex >= 0) {
                    if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                        continue;
                    }

                    if (pollIndex == 0) {
                        // Zygote server socket
						//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
						// 则创建ZygoteConnection对象,并添加到fds。
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        socketFDs.add(newPeer.getFileDescriptor());
                    } else if (pollIndex < usapPoolEventFDIndex) {
                        // Session socket accepted from the Zygote server socket

                        try {
                            ZygoteConnection connection = peers.get(pollIndex);
                            boolean multipleForksOK = !isUsapPoolEnabled()
                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                            //【见3.5小节】
                            final Runnable command =
                                    connection.processCommand(this, multipleForksOK);

                            // TODO (chriswailes): Is this extra check necessary?
                            if (mIsForkChild) {
                                // We're in the child. We should always have a command to run at
                                // this stage if processCommand hasn't called "exec".
                                if (command == null) {
                                    throw new IllegalStateException("command == null");
                                }

                                return command;
                            } else {
                                // We're in the server - we should never have any commands to run.
                                if (command != null) {
                                    throw new IllegalStateException("command != null");
                                }

                                // We don't know whether the remote side of the socket was closed or
                                // not until we attempt to read from it from processCommand. This
                                // shows up as a regular POLLIN event in our regular processing
                                // loop.
                                if (connection.isClosedByPeer()) {
                                    connection.closeSocket();
                                    peers.remove(pollIndex);
                                    socketFDs.remove(pollIndex);
                                }
                            }
                        } catch (Exception e) {
                            if (!mIsForkChild) {
                                // We're in the server so any exception here is one that has taken
                                // place pre-fork while processing commands or reading / writing
                                // from the control socket. Make a loud noise about any such
                                // exceptions so that we know exactly what failed and why.

                                Slog.e(TAG, "Exception executing zygote command: ", e);

                                // Make sure the socket is closed so that the other end knows
                                // immediately that something has gone wrong and doesn't time out
                                // waiting for a response.
                                ZygoteConnection conn = peers.remove(pollIndex);
                                conn.closeSocket();

                                socketFDs.remove(pollIndex);
                            } else {
                                // We're in the child so any exception caught here has happened post
                                // fork and before we execute ActivityThread.main (or any other
                                // main() method). Log the details of the exception and bring down
                                // the process.
                                Log.e(TAG, "Caught post-fork exception in child process.", e);
                                throw e;
                            }
                        } finally {
                            // Reset the child flag, in the event that the child process is a child-
                            // zygote. The flag will not be consulted this loop pass after the
                            // Runnable is returned.
                            mIsForkChild = false;
                        }

                    } else {
                        // Either the USAP pool event FD or a USAP reporting pipe.

                        // If this is the event FD the payload will be the number of USAPs removed.
                        // If this is a reporting pipe FD the payload will be the PID of the USAP
                        // that was just specialized.  The `continue` statements below ensure that
                        // the messagePayload will always be valid if we complete the try block
                        // without an exception.
                        long messagePayload;

                        try {
                            byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
                            int readBytes =
                                    Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);

                            if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
                                DataInputStream inputStream =
                                        new DataInputStream(new ByteArrayInputStream(buffer));

                                messagePayload = inputStream.readLong();
                            } else {
                                Log.e(TAG, "Incomplete read from USAP management FD of size "
                                        + readBytes);
                                continue;
                            }
                        } catch (Exception ex) {
                            if (pollIndex == usapPoolEventFDIndex) {
                                Log.e(TAG, "Failed to read from USAP pool event FD: "
                                        + ex.getMessage());
                            } else {
                                Log.e(TAG, "Failed to read from USAP reporting pipe: "
                                        + ex.getMessage());
                            }

                            continue;
                        }

                        if (pollIndex > usapPoolEventFDIndex) {
                            Zygote.removeUsapTableEntry((int) messagePayload);
                        }

                        usapPoolFDRead = true;
                    }
                }

                if (usapPoolFDRead) {
                    int usapPoolCount = Zygote.getUsapPoolCount();

                    if (usapPoolCount < mUsapPoolSizeMin) {
                        // Immediate refill
                        mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
                    } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
                        // Delayed refill
                        mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
                    }
                }
            }

            if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {
                int[] sessionSocketRawFDs =
                        socketFDs.subList(1, socketFDs.size())
                                .stream()
                                .mapToInt(FileDescriptor::getInt$)
                                .toArray();

                final boolean isPriorityRefill =
                        mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;

                final Runnable command =
                        fillUsapPool(sessionSocketRawFDs, isPriorityRefill);

                if (command != null) {
                    return command;
                } else if (isPriorityRefill) {
                    // Schedule a delayed refill to finish refilling the pool.
                    mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
                }
            }
        }
    }
}

Zygote采用高效的I/O多路复用机制,保证在没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。

3.5 ZygoteConnection.processCommand

Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    ZygoteArguments parsedArgs;

    try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
        while (true) {
            try {
				//读取socket客户端发送过来的参数列表,解析成Arguments对象格式
                parsedArgs = ZygoteArguments.getInstance(argBuffer);
                // Keep argBuffer around, since we need it to fork.
            } catch (IOException ex) {
                throw new IllegalStateException("IOException on command socket", ex);
            }
            if (parsedArgs == null) {
                isEof = true;
                return null;
            }

            int pid;
            FileDescriptor childPipeFd = null;
            FileDescriptor serverPipeFd = null;

            if (parsedArgs.mBootCompleted) {
                handleBootCompleted();
                return null;
            }

            if (parsedArgs.mAbiListQuery) {
                handleAbiListQuery();
                return null;
            }

            if (parsedArgs.mPidQuery) {
                handlePidQuery();
                return null;
            }

            if (parsedArgs.mUsapPoolStatusSpecified
                    || parsedArgs.mApiDenylistExemptions != null
                    || parsedArgs.mHiddenApiAccessLogSampleRate != -1
                    || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
                // Handle these once we've released argBuffer, to avoid opening a second one.
                break;
            }

            if (parsedArgs.mPreloadDefault) {
                handlePreload();
                return null;
            }

            if (parsedArgs.mPreloadPackage != null) {
                handlePreloadPackage(parsedArgs.mPreloadPackage,
                        parsedArgs.mPreloadPackageLibs,
                        parsedArgs.mPreloadPackageLibFileName,
                        parsedArgs.mPreloadPackageCacheKey);
                return null;
            }

            if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
                byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
                Parcel appInfoParcel = Parcel.obtain();
                appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
                appInfoParcel.setDataPosition(0);
                ApplicationInfo appInfo =
                        ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
                appInfoParcel.recycle();
                if (appInfo != null) {
                    handlePreloadApp(appInfo);
                } else {
                    throw new IllegalArgumentException("Failed to deserialize --preload-app");
                }
                return null;
            }

            if (parsedArgs.mPermittedCapabilities != 0
                    || parsedArgs.mEffectiveCapabilities != 0) {
                throw new ZygoteSecurityException("Client may not specify capabilities: "
                        + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
                        + ", effective=0x"
                        + Long.toHexString(parsedArgs.mEffectiveCapabilities));
            }

            Zygote.applyUidSecurityPolicy(parsedArgs, peer);
            Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);

            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

            int[][] rlimits = null;

            if (parsedArgs.mRLimits != null) {
                rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
            }

            int[] fdsToIgnore = null;

            if (parsedArgs.mInvokeWith != null) {
                try {
                    FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                    childPipeFd = pipeFds[1];
                    serverPipeFd = pipeFds[0];
                    Os.fcntlInt(childPipeFd, F_SETFD, 0);
                    fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
                } catch (ErrnoException errnoEx) {
                    throw new IllegalStateException("Unable to set up pipe for invoke-with",
                            errnoEx);
                }
            }

            /*
             * In order to avoid leaking descriptors to the Zygote child,
             * the native code must close the two Zygote socket descriptors
             * in the child process before it switches from Zygote-root to
             * the UID and privileges of the application being launched.
             *
             * In order to avoid "bad file descriptor" errors when the
             * two LocalSocket objects are closed, the Posix file
             * descriptors are released via a dup2() call which closes
             * the socket and substitutes an open descriptor to /dev/null.
             */

            int [] fdsToClose = { -1, -1 };

            FileDescriptor fd = mSocket.getFileDescriptor();

            if (fd != null) {
                fdsToClose[0] = fd.getInt$();
            }

            FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor();

            if (zygoteFd != null) {
                fdsToClose[1] = zygoteFd.getInt$();
            }

            if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
                    || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
                // Continue using old code for now. TODO: Handle these cases in the other path.
                pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
                        parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
                        parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
                        fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                        parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
                        parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
                        parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                        parsedArgs.mBindMountAppStorageDirs);

                try {
                    if (pid == 0) {
                        // in child子进程执行
                        zygoteServer.setForkChild();

                        zygoteServer.closeServerSocket();
                        IoUtils.closeQuietly(serverPipeFd);
                        serverPipeFd = null;
						//进入子进程流程
                        return handleChildProc(parsedArgs, childPipeFd,
                                parsedArgs.mStartChildZygote);
                    } else {
                        // In the parent. A pid < 0 indicates a failure and will be handled in
                        // handleParentProc.父进程执行
                        IoUtils.closeQuietly(childPipeFd);
                        childPipeFd = null;
                        handleParentProc(pid, serverPipeFd);
                        return null;
                    }
                } finally {
                    IoUtils.closeQuietly(childPipeFd);
                    IoUtils.closeQuietly(serverPipeFd);
                }
            } else {
                ZygoteHooks.preFork();
                Runnable result = Zygote.forkSimpleApps(argBuffer,
                        zygoteServer.getZygoteSocketFileDescriptor(),
                        peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
                if (result == null) {
                    // parent; we finished some number of forks. Result is Boolean.
                    // We already did the equivalent of handleParentProc().
                    ZygoteHooks.postForkCommon();
                    // argBuffer contains a command not understood by forksimpleApps.
                    continue;
                } else {
                    // child; result is a Runnable.
                    zygoteServer.setForkChild();
                    Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
                    return result;
                }
            }
        }
    }
    // Handle anything that may need a ZygoteCommandBuffer after we've released ours.
    if (parsedArgs.mUsapPoolStatusSpecified) {
        return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
    }
    if (parsedArgs.mApiDenylistExemptions != null) {
        return handleApiDenylistExemptions(zygoteServer,
                parsedArgs.mApiDenylistExemptions);
    }
    if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
            || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
        return handleHiddenApiAccessLogSampleRate(zygoteServer,
                parsedArgs.mHiddenApiAccessLogSampleRate,
                parsedArgs.mHiddenApiAccessStatslogSampleRate);
    }
    throw new AssertionError("Shouldn't get here");
}

四、总结

4.1 Zygote启动过程的调用流程图:

  1. 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
  2. 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
  3. 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
  4. preload()预加载通用类、drawable和color资源、共享库以及WebView,用于提高app启动效率;
  5. zygote完毕大部分工作,接下来再通过forkSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
  6. zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

4.2 Zygote进程能够重启的地方:

  • servicemanager进程被杀; (onresart)
  • surfaceflinger进程被杀; (onresart)
  • Zygote进程自己被杀; (oneshot=false)
  • system_server进程被杀; (waitpid)

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;