上一节我们详细的看了下Android应用进程的启动过程分析,知道了应用进程是由Zygote进程调用Linux的系统函数fork复制出来的,那么Zygote进程是怎么启动起来的?这节我们就来看一下Zygote进程的启动过程。

     当我们的Android手机开机时,Linux的init进程会去加载init.rc配置文件,老罗博客上讲的是Android 2.3的系统,当前应该还没有64位的虚拟机,所以Zygote进程的启动都是配置在init.rc文件中,而8.0的Android源码中已经支持了32位的虚拟机和64位的虚拟机,而且有主次之分,所以就会有四个配置文件,截图如下:


     该配置文件的目录路径为:system\core\rootdir\,init.zygote32.rc文件表示当前的手机只配置有32位的Zygote,init.zygote32_64.rc文件表示当前的Zygote同时配置有32位和64位,而且以32位为主Zygote,64位为次Zygote,主次是怎么区分的呢?就是从配置文件中的--socket-name属性来区分的。另外两个init.zygote64.rc、init.zygote64_32.rc分别表示只支持64位的Zygote和同时两个支持,但是以64位为主。init.zygote32_64.rc配置文件的源码如下:

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote    class main    priority -20    user root    group root readproc    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart audioserver    onrestart restart cameraserver    onrestart restart media    onrestart restart netd    onrestart restart wificond    writepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary    class main    priority -20    user root    group root readproc    socket zygote_secondary stream 660 root system    onrestart restart zygote    writepid /dev/cpuset/foreground/tasks

     大家可以看到,两个Zygote的name属性就表示出它们的主次了。init.rc文件加载完成后,两个Zygote虚拟机的name属性也用来在AMS请求创建新的应用进程时,进行匹配,这个过程我们上节已经看到了。Zygote是以service配置的,所以当解析该完成时,init进程就会调用fork去创建Zygote进程,并且执行app_main.cpp文件中的main函数,作为Zygote进行的启动入口。app_main.cpp文件的目录路径为:frameworks\base\cmds\app_process\app_main.cpp,它的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());    }    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));    // Process command line arguments    // ignore argv[0]    argc--;    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.    //    // As an exception to the above rule, anything in "spaced commands"    // goes to the vm even though it has a space in it.    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]));          ALOGV("app_process main add known option '%s'", argv[i]);          known_command = false;          continue;        }        for (int j = 0;             j < static_cast(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]));        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;            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 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) {        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.");    }}

     该函数首先创建一个AppRuntime对象,然后对init.rc配置文件中的启动参数argc、argv[]进行解析,while循环中我们可以看到,如果配置的启动参数为--zygote,表示要启动Zygote进程,如果为--start-system-server表示要启动SystemServer进程,如果为--application就表示是普通的应用进程。我们当前的场景中就是第一个,参数解析完成后,此时的局部变量zygote的值为true,最后的if/else分支就会执行runtime.start("com.android.internal.os.ZygoteInit", args, zygote)来继续完成Zygote进行的启动。

     接下来我们就看看AppRuntime的创建过程,AppRuntime类的定义也是在app_main文件中,该类的源码如下:

class AppRuntime : public AndroidRuntime{public:    AppRuntime(char* argBlockStart, const size_t argBlockLength)        : AndroidRuntime(argBlockStart, argBlockLength)        , mClass(NULL)    {    }    void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {        mClassName = className;        for (int i = 0; i < argc; ++i) {             mArgs.add(String8(argv[i]));        }    }    virtual void onVmCreated(JNIEnv* env)    {        if (mClassName.isEmpty()) {            return; // Zygote. Nothing to do here.        }        /*         * This is a little awkward because the JNI FindClass call uses the         * class loader associated with the native method we're executing in.         * If called in onStarted (from RuntimeInit.finishInit because we're         * launching "am", for example), FindClass would see that we're calling         * from a boot class' native method, and so wouldn't look for the class         * we're trying to look up in CLASSPATH. Unfortunately it needs to,         * because the "am" classes are not boot classes.         *         * The easiest fix is to call FindClass here, early on before we start         * executing boot class Java code and thereby deny ourselves access to         * non-boot classes.         */        char* slashClassName = toSlashClassName(mClassName.string());        mClass = env->FindClass(slashClassName);        if (mClass == NULL) {            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());        }        free(slashClassName);        mClass = reinterpret_cast(env->NewGlobalRef(mClass));    }    virtual void onStarted()    {        sp proc = ProcessState::self();        ALOGV("App process: starting thread pool.\n");        proc->startThreadPool();        AndroidRuntime* ar = AndroidRuntime::getRuntime();        ar->callMain(mClassName, mClass, mArgs);        IPCThreadState::self()->stopProcess();        hardware::IPCThreadState::self()->stopProcess();    }    virtual void onZygoteInit()    {        sp proc = ProcessState::self();        ALOGV("App process: starting thread pool.\n");        proc->startThreadPool();    }    virtual void onExit(int code)    {        if (mClassName.isEmpty()) {            // if zygote            IPCThreadState::self()->stopProcess();            hardware::IPCThreadState::self()->stopProcess();        }        AndroidRuntime::onExit(code);    }    String8 mClassName;    Vector mArgs;    jclass mClass;};

     它是AndroidRuntime类的子类,它的构造方法中没有任何逻辑。那我们接着来看看AndroidRuntime类的构造方法,AndroidRuntime类的定义在AndroidRuntime.cpp文件中,目录路径为:frameworks\base\core\jni\AndroidRuntime.cpp,它的构造方法的源码如下:

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :        mExitWithoutCleanup(false),        mArgBlockStart(argBlockStart),        mArgBlockLength(argBlockLength){    SkGraphics::Init();    // There is also a global font cache, but its budget is specified by    // SK_DEFAULT_FONT_CACHE_COUNT_LIMIT and SK_DEFAULT_FONT_CACHE_LIMIT.    // Pre-allocate enough space to hold a fair number of options.    mOptions.setCapacity(20);    assert(gCurRuntime == NULL);        // one per process    gCurRuntime = this;}

     这里就是给成员变量gCurRuntime赋值,后面的注释也写的非常清楚了,一个进程只会执行一次,如果gCurRuntime不为空,那么assert方法进行参数检查时就会抛出异常。好了,AppRuntime类的构造方法我们就看到这里,接下来我们继续分析app_main文件中的main函数的最后一句runtime.start("com.android.internal.os.ZygoteInit", args, zygote)来看看Zygote进行是如何启动起来的。runtime对象就是AppRuntime,它没有重写start方法,所以会执行父类AndroidRuntime类的start方法,AndroidRuntime类的start方法源码如下:

/* * Start the Android runtime.  This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */void AndroidRuntime::start(const char* className, const Vector& options, bool zygote){    ALOGD(">>>>>> START %s uid %d <<<<<<\n",            className != NULL ? className : "(unknown)", getuid());    static const String8 startSystemServer("start-system-server");    /*     * 'startSystemServer == true' means runtime is obsolete and not run from     * init.rc anymore, so we print out the boot start event here.     */    for (size_t i = 0; i < options.size(); ++i) {        if (options[i] == startSystemServer) {           /* track our progress through the boot sequence */           const int LOG_BOOT_PROGRESS_START = 3000;           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));        }    }    const char* rootDir = getenv("ANDROID_ROOT");    if (rootDir == NULL) {        rootDir = "/system";        if (!hasDir("/system")) {            LOG_FATAL("No root directory specified, and /android does not exist.");            return;        }        setenv("ANDROID_ROOT", rootDir, 1);    }    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);    /* start the virtual machine */    JniInvocation jni_invocation;    jni_invocation.Init(NULL);    JNIEnv* env;    if (startVm(&mJavaVM, &env, zygote) != 0) {        return;    }    onVmCreated(env);    /*     * Register android functions.     */    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;    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) {        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);    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 {            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");}

     该方法一共三个参数,第一个是启动类的类路径全名,也就是com.android.internal.os.ZygoteInit,第二个参数options就是前面解析好的启动参数,第三个zygote表示当前是否要启动Zygote进程,当前场景下该值为true,接下来就调用startVm启动虚拟机,我们来看一下该方法的实现。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 useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];    char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];    char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-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, "");    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;        }    }    ALOGV("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:");    strcpy(jniOptsBuf, "-Xjniopts:");    if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {        ALOGI("JNI options: '%s'\n", jniOptsBuf);    }    /* route exit() to our handler */    addOption("exit", (void*) runtime_exit);    /* route fprintf() to our handler */    addOption("vfprintf", (void*) runtime_vfprintf);    /* register the framework-specific "is sensitive thread" hook */    addOption("sensitiveThread", (void*) runtime_isSensitiveThread);    /* enable verbose; standard options are { jni, gc, class } */    //addOption("-verbose:jni");    addOption("-verbose:gc");    //addOption("-verbose:class");    /*     * The default starting and maximum size of the heap.  Larger     * values should be specified in a product property override.     */    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=");    /*     * 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:");    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:");    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=assume-verified");    } 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=assume-verified");        // 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);    // 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:");    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;}

     可以看到,该方法的代码非常多。前面的一大堆char数组都是用来指定虚拟机的启动属性的,这里我们也可以看到checkJni的默认值为false,如果我们指定了dalvik.vm.checkjni配置项的话,那么它就会为true,在执行JNI调用时就会进行合法性检查。dalvik.vm.heapsize用来指定虚拟机启动时的堆内存大小,可以看到8.0默认的虚拟机的堆内存配置为16M,再往下还有上节我们讲的ro.product.cpu.abilist64、ro.product.cpu.abilist32配置项,一大堆参数封装完成后,最后就直接调用JNI_CreateJavaVM方法来创建虚拟机。第一个方法参数pJavaVM是一个类型为JavaVM的双重指针,它的定义在libnativehelper\include\nativehelper\jni.h文件中,源码如下:

typedef _JavaVM JavaVM;struct _JavaVM {    const struct JNIInvokeInterface* functions;#if defined(__cplusplus)    jint DestroyJavaVM()    { return functions->DestroyJavaVM(this); }    jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)    { return functions->AttachCurrentThread(this, p_env, thr_args); }    jint DetachCurrentThread()    { return functions->DetachCurrentThread(this); }    jint GetEnv(void** env, jint version)    { return functions->GetEnv(this, env, version); }    jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)    { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }#endif /*__cplusplus*/};
     startVm方法执行完,AndroidRuntime类的成员变量mJavaVM就会被赋值,接下来执行onVmCreated方法,该方法在AndroidRuntime类中的实现为空,它是由AppRuntime类重写的,来执行一些扩展的工作。接下来继续执行startReg方法,进行native层的方法注册,它的源码如下:

/*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);    ALOGV("--- registering native functions ---\n");    /*     * Every "register" function calls one or more things that return     * a local reference (e.g. FindClass).  Because we haven't really     * started the VM yet, they're all getting stored in the base frame     * and never released.  Use Push/Pop to manage the storage.     */    env->PushLocalFrame(200);    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {        env->PopLocalFrame(NULL);        return -1;    }    env->PopLocalFrame(NULL);    //createJavaThread("fubar", quickTest, (void*) "hello");    return 0;}
     该方法中最重要的就是register_jni_procs逻辑了,该方法会将AndroidRuntime.cpp文件中定义的RegJNIRec gRegJNI[]数组中的所有方法注册进来,这样我们才可以从native层回调到Java层, gRegJNI数组中声明的都是方法指针,在Java层的实现方法的修饰符都会被定义为private,不允许其他地方调用,这样也是一种非常好的编码习惯。接下来最后的一段逻辑就是找到我们传入的class的Java类,然后调用该类的main方法,也就是frameworks\base\core\java\com\android\internal\os\ZygoteInit.java类的main方法了,它的main方法中会进入无限循环,直到虚拟机退出。ZygoteInit.java类的main方法的源码如下:

public static void main(String argv[]) {        ZygoteServer zygoteServer = new ZygoteServer();        // 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);        }        try {            // Report Zygote start time to tron unless it is a runtime restart            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {                MetricsLogger.histogram(null, "boot_zygote_init",                        (int) SystemClock.elapsedRealtime());            }            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";            BootTimingsTraceLog bootTimingsTraceLog = new BootTimingsTraceLog(bootTimeTag,                    Trace.TRACE_TAG_DALVIK);            bootTimingsTraceLog.traceBegin("ZygoteInit");            RuntimeInit.enableDdms();            // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            boolean startSystemServer = false;            String socketName = "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)) {                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());                } else {                    throw new RuntimeException("Unknown command line argument: " + argv[i]);                }            }            if (abiList == null) {                throw new RuntimeException("No ABI list supplied.");            }            zygoteServer.registerServerSocket(socketName);            // 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());                preload(bootTimingsTraceLog);                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,                    SystemClock.uptimeMillis());                bootTimingsTraceLog.traceEnd(); // ZygotePreload            } else {                Zygote.resetNicePriority();            }            // Finish profiling the zygote initialization.            SamplingProfilerIntegration.writeZygoteSnapshot();            // Do an initial gc to clean up after startup            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");            gcAndFinalize();            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC            bootTimingsTraceLog.traceEnd(); // ZygoteInit            // Disable tracing so that forked processes do not inherit stale tracing tags from            // Zygote.            Trace.setTracingEnabled(false);            // Zygote process unmounts root storage spaces.            Zygote.nativeUnmountStorageOnInit();            // Set seccomp policy            Seccomp.setPolicy();            ZygoteHooks.stopZygoteNoThreadCreation();            if (startSystemServer) {                startSystemServer(abiList, socketName, zygoteServer);            }            Log.i(TAG, "Accepting command socket connections");            zygoteServer.runSelectLoop(abiList);            zygoteServer.closeServerSocket();        } catch (Zygote.MethodAndArgsCaller caller) {            caller.run();        } catch (Throwable ex) {            Log.e(TAG, "System zygote died with exception", ex);            zygoteServer.closeServerSocket();            throw ex;        }    }
     首先构造一个ZygoteServer对象,名字取的非常形象,就像是服务器一样等待客户端来请求。接下来对我们传入的argv参数进行解析,几个if/else分支的判断就可以很明显的看出来意图。然后调用zygoteServer.registerServerSocket(socketName)进行socket注册,参数就是我们在init.rc中写入的socket名称。当然在ZygoteServer中注册时,还会加上private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"前缀,和zygoteName拼接起来。大家可以自己去看一下该方法的实现。注册完成后继续调用zygoteServer.runSelectLoop(abiList)进入无限循环,如果无限循环退出了,那说明虚拟机也要退出了,退出前执行zygoteServer.closeServerSocket()来将socket关闭。我们继续来看一下 runSelectLoop方法,该方法实现在frameworks\base\core\java\com\android\internal\os\ZygoteServer.java文件中,源码如下:

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {        ArrayList fds = new ArrayList();        ArrayList peers = new ArrayList();        fds.add(mServerSocket.getFileDescriptor());        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;            }            try {                Os.poll(pollFds, -1);            } 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) {                    ZygoteConnection newPeer = acceptCommandPeer(abiList);                    peers.add(newPeer);                    fds.add(newPeer.getFileDesciptor());                } else {                    boolean done = peers.get(i).runOnce(this);                    if (done) {                        peers.remove(i);                        fds.remove(i);                    }                }            }        }    }
     该方法中首先调用mServerSocket.getFileDescriptor()将刚才注册的socket的文件描述符添加到局部变量fds中,然后在while循环中新建局部变量pollFds,用来监控该文件描述符上的事件,Os.poll(pollFds, -1)就是调用Linux的epoll机制,传入的第二个参数为-1表示该文件描述符上如果没有事件则一直睡眠,如果有事件的话,该函数就会立刻返回去处理事件。我们启动新的进程时,也就是在else分支中通过peers.get(i).runOnce(this)将当前的连接事件取出来执行,新进程创建成员后肯定需要调用peers.remove(i)将对应的ZygoteConnection连接移除,以免重复创建。

     那么到这里,我们的Zygote进程就启动起来了,后续就会在这个while无限循环中等待AMS来请求创建新的进程了。

更多相关文章

  1. android 7.1 找不到 ll (ls -l)命令
  2. Android(安卓)释放资源和进程的优先级顺序
  3. Android(安卓)U盘文件显示在文件管理器
  4. Android初级开发(八)——手机多媒体—音频和视频的使用
  5. Android(安卓)Scroll详解(三):Android(安卓)绘制过程详解
  6. Android性能优化(◍˃ᗜ˂◍)✩
  7. Android(安卓)Scollview嵌套Listview,Gridview数据显示不完全问
  8. Java代理模式与Android的情结
  9. Android事件分派机制

随机推荐

  1. php如何使用date去掉时分秒
  2. kubernetes-ingress 安装
  3. PowerHA 常见故障排查
  4. css如何设置文字加粗
  5. Kubernetes 中定时任务的实现
  6. 争议 | 银行一定要上分布式数据库吗?有没
  7. Kubernetes 指标采集组件的部署
  8. 情报研判可视化分析平台开发解决方案
  9. 通过kuboard实现弹性伸缩
  10. Java和HTML有什么区别?哪个更重要?