Android 6.0 系統學習之 Zygote

jopen 9年前發布 | 24K 次閱讀 Android Android開發 移動開發

一次看到 Zygote 時,不明白這個名字什么意思,查了一下發現是受精卵的意思。Zygote 是 Android 系統中啟動應用程序與系統服務的服務。

學習 Zygote 這個服務,我想弄明白這些問題:

  1. Zygote 自己是由誰啟動的?
  2. Zygote 都能啟動哪些東西?
  3. Zygote 是如何啟動其他程序、服務的?
  4. </ol>

    現有資源

    現有的關于 Zygote 的文章已有很多。但是紙上得來終覺淺,絕知此事要孤行。前輩分享的知識,吃透理解后,沉淀成自己的東西才算是自己的。

    在這篇文章中,我主要學習了鄧凡平的《Android深入淺出之Zygote》老羅的《Android系統進程Zygote啟動過程的源代碼分析》。感謝這些前輩的無私奉獻,它們的努力,使我在后來的學習中減少了許多困難。

    誰負責啟動 Zygote?

    既然 Zygote 負責啟動 Android 系統的各個部分,我的第一個問題是它自己是如何自舉的?

    Android 以 Linux 為核心,這個問題交給了 Linux。init 程序 Linux 中負責載入 Linux 各個部分的程序,它在成功加載 Linux 系統后,按照 Android 啟動腳本 init.rc 文件中的配置,加載 Zygote。

    配置文件在 Android 6.0 代碼中位于 system/core/rootdir/init.zygote32.rc,具體內容為:

    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
        class main
        socket zygote stream 660 root system
        onrestart write /sys/android_power/request_state wake
        onrestart write /sys/power/state on
        onrestart restart media
        onrestart restart netd

    其中:

    1. 關鍵字 service 表示告訴 init 進程創建名為 zygote 的進程,所要執行的程序是 /system/bin/app_process,后面的都是傳遞的參數。
    2. 注意參數 --start-system-server,說明要啟動 SystemServer
    3. socket zygote stream 660 root system 表示創建名為 zygote 的 socket。
    4. 后面的 onrestart 關鍵字表示 zygote 進程重啟時所需執行的命令。
    5. </ol>

      Zygote 的啟動

      從中我們可以得出結論: zygote 只是服務的名稱,與此服務對應的程序是 app_process 程序,我們研究 zygote 的實現,就是要研究 app_process 程序。

      app_process 程序

      app_process 代碼位于 frameworks/base/cmds/app_process/app_main.cpp,入口函數為 main。將 main 函數的主要邏輯抽象出來:

      int main(int argc, char* const argv[])
      {
          ...
          AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
          ...
          // 解析參數,設置 Flag...
          ...
          if (zygote) {
              runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
          } else if (className) {
              runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
          } else {
              ...
              return 10;
          }
      }

      main 的大體流程為:

      1. 創建一個 AppRuntime 實例 runtime
      2. 解析傳入的命令行參數
      3. 判斷調用哪一個 runtime.start,傳入對應的參數
      4. </ol>

        由于 init.zygote32.rc 中傳入參數 -Xzygote /system/bin --zygote --start-system-server,因此將執行:

        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

        由此可知,app_process 沒干什么主要的事情,只是跳轉到 Java 類 com.android.internal.os.ZygoteInit,看來工作都在 ZygoteInit 中完成。

        在跳到 ZygoteInit 之前,先來看看 app_process 中用到的 AppRuntime。

        AndroidRuntime

        start 方法來自于 AppRuntime 的父類 AndroidRuntime,代碼位于 frameworks/base/core/jni/AndroidRuntime.cpp。來看 start 方法 (在 6.0 代碼中位于 1007 行):

        /*

        • Start the Android runtime. This involves starting the virtual machine
        • and calling the "static void main(String[] args)" method in the class
        • named by "className".
        • 啟動 Android 運行時。這包括啟動虛擬機和調用 "className" 對應的類
        • 的 "static void main(String[] args)" 方法。 *
        • Passes the main function two arguments, the class name and the specified
        • options string.
        • 將會向指定類的 main 函數傳入兩個參數,也就是 start 函數的 className
        • 和 options / void AndroidRuntime::start(const char className, const Vector<String8>& options, bool zygote) { ... / start the virtual machine / JniInvocation jni_invocation; jni_invocation.Init(NULL); 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; }

            ...

            /*

          • Start VM. This thread becomes the main thread of the VM, and will
          • not return until the VM exits. / char slashClassName = toSlashClassName(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);

        if 0

                if (env->ExceptionCheck())
                    threadExitUncaughtException(env);
        

        endif

            }
        }
        free(slashClassName);
        ...
        

        }</pre>

        AndroidRuntime 的 runtime 主要做了三件事:

        首先是創建虛擬機:

        /* start the virtual machine */
        JniInvocation jni_invocation;
        jni_invocation.Init(NULL);
        JNIEnv* env;
        if (startVm(&mJavaVM, &env, zygote) != 0) {
           return;
        }
        onVmCreated(env);

        之后是調用 startReg 函數注冊 JNI 方法:

        /*

        • Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; }</pre>

          最后構建參數、創建 JNI 類對象,獲取 main 方法,并最終執行下面一行執行 main 入口:

          env->CallStaticVoidMethod(startClass, startMeth, strArray);

          這樣我們就成功從 C 中啟動了一個虛擬機,并加載了 Java 類 ZygoteInit,并進入到它的 main 方法中執行。

          ZygoteInit

          之后就來到了 ZygoteInit.java 的 main 方法,代碼位于 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java。來看其 main 方法:

          public static void main(String argv[]) {
           try {

           ...
           registerZygoteSocket(socketName);
           ...
           if (startSystemServer) {
               startSystemServer(abiList, socketName);
           }
           ...
           runSelectLoop(abiList);
           ...
          

          } catch (...) { ... } }</pre>

          首先,調用 registerZygoteSocket 創建了一個名為 zygote 的 socket:

          registerZygoteSocket(socketName);

          之后啟動 SystemServer 組件:

          if (startSystemServer) {
          startSystemServer(abiList, socketName);
          }

          最后調用 runSelectLoopMode 進入一個死循環,等待接受 socket 上由 ActivityManagerService 發來的請求創建應用程序的請求:

          runSelectLoop(abiList);

          下面我們就對后兩個步驟詳細分析。

          一、啟動 SystemServer 組件

          SystemServer 名為系統服務進程,負責啟動 Android 系統的關鍵服務。來看看函數的主要實現:

          private static boolean startSystemServer(String abiList, String socketName)

           throws MethodAndArgsCaller, RuntimeException {
          

          ... / Request to fork the system server process / pid = Zygote.forkSystemServer(

            parsedArgs.uid, parsedArgs.gid,
            parsedArgs.gids,
            parsedArgs.debugFlags,
            null,
            parsedArgs.permittedCapabilities,
            parsedArgs.effectiveCapabilities);
          

          ... / For child process / if (pid == 0) {

            ...
            handleSystemServerProcess(parsedArgs);
          

          } return true; }</pre>

          首先調用了 Zygote 的靜態方法 forkSystemServer 來創建 SystemServer 進程。這也是我首次看到 Zygote 是如何孵♂化出東西來的。

          我們進入 forkSystemServer 看看具體實現:

          public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,

           int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
          

          ... int pid = nativeForkSystemServer(

               uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
          

          ... return pid; }</pre>

          可見,這又調用了 nativeForkSystemServer,這是一個 jni 調用,對應的函數為 com_android_internal_os_Zygote_nativeForkSystemServer,位于:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp,來看看它的實現:

          static jint com_android_internal_os_Zygote_nativeForkSystemServer(

            JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
            jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
            jlong effectiveCapabilities) {
          

          pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,

                                          debug_flags, rlimits,
                                          permittedCapabilities, effectiveCapabilities,
                                          MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                          NULL, NULL);
          

          ... return pid; }</pre>

          在這里調用了 ForkAndSpecializeCommon 函數,它是一個靜態函數,用來 fork Zygote 并設置子進程。代碼比較多,看看它的主要實現:

          static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,

                                         jint debug_flags, jobjectArray javaRlimits,
                                         jlong permittedCapabilities, jlong effectiveCapabilities,
                                         jint mount_external,
                                         jstring java_se_info, jstring java_se_name,
                                         bool is_system_server, jintArray fdsToClose,
                                         jstring instructionSet, jstring dataDir) {
          

          ... pid_t pid = fork(); if (pid == 0) { ... // 對子線程進行了一大堆設置 ... } return pid; }</pre>

          首先,執行 fork() 創建了一個子進程。在子進程中進行了一大堆設置。

          跳了這么一大堆,來梳理一下。啟動 SystemServer,首先要創建一個新進程,可我們現在在 Java 中,需要會到 C 中進行 fork(),我們通過 forkSystemServer - com_android_internal_os_Zygote_nativeForkSystemServer - ForkAndSpecializeCommon 來實現 JNI 調用并成功 fork,這樣新進程就有了。

          讓我們回到本節的一開始的 startSystemServer,現在子進程已經創建好了,接著往下看。在創建的子進程中,有一句 handleSystemServerProcess(parsedArgs),進入看看實現:

          /**

          • Finish remaining work for the newly forked system server process. */ private static void handleSystemServerProcess(

             ZygoteConnection.Arguments parsedArgs)
             throws ZygoteInit.MethodAndArgsCaller {
            

            ... final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); ... if (...) { ... } else { ClassLoader cl = null; if (systemServerClasspath != null) { cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader()); Thread.currentThread().setContextClassLoader(cl); }

            /*

            • Pass the remaining arguments to SystemServer. / RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); }</pre>

              從中可以看出,我們從環境變量 SYSTEMSERVERCLASSPATH 拿到 SystemServer 的類名,之后載入進來,最后使用 RuntimeInit.zygoteInit 來運行,它來執行 SystemServer 的 main 方法。

              RuntimeInit.zygoteInit 的具體實現可以簡單看一下:

              public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
              throws ZygoteInit.MethodAndArgsCaller {
              ...
              commonInit();   // 基本設置(異常捕獲、時區、HTTP User-Agent 等)
              nativeZygoteInit();
              applicationInit(targetSdkVersion, argv, classLoader); // 調用 Main 方法
              }

              其中 nativeZygoteInit() 是一個 jni 調用,位于 AndroidRuntime.cpp:

              static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv env, jobject clazz)
              {
              gCurRuntime->onZygoteInit();
              }</pre> 

              onZygoteInit() 是 AppRuntime 中的方法,具體為:

              virtual void onZygoteInit()
              {
              sp<ProcessState> proc = ProcessState::self();
              ALOGV("App process: starting thread pool.\n");
              proc->startThreadPool();
              }

              可見是啟動了一個線程池。nativeZygoteInit() 就分析到這里,由此可見,Zygote 啟動 SystemServer 的過程就算完了,之后的,都是 SystemServer 內部的事情了。

              二、runSelectLoop

              下面看看 runSelectLoop 的實現。

              /**
        • Runs the zygote process's select loop. Accepts new connections as
        • they happen, and reads commands from connections one spawn-request's
        • worth at a time.
        • 運行 zygote 進程的 select 循環。接受新的連接,讀取指令。 *
        • @throws MethodAndArgsCaller in a child process when a main() should
        • be executed.
        • 如果有 main() 需要被執行,拋出 MethodAndArgsCaller 異常。 */ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

          fds.add(sServerSocket.getFileDescriptor()); peers.add(null);

          while (true) {

           StructPollfd[] pollFds = new StructPollfd[fds.size()];
           for (int i = 0; i < pollFds.length; ++i) {
               pollFds[i] = new StructPollfd();
               pollFds[i].fd = fds.get(i);
               pollFds[i].events = (short) POLLIN;
           }
           try {
               Os.poll(pollFds, -1);
           } catch (...) {
               ...
           }
           for (int i = pollFds.length - 1; i >= 0; --i) {
               if ((pollFds[i].revents & POLLIN) == 0) {
                   continue;
               }
               if (i == 0) {
                   ZygoteConnection newPeer = acceptCommandPeer(abiList);
                   peers.add(newPeer);
                   fds.add(newPeer.getFileDesciptor());
               } else {
                   boolean done = peers.get(i).runOnce();
                   if (done) {
                       peers.remove(i);
                       fds.remove(i);
                   }
               }
           }
          

          } }</pre>

          首先獲取 socket 并加入到 fds 中:

          fds.add(sServerSocket.getFileDescriptor());

          之后執行:

          Os.poll(pollFds, -1);

          poll 會判斷 pollFds 是否可讀,若不可讀則阻塞等待。

          之后進入 for 循環:

          for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {

            continue;
          

          } if (i == 0) {

            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
          

          } else {

            boolean done = peers.get(i).runOnce();
            if (done) {
                peers.remove(i);
                fds.remove(i);
            }
          

          } }</pre>

          首先看是否已經在處理隊列中,若已在,則處理下一個。之后看新加的(最后一個又是未處理,那就是新家的),那就解析參數加進去。最后,對于已經加入的,判斷一下是否完成,完成了就從列表中刪除。

          注意,這些代碼都套在 while(true) 死循環里,這個 poll 的過程會一直進行。

          由此可見,Zygote 到這里就算啟動完了,并進入了一個死循環,要想啟動個東西,就從 socket 向它發指令,他就會孵♂化。

          至此,我關于 Zygote 的疑問基本搞明白了。本文對于 Zygote 的機制挖掘并不很深,對于 Zygote 的底層操作也沒有挖掘徹底。我想,對于了解來說,已經足夠了。

          來自:http://www.judymax.com/archives/1118

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!