一、 写在前面

  Zygote Android中最重要进程之一,Android中SystemServer进程、运用进程均是经过该进程fork而来。了解了Zygote进程的发动流程源码(基于Android源码master分支)对Android全体结构以及Android运用进程发动相关源码可谓是大有裨益。

二、 Zygote发动-native层

1、Zygote进程发动进口

  Zygote进程是init进程经过解析init.zygote64/32.rc文件发动的。其进口坐落app_main.cpp的main函数中。部分代码如下所示:

//argc:参数个数
//argv:zygote进程发动参数,来源于xx.rc文件
int main(int argc, char* const argv[])
{
    //省掉日志打印
    ......
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    //第一个参数没有运用到,因而直接跳过
    argc--;
    argv++;
    //The first argument after the VM args is the "parent dir", which
    // is currently unused.
    ......
    int i;
    for (i = 0; i < argc; i++) {
        //参数赋值给AppRuntime
        ......
    }
    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++];
        //判别是否是发动zygote进程
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        //判别是否发动SystemServer进程,java层有运用到该参数	
        } 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
        ......
    } else {
         //将参数存储到Vector列表中
        // We're in zygote mode.
        ......
    }
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
    //判别当时是否是发动zygote进程
    if (zygote) {
        //正式进入到Zygote进程发动流程
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.isEmpty()) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        ......
    }
}

2、Zygote进程初始化

  如下代码主要完成了虚拟机发动(可参考博客:基于Android R之ART虚拟机的创立流程)、动态注册Android结构中native函数与C++层函数的映射以及经过反射调用到ZygoteInit类中main函数。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    static const String8 startSystemServer("start-system-server");
    bool primary_zygote = false;
    ......
    //getenv(xx)用于获取Android体系环境变量
    //判别Android根目录是否存在
    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);
    }
    //判别art根目录是否存在
    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }
    //判别体系国际化数据根目录是否存在(/system/usr/share/i18n)
    //i18n数据包含与本地化相关的资源,例如语言翻译、日期/时刻格局和钱银符号,这些资源被Android运用程序用于供给本地化的用户体验
    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;
    }
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //发动虚拟机,以及依据虚拟机创立当时线程对应的JNIEnv(jni调用到java层相关目标)目标
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);
    //动态注册Android结构中native函数与C++层函数的映射
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ......
    //省掉参数构造相关代码
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
        } else {
            //终究经过反射调用到Android结构类com.android.internal.os.ZygoteInit的main函数中
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
                        ......
              }
    }
    free(slashClassName);
    ......
}

3、startReg

  该代码实现比较简单,就是循环调用结构体数组RegJNIRec中的函数指针,以动态注册Android结构中native函数与C++层函数的映射。大体代码如下:

//部分函数指针界说
static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
        REG_JNI(register_android_os_SystemClock),
        REG_JNI(register_android_util_CharsetUtils),
        ......
}
#define REG_JNI(name)      { name }
struct RegJNIRec {
        //界说函数指针
    int (*mProc)(JNIEnv*);
};
int AndroidRuntime::startReg(JNIEnv* env)
{
    env->PushLocalFrame(200);
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    return 0;
}
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    //循环调用到指定函数进行动态注册
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
            return -1;
        }
    }
    return 0;
}

  如下以register_android_os_SystemClock为例。终究会调用到android_os_SystemClock类中。代码如下:

static const JNINativeMethod gMethods[] = {
    { "uptimeMillis", "()J", (void*) uptimeMillis },
    { "uptimeNanos", "()J", (void*) uptimeNanos },
    { "elapsedRealtime", "()J", (void*) elapsedRealtime },
    { "elapsedRealtimeNanos", "()J", (void*) elapsedRealtimeNano },
    { "currentThreadTimeMillis", "()J",
            (void*) android_os_SystemClock_currentThreadTimeMillis },
    { "currentThreadTimeMicro", "()J",
            (void*) android_os_SystemClock_currentThreadTimeMicro },
    { "currentTimeMicro", "()J",
            (void*) android_os_SystemClock_currentTimeMicro },
};
int register_android_os_SystemClock(JNIEnv* env)
{
    //最后一个参数表明需求注册函数个数
    return RegisterMethodsOrDie(env, "android/os/SystemClock", gMethods, NELEM(gMethods));
}

三、 Zygote发动-Java层

1、ZygoteInit

  ZygoteInit中main函数全体来说就三件工作:(1)Zygote相关初始化;(2)fork systemServer进程;(3)创立LocalSocketServer用于监听进程创立。

public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;
    //用于表明Zygote进程发动,如果在该进程中新建线程则会报错
    //在zygote中只能是单线程,这和后续子进程创立fork有关
    ZygoteHooks.startZygoteNoThreadCreation();
    try {
        //用于将当时进程的进程组ID(PGID)设置为与该进程的pid相同的值
        //第一个参数为0表明将当时进程PGID设置为本身的PID,第二个参数为0表明将该操作用于当时进程
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }
    Runnable caller;
    try {
        final long startTime = SystemClock.elapsedRealtime();
        //判别当时Android体系是否是重启
        final boolean isRuntimeRestarted = "1".equals(SystemProperties.get("sys.boot_completed"));
        //判别当时进程是64位还是32位
        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]);
            }
        }
        //判别当时是否是zygote进程发动
        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
        //省掉trace相关
        .......
        //gc相关,尝试铲除无用目标
        gcAndFinalize();
        //zygote native层相关初始化,比方获取socket fd、selinux初始化以及storage存储目录初始化
        Zygote.initNativeState(isPrimaryZygote);
        //表明现在可以创立线程
        ZygoteHooks.stopZygoteNoThreadCreation();
        //用于构造LocalSocket
        zygoteServer = new ZygoteServer(isPrimaryZygote);
        //fork SystemServer进程
        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
            if (r != null) {
                r.run();
                return;
            }
        }
        Log.i(TAG, "Accepting command socket connections");
        //LocalSocketServer等待链接,用于子进程创立
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }
    if (caller != null) {
        caller.run();
    }
}

四、总结

  如上即为Zygote发动的全体流程,其所涉及到的代码并不多,但细节也不少;关于其他没有涉及到的细节部分可移步Android体系发动-zygote篇。除了上述源码之外,如下还有几个有用的知识点可能对当时以及后续进程发动相关源码理解有必定的帮助:

  • JavaVM:每个进程有且只有一个JavaVM实例;
  • JNIEnv:每个线程有且只有一个JNIEnv实例。由Java虚拟机动态创立,并经过JNI_OnLoad函数传递给本地方法。JNIEnv实现是渠道相关的,而且由Java虚拟机厂商供给。在Android渠道上,JNIEnv的实现由Dalvik虚拟机和ART虚拟机供给,每个线程都有自己的JNIEnv实例,而且在Java代码和本地代码之间交互时自动创立和开释;
  • JNI_OnLoad:当本地so库加载到Java虚拟机中时,JVM会自动调用JNI_OnLoad函数。在JNI_OnLoad函数中,本地库可以获取JNIEnv,并将其存储在本地线程中,以供本地方法运用;
  • fork:在C或C++代码中,运用 fork() 函数创立一个新的子进程,这个函数会回来两次,一次在父进程中回来子进程的 PID,一次在子进程中回来 0。