Android系統(tǒng)啟動(dòng)-Zygote進(jìn)程

本篇文章基于Android6.0源碼分析

相關(guān)源碼文件:

/system/core/rootdir/init.rc
/system/core/rootdir/init.zygote64.rc

/frameworks/base/cmds/app_process/App_main.cpp
/frameworks/base/core/jni/AndroidRuntime.cpp

/frameworks/base/core/java/com/android/internal/os/
- ZygoteInit.java
- Zygote.java
- ZygoteConnection.java

/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp

Zygote進(jìn)程啟動(dòng)前的概述

通過(guò)init.rc的文件解析會(huì)啟動(dòng)zygote相關(guān)的服務(wù)從而啟動(dòng)zygote進(jìn)程。通過(guò)import導(dǎo)入決定啟動(dòng)哪種類(lèi)型的zygote服務(wù)腳本,這里分為32位和64位架構(gòu)的zygote服務(wù)腳本

import /init.${ro.zygote}.rc

在/system/core/rootdir目錄中有四個(gè)zygote相關(guān)的服務(wù)腳本

init.zygote32.rc // 支持32位的zygote
init.zygote32_64.rc // 即支持32位也支持64位的zygote,其中以32位為主,64位為輔
init.zygote64.rc // 支持64位的zygote
init.zygote64_32.rc // 即支持64位也支持32位的zygote,其中以64位為主,32位為輔

下面我們分析只分析64位的zygote服務(wù)腳本的Android初始化語(yǔ)言:

service zygote /system/bin/app_process64 -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
 writepid /dev/cpuset/foreground/tasks

zygote進(jìn)程的執(zhí)行程序?yàn)?code>/system/bin/app_process64中,其中參數(shù)為:-Xzygote /system/bin --zygote --start-system-server,classname為main。除了在Init進(jìn)程解析時(shí)創(chuàng)建Zygote進(jìn)程,在servicemanager、surfaceflinger、systemserver進(jìn)程被殺時(shí)Zygote進(jìn)程也會(huì)進(jìn)行重啟。

其中/system/bin/app_process64的映射的執(zhí)行文件為:/frameworks/base/cmds/app_process/app_main.cpp

Zygote進(jìn)程啟動(dòng)

圖1 zygote執(zhí)行流程

如圖1所示,zygote進(jìn)程啟動(dòng)時(shí)會(huì)先啟動(dòng)app_main類(lèi)的main()方法:

  // 參數(shù)argv為 :  -Xzygote /system/bin --zygote --start-system-server
  int main(int argc, char* const argv[])
  {
      // 創(chuàng)建一個(gè)AppRuntime實(shí)例,AppRuntime 繼承 AndoirdRuntime
      AppRuntime runtime (argv[0], computeArgBlockSize(argc, argv));
      //忽略第一個(gè)參數(shù)
      argc--;
      argv++;

  
      // 解析參數(shù)并對(duì)變量賦值
      bool zygote = false;
      bool startSystemServer = false;
      bool application = false;
      String8 niceName;
      String8 className;

      ++i;  // Skip unused "parent dir" argument.
      while (i < argc) {
          const char * arg = argv [i++];
          if (strcmp(arg, "--zygote") == 0) {
               // 參數(shù)中有--zygote
              zygote = true;
              niceName = ZYGOTE_NICE_NAME;
          } else if (strcmp(arg, "--start-system-server") == 0) {
              // 參數(shù)中有--start-system-server
              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) {
         //如果zygote為true,則調(diào)用AndroidRuntime的start方法,并傳入了"com.android.internal.os.ZygoteInit"參數(shù)
         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
      } else if (className) {
          runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
      } else {
          fprintf(stderr, "Error: no class name or --zygote supplied.\n");
          app_usage();
          LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
          return 10;
      }
  }

在app_main的mian()方法中,主要是根據(jù)zygote的腳本的參數(shù)進(jìn)行解析,在解析到有--zygote字符后,則確定執(zhí)行AndroidRuntime.start方法,并且第一個(gè)參數(shù)傳為com.android.internal.os.ZygoteInit

AndroidRuntime.start()

在此方法中,主要做了三件事:
· 創(chuàng)建虛擬機(jī)實(shí)例
· JNI方法的注冊(cè)
· 調(diào)用參數(shù)的main()方法

  // 這里的className為:com.android.internal.os.ZygoteInit
  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;
       // 1. 創(chuàng)建虛擬機(jī)
      if (startVm(& mJavaVM, &env, zygote) != 0) {
      return;
       }
      onVmCreated(env);
      // 2. JNI方法注冊(cè)
      if (startReg(env) < 0) {
          ALOGE("Unable to register all android natives\n");
          return;
      }

      // 解析classname參數(shù)
     //將"com.android.internal.os.ZygoteInit"轉(zhuǎn)換為"com/android/internal/os/ZygoteInit"
      char * slashClassName = toSlashClassName(className);
      jclass startClass = env->FindClass(slashClassName);

      if (startClass == NULL) {
      } else {
          //  得到ZygoteInit的main方法
          jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
          "([Ljava/lang/String;)V");
          if (startMeth == NULL) {
          } else { env ->
                // 3. 執(zhí)行ZygoteInit的main方法
              CallStaticVoidMethod(startClass, startMeth, strArray);
          }
      }
      free(slashClassName);

  }

對(duì)start方法進(jìn)行了一些刪減后,主要是通過(guò)startVm創(chuàng)建虛擬機(jī),通過(guò)startReg(env)進(jìn)行JNI方法注冊(cè),最后解析className參數(shù),去執(zhí)行ZygoteInit.main方法。下面將逐一分析這三種狀態(tài)。

1. 創(chuàng)建虛擬機(jī)實(shí)例

startVm

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
  {
      // ... 
      // JNI檢測(cè)功能
      bool checkJni = false;
      property_get("dalvik.vm.checkjni", propBuf, "");
      if (strcmp(propBuf, "true") == 0) {
          checkJni = true;
      } else if (strcmp(propBuf, "false") != 0) {
          /* property is neither true nor false; fall back on kernel parameter */
          property_get("ro.kernel.android.checkjni", propBuf, "");
          if (propBuf[0] == '1') {
              checkJni = true;
          }
      }
      ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
      if (checkJni) {
          addOption("-Xcheck:jni");
      }

       // /虛擬機(jī)產(chǎn)生的trace文件,主要用于分析系統(tǒng)問(wèn)題,路徑默認(rèn)為/data/anr/traces.txt
      parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");

      //對(duì)于不同的軟硬件環(huán)境,這些參數(shù)往往需要調(diào)整、優(yōu)化,從而使系統(tǒng)達(dá)到最佳性能
      parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
      parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");

      parseRuntimeOption(
          "dalvik.vm.heapgrowthlimit",
          heapgrowthlimitOptsBuf,
          "-XX:HeapGrowthLimit="
      );
      parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
      parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
      parseRuntimeOption(
          "dalvik.vm.heaptargetutilization",
          heaptargetutilizationOptsBuf,
          "-XX:HeapTargetUtilization="
      );
      // ...
      // 初始化虛擬機(jī)
      if (JNI_CreateJavaVM(pJavaVM, pEnv, & initArgs) < 0) {
      ALOGE("JNI_CreateJavaVM failed\n");
      return -1;
  }

      return 0;
  }

startVm方法里面有很多代碼,但主要分為三步,第一步是檢測(cè),第二步是軟硬件參數(shù)的設(shè)置,第三步是初始化虛擬機(jī)。

2. JNI方法的注冊(cè)

startReg

  int AndroidRuntime::startReg(JNIEnv* env)
  {
      androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

      ALOGV("--- registering native functions ---\n");
      env->PushLocalFrame(200);
      //進(jìn)程JNI方法的注冊(cè)
      if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { env ->
          PopLocalFrame(NULL);
          return -1;
      }
      env->PopLocalFrame(NULL);
      return 0;
  }

  // 這里的array[]是gRegJNI,它是一個(gè)映射了很多方法的數(shù)組
  static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
  {
      // 執(zhí)行很多映射的方法
      for (size_t i = 0; i < count; i++) {
      if (array[i].mProc(env) < 0) {
          return -1;
      }
  }
      return 0;
  }

startReg方法是對(duì)JNI方法的注冊(cè),它通過(guò)一個(gè)有很多宏定義的數(shù)組,并執(zhí)行數(shù)組定義的方法,進(jìn)行對(duì)JNI和Java層方法一一映射。

3. 調(diào)用ZygoteInit.main方法

在AndroidRuntime.start()方法的最后,通過(guò)反射執(zhí)行了其ZygoteInit.main()方法。

    if (startClass == NULL) {
    } else {
        //  得到ZygoteInit的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
        "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
        } else { env ->
              // 3. 執(zhí)行ZygoteInit的main方法
            CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }

通過(guò)反射去執(zhí)行ZygoteInit.main方法,也是第一次進(jìn)入java語(yǔ)言的世界。所以AndroidRuntime的start方法做了三件事,一是初始化虛擬機(jī),二是JNI方法的注冊(cè),三是通過(guò)反射執(zhí)行ZygoteInit.main方法。

ZygoteInit.main

Zygote進(jìn)程用于創(chuàng)建管理framework層的SystemServer進(jìn)程,還用于創(chuàng)建App進(jìn)程,就是應(yīng)用App啟動(dòng)創(chuàng)建進(jìn)程時(shí),是由Zygote進(jìn)程創(chuàng)建的,并且Zygote創(chuàng)建子進(jìn)程將使用copy on write的技術(shù),就是子進(jìn)程直接繼承父進(jìn)程的現(xiàn)有的資源,在子進(jìn)程對(duì)于共有的資源是讀時(shí)共享,寫(xiě)時(shí)復(fù)制
ZygoteInit.main方法中主要做了四件事:
· 注冊(cè)服務(wù)端的socket,用于接收創(chuàng)建子進(jìn)程的信息
· 提前預(yù)加載類(lèi)和資源,用于子進(jìn)程共享
· 創(chuàng)建SystemServer進(jìn)程,其管理著framework層
· 循環(huán)監(jiān)聽(tīng)服務(wù)socket,創(chuàng)建子進(jìn)程

  public static void main(String argv[])
  {
      try {
          // 創(chuàng)建服務(wù)端Soctet,用于接收創(chuàng)建子進(jìn)程信息
          registerZygoteSocket(socketName);
         // 提前預(yù)加載類(lèi)和資源
          preload();
          // gc操作
          gcAndFinalize();
          // 創(chuàng)建SystemServer進(jìn)程
          if (startSystemServer) {
              startSystemServer(abiList, socketName);
          }
         // 用服務(wù)socket監(jiān)聽(tīng)創(chuàng)建進(jìn)程信息,并創(chuàng)建子進(jìn)程
          runSelectLoop(abiList);

          closeServerSocket();
      } catch (MethodAndArgsCaller caller) {
          caller.run();
      } catch (RuntimeException ex) {
          Log.e(TAG, "Zygote died with exception", ex);
          closeServerSocket();
          throw ex;
      }
  }

通過(guò)registerZygoteSocket方法去創(chuàng)建服務(wù)端的socket,preload()方法去提前加載類(lèi)和資源,startSystemServer方法去創(chuàng)建SystemServer進(jìn)程去管理framework層,runSelectLoop方法循環(huán)監(jiān)聽(tīng)創(chuàng)建子進(jìn)程。

1. 注冊(cè)服務(wù)端Socket

registerZygoteSocket

  private static void registerZygoteSocket(String socketName)
  {
      if (sServerSocket == null) {
          int fileDesc;
          final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
          try {
              String env = System . getenv (fullSocketName);
              fileDesc = Integer.parseInt(env);
          } catch (RuntimeException ex) {
              throw new RuntimeException (fullSocketName + " unset or invalid", ex);
          }

          try {
               // 創(chuàng)建服務(wù)端的socket
              FileDescriptor fd = new FileDescriptor();
              fd.setInt$(fileDesc);
              sServerSocket = new LocalServerSocket (fd);
          } catch (IOException ex) {
              throw new RuntimeException (
                      "Error binding to local socket '" + fileDesc + "'", ex);
          }
      }
  }

創(chuàng)建一個(gè)服務(wù)端的socket用于接口多個(gè)客戶(hù)端的信息接收,在后面的runSelectLoop方法用于監(jiān)聽(tīng)服務(wù)端的socket信息,以便創(chuàng)建子進(jìn)程。

2. 預(yù)加載資源

preload

  static void preload()
  {
      preloadClasses();  //預(yù)加載位于/system/etc/preloaded-classes文件中的類(lèi)
      preloadResources();  //預(yù)加載資源,包含drawable和color資源
      preloadOpenGL(); //預(yù)加載OpenGL 
      preloadSharedLibraries(); //預(yù)加載"android","compiler_rt","jnigraphics"這3個(gè)共享庫(kù)
      preloadTextResources(); //預(yù)加載 文本連接符資源
      WebViewFactory.prepareWebViewInZygote(); //僅用于zygote進(jìn)程,用于內(nèi)存共享的進(jìn)程
  }

preloadClasses()方法通過(guò)Class.forName()反射的方法去加載類(lèi),preloadResources方法主要是加載位于com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists的資源。
提前加載資源的好處是,在復(fù)制創(chuàng)建子進(jìn)程時(shí),提前加載好的資源可以給子進(jìn)程直接使用,不用第二次創(chuàng)建,但不好的地方是每個(gè)創(chuàng)建的子進(jìn)程都有擁有很多資源,而不管是否需要。

3. 啟動(dòng)SystemServer進(jìn)程

startSystemServer

  private static boolean startSystemServer(String abiList, String socketName)
  throws MethodAndArgsCaller, RuntimeException
  {
      // 通過(guò)數(shù)組保存創(chuàng)建systemserver進(jìn)程的信息
      String args [] = {
          "--setuid=1000",
          "--setgid=1000",
          "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
          "--capabilities=" + capabilities + "," + capabilities,
          "--nice-name=system_server",
          "--runtime-args",
          "com.android.server.SystemServer",
      };
      ZygoteConnection.Arguments parsedArgs = null;

      int pid;

      try {
          parsedArgs = new ZygoteConnection . Arguments (args);
          ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
          ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

          // 創(chuàng)建systemserver進(jìn)程
          pid = Zygote.forkSystemServer(
              parsedArgs.uid, parsedArgs.gid,
              parsedArgs.gids,
              parsedArgs.debugFlags,
              null,
              parsedArgs.permittedCapabilities,
              parsedArgs.effectiveCapabilities
          );
      } catch (IllegalArgumentException ex) {
          throw new RuntimeException (ex);
      }

      /* pid==0 則是子進(jìn)程,就是systemserver */
      if (pid == 0) {
          if (hasSecondZygote(abiList)) {
              waitForSecondaryZygote(socketName);
          }

          // 完成system_server進(jìn)程剩余的工作
          handleSystemServerProcess(parsedArgs);
      }

      return true;
  }

通過(guò)Zygote.forkSystemServer去創(chuàng)建SystemServer進(jìn)程,其進(jìn)程是管理著framework的,我們將在下一篇分析SystemServer進(jìn)程進(jìn)程的啟動(dòng)。

4. 循環(huán)等待孵化進(jìn)程

runSelectLoop

  private static void runSelectLoop(String abiList) throws MethodAndArgsCaller
  {
      // FileDescriptor數(shù)組
      ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
       // ZygoteConnection數(shù)組
      ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
      //sServerSocket是socket通信中的服務(wù)端,即zygote進(jìn)程。保存到fds[0]
      fds.add(sServerSocket.getFileDescriptor());
      peers.add(null);

      while (true) {
          // StructPollfd數(shù)組,并將相應(yīng)位置fds的值賦值
          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 {
               //處理輪詢(xún)狀態(tài),當(dāng)pollFds有事件到來(lái)則往下執(zhí)行,否則阻塞在這里
              Os.poll(pollFds, -1);
          } catch (ErrnoException ex) {
              throw new RuntimeException ("poll failed", ex);
          }
          for (int i = pollFds.length - 1; i >= 0; --i) {

              //采用I/O多路復(fù)用機(jī)制,當(dāng)接收到客戶(hù)端發(fā)出連接請(qǐng)求 或者數(shù)據(jù)處理請(qǐng)求到來(lái),則往下執(zhí)行;
             // 否則進(jìn)入continue,跳出本次循環(huán)。
              if ((pollFds[i].revents & POLLIN) == 0) {
              continue;
             }
              if (i == 0) {
                  ZygoteConnection newPeer = acceptCommandPeer (abiList);
                  peers.add(newPeer);
                  fds.add(newPeer.getFileDesciptor());
              } else {
                   //i>0,則代表通過(guò)socket接收來(lái)自對(duì)端的數(shù)據(jù),并執(zhí)行相應(yīng)操作
                  boolean done = peers.get (i).runOnce();
                  if (done) {
                      peers.remove(i);
                      fds.remove(i);
                  }
              }
          }
      }
  }

在runSelectLoop方法中有一個(gè)輪詢(xún)的狀態(tài),如果有事件接收則會(huì)去執(zhí)行runOnce()的方法操作:

  boolean runOnce() throws ZygoteInit.MethodAndArgsCaller
  {

      String args [];
      Arguments parsedArgs = null;
      FileDescriptor[] descriptors;

      try {
          //讀取socket客戶(hù)端發(fā)送過(guò)來(lái)的參數(shù)列表
          args = readArgumentList();
          descriptors = mSocket.getAncillaryFileDescriptors();
      } catch (IOException ex) {
          Log.w(TAG, "IOException on command socket " + ex.getMessage());
          closeSocket();
          return true;
      }

      if (args == null) {
          // EOF reached.
          closeSocket();
          return true;
      }

   
      try {
           //將binder客戶(hù)端傳遞過(guò)來(lái)的參數(shù),解析成Arguments對(duì)象格式
          parsedArgs = new Arguments (args);
          ...
         // fork創(chuàng)建一個(gè)新的進(jìn)程
          pid = Zygote.forkAndSpecialize(
              parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
              parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
              parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
              parsedArgs.appDataDir
          );
      } catch (ErrnoException ex) {
          logAndPrintError(newStderr, "Exception creating pipe", ex);
      } catch (IllegalArgumentException ex) {
          logAndPrintError(newStderr, "Invalid zygote arguments", ex);
      } catch (ZygoteSecurityException ex) {
          logAndPrintError(
              newStderr,
              "Zygote security policy prevents request: ", ex
          );
      }

      try {
          if (pid == 0) {
             // 處理子進(jìn)程
              IoUtils.closeQuietly(serverPipeFd);
              serverPipeFd = null;
              handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

              // should never get here, the child is expected to either
              // throw ZygoteInit.MethodAndArgsCaller or exec().
              return true;
          } else {
              // 父進(jìn)程
              IoUtils.closeQuietly(childPipeFd);
              childPipeFd = null;
              return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
          }
      } finally {
          IoUtils.closeQuietly(childPipeFd);
          IoUtils.closeQuietly(serverPipeFd);
      }
  }

所以在runSelectLoop方法中,通過(guò)客戶(hù)端的socket不斷的和服務(wù)端的socket通信的監(jiān)聽(tīng),通過(guò)調(diào)用起runOnce方法去不斷的創(chuàng)建新的進(jìn)程。

總結(jié)

Zygote進(jìn)程的啟動(dòng)過(guò)程主要有:

  1. 創(chuàng)建虛擬機(jī)和JNI方法的注冊(cè)
  2. 注冊(cè)服務(wù)Socket和提前加載系統(tǒng)類(lèi)和資源
  3. 創(chuàng)建SystemServce進(jìn)程
  4. 循環(huán)等待孵化進(jìn)程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容