系统启动流程(三)之解析zygote启动过程

460 阅读3分钟

前言

在Android系统中,Dalvik虚拟机或者是ART、应用程序进程、还有运行系统的关键服务(比如SystemServer等)进程都是由Zygote来创建的,Zygote通过fork来创建子进程。因为Zygote进程在启动时,会创建Dalvik虚拟机或者是ART,所以通过fork出的子进程中也会带有Dalvik虚拟机或者ART。

通过系统启动流程(二)之解析init.rc文件,我们能知道Zygote进程是由init进程启动时创建而成的。

小知识点

起初Zygote进程的名称并不是叫“zygote”,在源码中能看到它修改进程名为zygote的地方,代码(frameworks/base/cmds/app_process/app_main.cpp)如下: 1687917711082.png image.png

zygote启动过程源码分析

先来一张时序图,根据时序图来分析源码:

zygote.png

根据简单易懂(二)之解析init.rc文件,我们知道init主要是调用了app_main.cppmain函数里的runtime.start("com.android.internal.os.ZygoteInit", args, zygote)来启动Zygote进程的,这里的runtime其实就是AndroidRuntime的实例。

app_main.cpp

我们先从app_main.cpp里的main函数开始分析:

//代码文件位置:frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){
    *****省略部分代码*****
    
    while (i < argc) {
        if (strcmp(arg, "--zygote") == 0) {
            //如果当前运行在zygote进程中,则将zygote设置为true
            zygote = true;
        }
        
    *****省略部分代码*****  
    
    if (zygote) { 
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 
    }
    
    *****省略部分代码*****    
}

因为Zygote进程都是通过fork自身来创建子进程的,所以Zygote的子进程也都可以进入到app_main.cppmain函数,所以main函数中为了区分当前是运行在哪个进程里,会通过参数arg来判断。上面代码中,通过判断是否包含“--zygote”,如果有,说明是在Zygote进程中。(这个“--zygote”init.rc文件里传过来的,具体可以看上篇文章)。

AndroidRuntime

接下来就是如果Zygote等于true的话,就会调用到AndroidRuntimestart函数:

//代码文件位置:frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    *****省略部分代码*****
    
    //在这里启动Java虚拟机
     if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    
    //为Java虚拟机注册JNI方法
     if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    
    //这个className就是app_main传过来的"com.android.internal.os.ZygoteInit"
    classNameStr = env->NewStringUTF(className);
    
    //将"com.android.internal.os.ZygoteInit"里的 “.” 替换为 “/”
    char* slashClassName = toSlashClassName(className);
    
    //找到ZygoteInit类
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
    
        //在这里找到ZygoteInit的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        } else {
            //通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
    *****省略部分代码*****

上述代码里加了注释了,整体下来的流程是:先调用startVm函数创建了Java虚拟机,接着调用startReg函数给Java虚拟机注册JNI方法,再找到ZygoteInit后,通过JNI调到到ZygoteInitmain方法。

小知识点:

这里需要通过JNI调用的原因是:因为ZygoteInit是一个java语言编写的类,然而当前是在zygote进程下还处于Native环境下,如果要调用到java层的代码,就需要通过JNI调用。

ZygoteInit

也就是说到这里时,zygote进程就从Native层进入到java层了。继续看javaZygoteInitmain方法:

//代码文件位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    *****省略部分代码*****
    
    //创建一个Server端的Socket,socketName的值为"zygote"
    zygoteServer.registerServerSocket(socketName);
   
    //预加载类和资源
    preload(bootTimingsTraceLog);
    
    if (startSystemServer) {
        //注意,在这里启动了SystemServer进程
        startSystemServer(abiList, socketName, zygoteServer);
    }
    
    //一直循环,等待AMS的请求,去fork子进程
    zygoteServer.runSelectLoop(abiList);
}

通过上述代码,我们能知道ZygoteInitmain方法主要做4件事:

  1. 创建一个Server端Socket
  2. 预加载类和资源
  3. 启动SystemServer进程
  4. 一直等待AMS请求,去创建新的应用程序进程

小知识点:

从这里我们知道了zygote进程是通过socket来跟其他进程通信的。

这里能看到SystemServer进程是这里被启动的,也就证明了前面讲的zygote进程负责启动systemserver进程,具体的启动过程,我们留下一篇文章讲。

系列文章

点击直达→→ 更多系统启动流程文章

有所收获的朋友,请多多关注、点赞,谢谢大家!