当前位置:   article > 正文

Android 8.1 zygote创建新应用进程_startzygotenothreadcreation

startzygotenothreadcreation

Android 8.1 zygote创建新应用进程

涉及到的文件以及路径:

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

分析过Android系统启动流程的同学都知道,zygote启动之后,会调用ZygoteInit.java中的main函数。

ZygoteInit.java的路径: frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

这个main函数如下:

  1. public static void main(String argv[]) {
  2. // 创建一个ZygoteServer 对象,这个是8.0 之后才有的
  3. // 这个就是zygote最后等待ActivityManager 连接来 fork新进程的地方
  4. ZygoteServer zygoteServer = new ZygoteServer();
  5. // Mark zygote start. This ensures that thread creation will throw
  6. // an error.
  7. // 调用native函数,确保当前没有其它线程在运行
  8. // 主要还是处于安全的考虑
  9. // 启动无多线程模式 .当在zygoteInit中新建线程系统挂掉
  10. // 主要是由于担心用户新建线程提高预加载速度
  11. // 但是可能没做好同步工作, 当有的应用需要预加载的资源,但是多线程情况下还没有加载,发生问题
  12. ZygoteHooks.startZygoteNoThreadCreation();
  13. // Zygote goes into its own process group.
  14. // 指定当前进程的id(第一个参数是目标进程id,第二个参数是进程组id,把第二个参数设置成第一个的值)
  15. try {
  16. Os.setpgid(0, 0);
  17. } catch (ErrnoException ex) {
  18. throw new RuntimeException("Failed to setpgid(0,0)", ex);
  19. }
  20. final Runnable caller;
  21. try { // 解析上面传递过来的参数
  22. // Report Zygote start time to tron unless it is a runtime restart
  23. if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { // 如果是重启sys.boot_completed值是1
  24. //上报Zygote进程启动的时间
  25. MetricsLogger.histogram(null, "boot_zygote_init",(int) SystemClock.elapsedRealtime());
  26. }
  27. String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
  28. TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);
  29. bootTimingsTraceLog.traceBegin("ZygoteInit");
  30. RuntimeInit.enableDdms();
  31. boolean startSystemServer = false; // 是否启动 SystemServer
  32. String socketName = "zygote"; // 创建的socket的名称
  33. String abiList = null; // 支持的so库的类型
  34. boolean enableLazyPreload = false; // 这个尚不清楚,不过传递过来的参数中没有这个
  35. for (int i = 1; i < argv.length; i++) {
  36. if ("start-system-server".equals(argv[i])) {
  37. startSystemServer = true;
  38. } else if ("--enable-lazy-preload".equals(argv[i])) {
  39. enableLazyPreload = true;
  40. } else if (argv[i].startsWith(ABI_LIST_ARG)) {
  41. abiList = argv[i].substring(ABI_LIST_ARG.length());
  42. } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
  43. socketName = argv[i].substring(SOCKET_NAME_ARG.length());
  44. } else {
  45. throw new RuntimeException("Unknown command line argument: " + argv[i]);
  46. }
  47. }
  48. if (abiList == null) {
  49. throw new RuntimeException("No ABI list supplied.");
  50. }
  51. zygoteServer.registerServerSocket(socketName); // 注册server socket
  52. // In some configurations, we avoid preloading resources and classes eagerly.
  53. // In such cases, we will preload things prior to our first fork.
  54. if (!enableLazyPreload) {
  55. bootTimingsTraceLog.traceBegin("ZygotePreload");
  56. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
  57. SystemClock.uptimeMillis());
  58. preload(bootTimingsTraceLog);
  59. EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
  60. SystemClock.uptimeMillis());
  61. bootTimingsTraceLog.traceEnd(); // ZygotePreload
  62. } else {
  63. Zygote.resetNicePriority();
  64. }
  65. // Do an initial gc to clean up after startup
  66. bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
  67. gcAndFinalize();
  68. bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
  69. bootTimingsTraceLog.traceEnd(); // ZygoteInit
  70. // Disable tracing so that forked processes do not inherit stale tracing tags from
  71. // Zygote.
  72. Trace.setTracingEnabled(false, 0);
  73. // Zygote process unmounts root storage spaces.
  74. // // 卸载root的存储空间
  75. Zygote.nativeUnmountStorageOnInit();
  76. // Set seccomp policy
  77. // Set seccomp policy
  78. // 加载seccomp的过滤规则
  79. // 所有 Android 软件都使用系统调用(简称为 syscall)与 Linux 内核进行通信
  80. // 内核提供许多特定于设备和SOC的系统调用,让用户空间进程(包括应用)可以直接与内核进行交互
  81. // 不过,其中许多系统调用Android未予使用或未予正式支持
  82. // 通过seccomp,Android可使应用软件无法访问未使用的内核系统调用
  83. // 由于应用无法访问这些系统调用,因此,它们不会被潜在的有害应用利用
  84. // 该过滤器安装到zygote进程中,由于所有Android应用均衍生自该进程
  85. // 因而会影响到所有应用
  86. Seccomp.setPolicy();
  87. ZygoteHooks.stopZygoteNoThreadCreation(); // 允许有其他线程了
  88. if (startSystemServer) {
  89. Runnable r = forkSystemServer(abiList, socketName, zygoteServer); // 启动SystemServer
  90. // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
  91. // child (system_server) process.
  92. if (r != null) {
  93. r.run(); // 这里会调用到 RuntimeInit.java 中的 MethodAndArgsCaller 的 run方法,来正式进入 SystemServer的main函数
  94. return;
  95. }
  96. }
  97. Log.i(TAG, "Accepting command socket connections");
  98. // The select loop returns early in the child process after a fork and
  99. // loops forever in the zygote.
  100. caller = zygoteServer.runSelectLoop(abiList); // zygote进程进入无限循环,处理请求
  101. } catch (Throwable ex) {
  102. Log.e(TAG, "System zygote died with exception", ex);
  103. throw ex;
  104. } finally {
  105. Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
  106. // 这个地方有两个调用的流程
  107. // 1: zygote 进程退出的时候会调用这个函数,用来关闭zygote自己创建的用来接收ActivityManager的链接请求的socket
  108. // 2:当每个子线程fork完毕,准备好之后,会走到这里,这个时候会在子进程中执行的,这里会调用closeServerSocket函数,确保从zygote集成过来的socket关闭。
  109. // 其实这个时候,因为子进程刚刚fock出来的时候就已经掉用过closeServerSocket函数了,因此再次调用,是没有效果的
  110. zygoteServer.closeServerSocket();
  111. }
  112. // We're in the child process and have exited the select loop. Proceed to execute the
  113. // command.
  114. if (caller != null) {
  115. caller.run(); // 这里才是重点,上面会返回一个Runnable的对象,这个地方调用他的 run函数会进入到子进程的真正的main函数里面
  116. }
  117. }

这个main函数中,首选会创建一个ZygoteServer对象,这个就是用来处理后续zygote socket连接的地方。然后会解析前面传递进来的参数。根据参数决定是否启动SystemServer,启动SystemServer的部分,网上比较多,这里就不做详细介绍了。

  根据代码流程我们会发现,在main函数的最后会调用 caller = zygoteServer.runSelectLoop(abiList);进入到ZygoteServer类的runSelectLoop函数中。下面我们就着重分析下这个函数的具体实现。

  1. /**
  2. * Runs the zygote process's select loop. Accepts new connections as
  3. * they happen, and reads commands from connections one spawn-request's
  4. * worth at a time.
  5. */
  6. Runnable runSelectLoop(String abiList) {
  7. // 记录需要监听的句柄
  8. ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  9. // 记录上面监听的句柄所对应的处理类的实例对象
  10. ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  11. fds.add(mServerSocket.getFileDescriptor());
  12. peers.add(null); // 这里add null 是为了使得它的index 和 fds 的index想对应。
  13. while (true) {
  14. StructPollfd[] pollFds = new StructPollfd[fds.size()];
  15. for (int i = 0; i < pollFds.length; ++i) {
  16. pollFds[i] = new StructPollfd();
  17. pollFds[i].fd = fds.get(i);
  18. pollFds[i].events = (short) POLLIN;
  19. }
  20. try {
  21. Os.poll(pollFds, -1); // 开始进入监听模式 无论是监听到 连接请求还是 数据过来,这个函数都会返回
  22. } catch (ErrnoException ex) {
  23. throw new RuntimeException("poll failed", ex);
  24. }
  25. for (int i = pollFds.length - 1; i >= 0; --i) { // 根据监听到的消息长度,循环处理监听到的所有消息
  26. if ((pollFds[i].revents & POLLIN) == 0) { // 无效消息,跳过
  27. continue;
  28. }
  29. Slog.e(TAG, "runSelectLoop i = "+i+" mIsForkChild = "+mIsForkChild);
  30. if (i == 0) { // 如果 i是0,就说明监听到了连接请求,
  31. // 此时调用 acceptCommandPeer 函数,这个函数会调用 mServerSocket.accept() 接受连接,并返回句柄
  32. // 然后用此句柄为参数创建了 ZygoteConnection 对象,然后由 ZygoteConnection 对象负责这一个连接的后续数据处理
  33. ZygoteConnection newPeer = acceptCommandPeer(abiList);
  34. peers.add(newPeer); // 添加到 peers 这个
  35. fds.add(newPeer.getFileDesciptor()); // 添加到 fds,然后在下次循环的时候,将刚刚接受的链接请求也一同添加到监听
  36. } else { // 如果不是0.那就是上面 i=0的时候接受到的连接发来数据了。
  37. try {
  38. ZygoteConnection connection = peers.get(i); // 从刚刚记录的peers中获取处理对应数据的 ZygoteConnection 类
  39. final Runnable command = connection.processOneCommand(this);
  40. // 因为上面的 processOneCommand 函数调用中,如果创建了新的进程,上面的函数就会有两个返回,
  41. // 第一个是父进程的正常返回 此时的返回值是 null,还是在zygote进程中运行,并且mIsForkChild的值是没有变的,这个时候会进入到else
  42. // 第二个返回时子进程的返回 此时的返回时不是空,此时是在子进程中运行,并且在子进程刚刚创建的时候,就将自己的mIsForkChild设置为 true了。
  43. if (mIsForkChild) {
  44. // We're in the child. We should always have a command to run at this
  45. // stage if processOneCommand hasn't called "exec".
  46. // 这里是在子进程
  47. if (command == null) {
  48. throw new IllegalStateException("command == null");
  49. }
  50. return command;
  51. } else {
  52. // We're in the server - we should never have any commands to run.
  53. // 这里是在父进程中
  54. if (command != null) {
  55. throw new IllegalStateException("command != null");
  56. }
  57. // We don't know whether the remote side of the socket was closed or
  58. // not until we attempt to read from it from processOneCommand. This shows up as
  59. // a regular POLLIN event in our regular processing loop.
  60. if (connection.isClosedByPeer()) {
  61. connection.closeSocket();
  62. peers.remove(i);
  63. fds.remove(i);
  64. }
  65. }
  66. } catch (Exception e) {
  67. if (!mIsForkChild) {
  68. // We're in the server so any exception here is one that has taken place
  69. // pre-fork while processing commands or reading / writing from the
  70. // control socket. Make a loud noise about any such exceptions so that
  71. // we know exactly what failed and why.
  72. Slog.e(TAG, "Exception executing zygote command: ", e);
  73. // Make sure the socket is closed so that the other end knows immediately
  74. // that something has gone wrong and doesn't time out waiting for a
  75. // response.
  76. ZygoteConnection conn = peers.remove(i);
  77. conn.closeSocket();
  78. fds.remove(i);
  79. } else {
  80. // We're in the child so any exception caught here has happened post
  81. // fork and before we execute ActivityThread.main (or any other main()
  82. // method). Log the details of the exception and bring down the process.
  83. Log.e(TAG, "Caught post-fork exception in child process.", e);
  84. throw e;
  85. }
  86. }
  87. }
  88. }
  89. }
  90. }


ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
这个函数首先创建两个链表,第一个链表 fds 是用来保存要监听的socket文件描述符。
第二个链表peers用来保存对应的socket文件上的事件处理函数
另外 fds 和 peers 中元素是有对应关键的,即:fds中的第i个元素所对应的处理类就是peers中的第i个元素。这个后面的代码中可以看出来
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
这里将mServerSocket.getFileDescriptor()添加到fds里面,就是将zygote自己创建的用来监听ActivityManager连接的socket添加到fds链表里面。因为这个socket上没有对应的事件处理类,因此其对应的peers中的处理类对象设置为null

  1. StructPollfd[] pollFds = new StructPollfd[fds.size()];
  2. for (int i = 0; i < pollFds.length; ++i) {// 填充pollFds
  3. pollFds[i] = new StructPollfd();
  4. pollFds[i].fd = fds.get(i);
  5. pollFds[i].events = (short) POLLIN;
  6. }
  7. try {
  8. Os.poll(pollFds, -1); // 开始进入监听模式 无论是监听到 连接请求还是 数据过来,这个函数都会返回
  9. } catch (ErrnoException ex) {
  10. throw new RuntimeException("poll failed", ex);
  11. }

  上面这个部分代码就是每次循环都会 根据 fds 的大小重新建立pollFds,然后开始监听。

  1. // 上面的函数一旦监听到动作就会返回,然后执行下面的代码
  2. for (int i = pollFds.length - 1; i >= 0; --i) {
  3. if ((pollFds[i].revents & POLLIN) == 0) {
  4. continue;
  5. }
  6. // 上面根据监听的pollFds的长度,循环从后到前,依次判断是哪个句柄上存在数据,获取存在数据的句柄
  7. if (i == 0) { // 如果i等于0,就说明是zygote的socket上监听到了连接请求。
  8. // 对于新的链接请求,这里会调用 acceptCommandPeer 函数,这个函数会调用 mServerSocket.accept() 接受连接,并返回句柄
  9. // 然后用此句柄为参数创建了 ZygoteConnection 对象,然后由 ZygoteConnection 对象负责这一个连接的后续数据处理
  10. ZygoteConnection newPeer = acceptCommandPeer(abiList);
  11. peers.add(newPeer); // 将新创建的ZygoteConnection添加到 peers 这个列表中
  12. fds.add(newPeer.getFileDesciptor()); // 添加到 fds,然后在下次循环的时候,将刚刚接受的链接请求也一同添加到监听。
  13. } else { // 如果i不是0.就说明是已将连接的socket上有数据发送过来了
  14. ZygoteConnection connection = peers.get(i); // 从刚刚记录的peers中获取处理对应数据的 ZygoteConnection 类
  15. final Runnable command = connection.processOneCommand(this); // 调用processOneCommand 函数处理socket发送过来的数据。
  16. if (mIsForkChild) { // 由于前面processOneCommand函数很可能会创建新的进程,因此当再次返回这里的时候,有可能会有两个进程这里就需要判断是在那个进程中
  17. // 这里是在子进程。表示在processOneCommand中fork了新的进程,此时返回来的时候,新的进程会设置 mIsForkChild 标志位
  18. if (command == null) {
  19. throw new IllegalStateException("command == null");
  20. }
  21. return command;
  22. } else {
  23. // 这里是在父进程中。表示的时候 zygote 进程,
  24. // 下面会关闭socket,并且将此socket的文件句柄,以及对应的处理类从链表中移除。
  25. if (connection.isClosedByPeer()) {
  26. connection.closeSocket();
  27. peers.remove(i);
  28. fds.remove(i);
  29. }
  30. }
  31. }
  32. }

下面我们看下acceptCommandPeer函数的具体实现:

  1. /**
  2. * Waits for and accepts a single command connection. Throws
  3. * RuntimeException on failure.
  4. // socket编程中,accept()调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET
  5. // 它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符
  6. // 新建立的套接字不在监听状态,原来所监听的套接字的状态也不受accept()调用的影响
  7. // 从代码,可以看出 acceptCommandPeer 调用了server socket的accpet函数。于是当新的连接建立时,
  8. // zygote将会创建出一个新的socket与其通信,并将该socket加入到fds中。因此,一旦通信连接建立后,fds中将会包含有多个socket(我这里表述有点问题,这里实际上是同一个socket上面的不同的链接,请读者注意下)
  9. */
  10. private ZygoteConnection acceptCommandPeer(String abiList) {
  11. try {
  12. // 注意这里的参数中调用了 mServerSocket.accept()
  13. return createNewConnection(mServerSocket.accept(), abiList);
  14. } catch (IOException ex) {
  15. throw new RuntimeException(
  16. "IOException during accept()", ex);
  17. }
  18. }
  19. protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
  20. throws IOException {
  21. // 这里根据参数,直接创建ZygoteConnection类对象
  22. return new ZygoteConnection(socket, abiList);
  23. }
  24. 下面是ZygoteConnection的构造函数
  25. /**
  26. * Constructs instance from connected socket.
  27. *
  28. * @param socket non-null; connected socket
  29. * @param abiList non-null; a list of ABIs this zygote supports.
  30. * @throws IOException
  31. */
  32. ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
  33. mSocket = socket;
  34. this.abiList = abiList;
  35. mSocketOutStream= new DataOutputStream(socket.getOutputStream());
  36. mSocketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), 256);
  37. mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
  38. try {
  39. peer = mSocket.getPeerCredentials();
  40. } catch (IOException ex) {
  41. Log.e(TAG, "Cannot read peer credentials", ex);
  42. throw ex;
  43. }
  44. isEof = false;
  45. }

上面的代码流程很清晰,就是创建了一个ZygoteConnection对象。这个对象是用来处理这个socket具体发送过来的数据的。

下面我们在看下processOneCommand函数的具体实现。看看ZygoteConnection类中的processOneCommand函数都干了什么。

  1. /**
  2. * Reads one start command from the command socket. If successful, a child is forked and a
  3. * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
  4. * process. {@code null} is always returned in the parent process (the zygote).
  5. *
  6. * If the client closes the socket, an {@code EOF} condition is set, which callers can test
  7. * for by calling {@code ZygoteConnection.isClosedByPeer}.
  8. */
  9. Runnable processOneCommand(ZygoteServer zygoteServer) {
  10. String args[];
  11. Arguments parsedArgs = null;
  12. FileDescriptor[] descriptors;
  13. try {
  14. args = readArgumentList(); // 从socket 中读取传递过来的各种参数
  15. descriptors = mSocket.getAncillaryFileDescriptors();
  16. } catch (IOException ex) {
  17. throw new IllegalStateException("IOException on command socket", ex);
  18. }
  19. // readArgumentList returns null only when it has reached EOF with no available
  20. // data to read. This will only happen when the remote socket has disconnected.
  21. if (args == null) {
  22. isEof = true;
  23. return null;
  24. }
  25. int pid = -1;
  26. FileDescriptor childPipeFd = null;
  27. FileDescriptor serverPipeFd = null;
  28. // parsedArgs 这个类是个工具类,主要是保存 并解析上面传递的参数,并保存解析的结果
  29. // 这里根据读取到的数据,来构建Arguments类,这个类会解析传递过来的数据,并保存解析的结果
  30. parsedArgs = new Arguments(args);
  31. if (parsedArgs.abiListQuery) { // 查询 AbiList
  32. handleAbiListQuery();
  33. return null;
  34. }
  35. if (parsedArgs.preloadDefault) { // 加载,并返回结果
  36. handlePreload();
  37. return null;
  38. }
  39. if (parsedArgs.preloadPackage != null) { // 预加载,
  40. handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
  41. parsedArgs.preloadPackageCacheKey);
  42. return null;
  43. }
  44. if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
  45. throw new ZygoteSecurityException("Client may not specify capabilities: " +
  46. "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
  47. ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
  48. }
  49. // 安全检查
  50. applyUidSecurityPolicy(parsedArgs, peer);
  51. applyInvokeWithSecurityPolicy(parsedArgs, peer);
  52. applyDebuggerSystemProperty(parsedArgs);
  53. applyInvokeWithSystemProperty(parsedArgs);
  54. int[] fdsToIgnore = null;
  55. Log.e(TAG, " processOneCommand parsedArgs.invokeWith = "+parsedArgs.invokeWith);
  56. if (parsedArgs.invokeWith != null) { // 这里好像一直都是空的,因此这里进不去
  57. try {
  58. FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); // 获取管道通讯的两端
  59. childPipeFd = pipeFds[1]; // 写入端
  60. serverPipeFd = pipeFds[0]; // 读取端
  61. Os.fcntlInt(childPipeFd, F_SETFD, 0);
  62. fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
  63. } catch (ErrnoException errnoEx) {
  64. throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
  65. }
  66. }
  67. /**
  68. * In order to avoid leaking descriptors to the Zygote child,
  69. * the native code must close the two Zygote socket descriptors
  70. * in the child process before it switches from Zygote-root to
  71. * the UID and privileges of the application being launched.
  72. *
  73. * In order to avoid "bad file descriptor" errors when the
  74. * two LocalSocket objects are closed, the Posix file
  75. * descriptors are released via a dup2() call which closes
  76. * the socket and substitutes an open descriptor to /dev/null.
  77. */
  78. int [] fdsToClose = { -1, -1 };
  79. FileDescriptor fd = mSocket.getFileDescriptor();
  80. if (fd != null) {
  81. fdsToClose[0] = fd.getInt$();
  82. }
  83. fd = zygoteServer.getServerSocketFileDescriptor();
  84. if (fd != null) {
  85. fdsToClose[1] = fd.getInt$();
  86. }
  87. fd = null;
  88. // 创建子进程
  89. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
  90. parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
  91. parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
  92. parsedArgs.appDataDir);
  93. try {
  94. if (pid == 0) {
  95. // in child
  96. // 因为子进程是复制于父进程,因此在子进程中 他的 mIsForkChild 值依然是父进程的原始值,false
  97. // 此时调用 setForkChild 只会设置子进程中的 mIsForkChild 变量的值,
  98. zygoteServer.setForkChild(); //设置标志.这样在这个地方返回的时候,zygoteServer 就会走到子进程的处理函数中了
  99. zygoteServer.closeServerSocket(); // 关闭子线程中的 socket,这个socket是从zygote集成过来的,因此这里需要首选关闭掉。
  100. IoUtils.closeQuietly(serverPipeFd); // 关闭流
  101. serverPipeFd = null;
  102. return handleChildProc(parsedArgs, descriptors, childPipeFd);
  103. } else {
  104. // In the parent. A pid < 0 indicates a failure and will be handled in
  105. // handleParentProc. 这里是在父进程中
  106. IoUtils.closeQuietly(childPipeFd);
  107. childPipeFd = null;
  108. handleParentProc(pid, descriptors, serverPipeFd);
  109. return null;
  110. }
  111. } finally {
  112. IoUtils.closeQuietly(childPipeFd);
  113. IoUtils.closeQuietly(serverPipeFd);
  114. }
  115. }

这个函数的流程比较简单,首先读取对端发送过来的数据,然后根据发送过来的数据构建Arguments这个类,这类会解析传递过来的参数,并保存解析的结果。然后根据解析情况进行各种判断。然后调用Zygote.forkAndSpecialize创建新的进程,这个函数会有两次返回,第一次是在原来的父进程中返回,第二次是在新创建的子进程中返回。从这个函数返回起,子进程和父进程就分道扬镳了,这个时候,我们需要注意下自己看的这部分代码是在子线程中还是在父进程中。
 

  1. 下面我们在贴下forkAndSpecialize函数的代码
  2. public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
  3. int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
  4. int[] fdsToIgnore, String instructionSet, String appDataDir) {
  5. VM_HOOKS.preFork(); // 这里会等待zygote的所有子线程都退出即:停止Zyote的4个Daemon子线程的运行,初始化gc堆
  6. // Resets nice priority for zygote process.
  7. resetNicePriority(); // 设置zygote进程的优先级为 normal
  8. int pid = nativeForkAndSpecialize(
  9. uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
  10. fdsToIgnore, instructionSet, appDataDir);
  11. // Enable tracing as soon as possible for the child process.
  12. if (pid == 0) {
  13. // 子进程中
  14. Trace.setTracingEnabled(true, debugFlags);
  15. // Note that this event ends at the end of handleChildProc,
  16. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
  17. }
  18. VM_HOOKS.postForkCommon(); // 启动4个Deamon子线程
  19. return pid;
  20. }

下面我们看下handleChildProc函数的大体流程

  1. private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
  2. FileDescriptor pipeFd) {
  3. closeSocket(); // 关闭socket。这个socket 根前面刚刚关闭的socket不是同一个
  4. if (parsedArgs.niceName != null) { // 设置子进程的名称
  5. Process.setArgV0(parsedArgs.niceName);
  6. }
  7. // End of the postFork event.
  8. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  9. if (parsedArgs.invokeWith != null) { // 这里好像一直都是空的
  10. WrapperInit.execApplication(parsedArgs.invokeWith,
  11. parsedArgs.niceName, parsedArgs.targetSdkVersion,
  12. VMRuntime.getCurrentInstructionSet(),
  13. pipeFd, parsedArgs.remainingArgs);
  14. // Should not get here.
  15. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
  16. } else { // 这里调用 ZygoteInit.zygoteInit 进一步初始化
  17. return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
  18. null /* classLoader */);
  19. }
  20. }

下面我们看下ZygoteInit.zygoteInit的实现

  1. // 这个函数是一个公共的函数,启动 systemServer 以及启动 应用都会调用到这里
  2. public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
  3. if (RuntimeInit.DEBUG) {
  4. Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
  5. }
  6. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
  7. RuntimeInit.redirectLogStreams(); // 将system.out 以及System.err 的输出重定向到 Android log中
  8. RuntimeInit.commonInit();
  9. ZygoteInit.nativeZygoteInit(); // 初始化native层
  10. return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
  11. }
  12. 下面是applicationInit函数的实现
  13. protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
  14. ClassLoader classLoader) {
  15. // 如果应用调用System.exit()直接终结一个进程,但是没有调用 shutdown hooks,这个对于一个Android应用了来说确实可以
  16. // 但是shutdown hooks是用来关闭Binder的,如果没有调用,会导致一些线程遗留,造成crash
  17. nativeSetExitWithoutCleanup(true);
  18. // We want to be fairly aggressive about heap utilization, to avoid
  19. // holding on to a lot of memory that isn't needed.
  20. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); // 与内存占用相关
  21. VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); // 设置sdk版本
  22. final Arguments args = new Arguments(argv);
  23. // The end of of the RuntimeInit event (see #zygoteInit).
  24. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  25. // Remaining arguments are passed to the start class's static main
  26. return findStaticMain(args.startClass, args.startArgs, classLoader);
  27. }

 这个findStaticMain函数会根据传递的参数,找到对应的java类的静态main函数,然后 通过return new MethodAndArgsCaller(m, argv);来返回一个MethodAndArgsCaller类,下面我们看下MethodAndArgsCaller类的实现。

  1. static class MethodAndArgsCaller implements Runnable {
  2. /** method to call */
  3. private final Method mMethod;
  4. /** argument array */
  5. private final String[] mArgs;
  6. public MethodAndArgsCaller(Method method, String[] args) {
  7. mMethod = method;
  8. mArgs = args;
  9. }
  10. public void run() {
  11. try {
  12. mMethod.invoke(null, new Object[] { mArgs }); //这个会调用相应的方法并将mArgs作为参数传递过去
  13. } catch (IllegalAccessException ex) {
  14. throw new RuntimeException(ex);
  15. } catch (InvocationTargetException ex) {
  16. Throwable cause = ex.getCause();
  17. if (cause instanceof RuntimeException) {
  18. throw (RuntimeException) cause;
  19. } else if (cause instanceof Error) {
  20. throw (Error) cause;
  21. }
  22. throw new RuntimeException(ex);
  23. }
  24. }
  25. }

这个类的实现很简单,就是保存要启动的函数对象,已经要传递的参数,然后提供一个 run函数来执行对应的函数并传递参数给这个函数。如果这里调用的是 SystemServer,那么这里就会调用SystemServer.java的main函数,如果是启动的应用,那就会调用ActivityThread.java 的main函数。

但是上面的findStaticMain并没有调用这个run函数,而是仅仅创建了一个类对象,然后就将这个对象返回了。那么这个函数是在哪里调用的呢,这里就一层一层的返回了,首先这里会返回到ZygoteConnection.java的processOneCommand 函数,然后这个函数接着返回,会返回到ZygoteServer.java中的runSelectLoop函数中,在这个函数有下面的代码:

if (mIsForkChild) {
    // We're in the child. We should always have a command to run at this
    // stage if processOneCommand hasn't called "exec".
    // 这里是在子进程
    if (command == null) {
        throw new IllegalStateException("command == null");
    }
    return command; // 这里再次返回
}

上面的代码会继续返回到ZygoteInit.java中的main函数中;下面这部分代码就会main函数的处理函数。

  1. // The select loop returns early in the child process after a fork and
  2. // loops forever in the zygote.
  3. caller = zygoteServer.runSelectLoop(abiList); // zygote进程进入无限循环,处理请求
  4. } catch (Throwable ex) {
  5. Log.e(TAG, "System zygote died with exception", ex);
  6. throw ex;
  7. } finally {
  8. Log.i(TAG, "zygoteServer.closeServerSocket finally finally");
  9. // 这个地方有两个调用的流程
  10. // 1: zygote 进程退出的时候会调用这个函数,用来关闭zygote自己创建的用来接收ActivityManager的链接请求的socket
  11. // 2:当每个子线程fork完毕,准备好之后,会走到这里,这个时候会在子进程中执行的,这里会调用closeServerSocket函数,确保从zygote集成过来的socket关闭。
  12. // 其实这个时候,因为子进程刚刚fock出来的时候就已经掉用过closeServerSocket函数了,因此再次调用,是没有效果的
  13. zygoteServer.closeServerSocket();
  14. }
  15. // We're in the child process and have exited the select loop. Proceed to execute the
  16. // command.
  17. if (caller != null) {
  18. caller.run(); // 这里才是重点,上面会返回一个Runnable的对象,这个地方调用他的 run函数会进入到子进程的真正的main函数里面
  19. }

上面的这段代码,当zygoteServer.runSelectLoop返回的时候,就已经是在子进程中了,此时会在后面调用caller.run();来执行对应的java文件的main函数。至此zygote中启动新进程的流程就梳理完成了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/227931
推荐阅读
相关标签
  

闽ICP备14008679号