解析zygote启动过程

在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.cpp中main函数里的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) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            //如果当前运行在zygote进程中,则将zygote设置为true
            zygote = true;
            niceName = ZYGOTE_NICE_NAME; 
        }
        
    *****省略部分代码*****  
    
    if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); }
    
    *****省略部分代码*****    
}

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

AndroidRuntime

接下来就是如果zygote等于true的话,就会调用到AndroidRuntime的start函数

//代码文件位置: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);
    assert(classNameStr != NULL);
    
    *****省略部分代码*****
    //将"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");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            //通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    
    *****省略部分代码*****

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

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

ZygoteInit

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

//代码文件位置: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);
    }
    Log.i(TAG, "Accepting command socket connections");
    //一直循环,等待AMS的请求,去fork子进程
    zygoteServer.runSelectLoop(abiList);
}

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值