Zygote的启动流程

前言

Android系统开发,zygote显然是接触很多的一个术语。那zygote是什么呢?好奇查了下zygote的中文翻译:受精卵。这是我见过最形象和最正确的命名。顾名思义,就是孵化下一代。Android中,Zygote是所有App的父进程,所有的app都由它孵化而出,可见zygote的地位,堪比女娲造人。那zygote在Android系统中是如何启动的呢?

概述

众所周知,Android系统是跑在Linux内核上的,姑且将zygote看成是跑在Linux上的一个Linux应用。那么zygote想要启动,则必然需要先让Linux内核跑起来(听起来像是废话了~)。事实也是如此,zygote正是由Linux的天字第一号进程【init】启动。接下来就是从init.rc开始,一路分析zygote的启动过程。先上一张流程图,本文所讲的内容都在这。
在这里插入图片描述

init.rc

init进程启动后,对init.rc文件进行了解析并执行了各个阶段的动作,而zygote进程就是这个过程中被触发启动的。直接看代码直观点:

/system/core/rootdir/init.rc

on late-init
    ...
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start
    

...
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
 # A/B update verifier that marks a successful boot.
 exec_start update_verifier_nonencrypted
 start netd
 start zygote
 start zygote_secondary
 
 ...

zygote在init.rc中被触发并通过【start zygote】的方式启动,而这里的zygote是init.rc文件中的服务,如下:

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
 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/tasks

可见zygote服务最终调用了app_process这个可执行文件,并传入【–zygote】和【–start-system-server】这两个参数。

app_main

app_main是一个可执行文件,入口是main函数,具体源码如下:

/frameworks/base/cmds/app_process/app_main.cpp

 int main(int argc, char* const argv[])
 {
     ...
     
     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
     
     ...
    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;
      }
    }
     ... 
     
    if (zygote) {
      runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } 

    ...
 }

专注zygote相关的关键代码,在这个main函数中,主要做了三件事:

1.使用AppRuntime类实例化了一个虚拟机runtime,而AppRuntime则继承AndroidRuntime;
2.解析传给app_main的参数,主要是zygote和start_system_server;
3.启动虚拟机。启动的方法start是父类AndroidRuntime的方法。注意第一个传参的参数。

zygote启动方法在AndroidRuntime中,进入观摩下。

AndroidRuntime

frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...
    
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL); //加载libart.so
    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;
    }

    ...
    
    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 {
          env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    
    ...
    
}

start方法中,主要做了四件事:

1.加载libart.so,否则不能启动虚拟机;
2.启动虚拟机;
3.加载注册JNI方法;
4.根据传递给start方法的第一个参数,去寻找ZygoteInit类,找到类之后,找到该类的main方法,然后调用,在这之后就进入了Java的世界。

start方法的第一个参数为"com.android.internal.os.ZygoteInit",然后通过FindClass方法找到ZygoteInit类,然后再调用相应的main方法进入到Java世界。

ZygoteInit

到了这里,就已经进入到了Java的世界,虚拟机已经运行起来,接下来要做的事就是启动system_server,然后做好自己的本分,等待孵化app的指令。具体详见main方法:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {

    ...
    
    if (startSystemServer) {
        Runnable r = forkSystemServer(abiList, socketName, 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.
    caller = zygoteServer.runSelectLoop(abiList);
    
    if (caller != null) {
        caller.run();
    }
    ...

}

主要做了三件事:

1.解析参数;
2.fork system_server;
3.调用runSelectLoop方法,等待进程孵化请求;

每个main方法一定会做的事情,那就是解析传入给它的参数,这里主要解析了start_system_server的创建需求,这个参数事从init.rc中传下来的。如果init.rc中有创建的system_server的需求,那么就会在这里被解析,然后进行创建。zygote在完成了system_server的创建后,调用runSelectLoop方法进行等待,响应app进程的创建请求,创建成功后,再调用run方法执行。

结语

zygote的启动分析到此结束,到了这里,zygote就一直等待进程的创建请求,app想要启动的时候,就由ams通过socket发需求给zygote就好。

每一次的源码阅读,都有种【自己很渺小】的感觉。对自己来讲,对Android源码的每一次阅读,就是一次揭秘的过程。但每一次阅读完,都会产生新的疑问,比如app的启动流程是怎么样的?ams又是跟zygote怎样创建联系的?

但正是这些疑问驱使我去阅读源码,去了解个中奥妙。

最后

我在微信公众号也有写文章,更新比较及时,有兴趣者可以扫描如下二维码,或者微信搜索【Android系统实战开发】,关注有惊喜哦!

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章