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系統實戰開發】,關注有驚喜哦!

在這裏插入圖片描述

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