当前位置:   article > 正文

Android系统的心脏-Zygote进程如何fork一个新的应用进程_forkandspecialize

forkandspecialize

简介:

在Android系统中,所有的应用程序进程都是有Zygote进程创建的。那么,到底是如何创建出来的呢?本节来分析一下这个创建流程。 

ZygoteInit代码回顾:

在Android初始化流程中,init进程创建了zygote进程,(通过init.rc中的指令),而且,在zygote这个进程中,注册了zygote socket, 而且,会根据是否是ZYGOTE_FORK_MODE模式,去执行zygote的创建,或进入selectLoop监听循环中,代码在ZygoteInit.java中,如下:

  1. public static void main(String argv[]) {
  2.  
  3.     ......
  4.  
  5.     registerZygoteSocket();
  6.  
  7.     ......
  8.  
  9.     if (argv[1].equals("start-system-server")) {
  10.                 startSystemServer();
  11.     } else if (!argv[1].equals("")) {
  12.                 throw new RuntimeException(argv[0] + USAGE_STRING);
  13.     }
  14.     if (ZYGOTE_FORK_MODE) {
  15.                 runForkMode();
  16.     } else {
  17.                 runSelectLoopMode();
  18.     }
  19.     
  20.  
  21. }    

ZYGOTE_FORK_MODE的定义:

private static final boolean ZYGOTE_FORK_MODE = false;

所以,会执行到runSelectLoopMode,即在创建了SystemServer进程之后,就进入了这个runSelectLoopMode方法的执行。 

从runSelectLoopMode开始分析:

  1. private static void runSelectLoopMode() throws MethodAndArgsCaller {
  2.         ArrayList<FileDescriptor> fds = new ArrayList();
  3.         ArrayList<ZygoteConnection> peers = new ArrayList();
  4.         FileDescriptor[] fdArray = new FileDescriptor[4];
  5.  
  6.         fds.add(sServerSocket.getFileDescriptor());
  7.         peers.add(null);
  8.  
  9.         int loopCount = GC_LOOP_COUNT;
  10.         while (true) {
  11.             int index;
  12.  
  13.             ......
  14.  
  15.             try {
  16.                 fdArray = fds.toArray(fdArray);
  17.                 index = selectReadable(fdArray);
  18.             } catch (IOException ex) {
  19.                 throw new RuntimeException("Error in select()", ex);
  20.             }
  21.  
  22.             if (index < 0) {
  23.                 throw new RuntimeException("Error in select()");
  24.             } else if (index == 0) {
  25.                 ZygoteConnection newPeer = acceptCommandPeer();
  26.                 peers.add(newPeer);
  27.                 fds.add(newPeer.getFileDesciptor());
  28.             } else {
  29.                 boolean done;
  30.                 done = peers.get(index).runOnce();
  31.  
  32.                 if (done) {
  33.                     peers.remove(index);
  34.                     fds.remove(index);
  35.                 }
  36.             }
  37.         }
  38.     }

分析:

1)通过前面注册的socket来获取文件描述符,通过这个描述符来处理来自外部的请求;这个描述符什么时候创建的呢?看下面的代码(ZygoteInit.java的registerZygoteSocket方法:

  1. private static void registerZygoteSocket() {
  2.         if (sServerSocket == null) {
  3.             int fileDesc;
  4.             try {
  5.                 String env = System.getenv(ANDROID_SOCKET_ENV);
  6.                 fileDesc = Integer.parseInt(env);
  7.             } catch (RuntimeException ex) {
  8.                 throw new RuntimeException(
  9.                         ANDROID_SOCKET_ENV + " unset or invalid", ex);
  10.             }
  11.  
  12.             try {
  13.                 sServerSocket = new LocalServerSocket(
  14.                         createFileDescriptor(fileDesc));
  15.             } catch (IOException ex) {
  16.                 throw new RuntimeException(
  17.                         "Error binding to local socket '" + fileDesc + "'", ex);
  18.             }
  19.         }
  20.     }

这里的

sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));

在初始化sServerSocket的时候,创建了FileDescriptor,即

ANDROID_SOCKET_ENV

环境变量对应的文件描述符,ANDROID_SOCKET_ENV的定义: 

private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";

2)selectReadable:这是一个native方法,用于监视文件描述符,如果文件描述符中有相关的事件,则返回文件描述符在数组中的索引index。其实就是找到有事件发生的文件描述符。那么,如何监听呢?答案就是通过Linux系统调用select函数来实现; 

3)根据index去创建ZygoteConnection,并且保存起来;

4)执行ZygoteConnection实例的runOnce方法。这是个关键函数,是创建应用程序进程的入口。

整个流程涉及到java和native,时序图如下(分为java层和native层)如下:

java层时序图:

 

select函数的功能:

它可以同时监听多个socket描述符,并且知道哪一个socket描述符已经可以读取数据了,哪个描述符可以 写入数据,以及哪个socket出现了错误。这里的socket描述符也是文件的一种。

Native层时序图:

 

 从java的forkAndSpecialize()调用到native层的forkAndSpecializeCommon()方法中,而在这个方法中,最终,通过fork系统调用创建了一个新的进程,这个进程就是用用程序进程。

forkAndSpecializeCommon()的fork:

在forkAndSpecializeCommon()中,fork的调用如下:

  1. static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
  2. {
  3.     pid_t pid;
  4.     
  5.     ......
  6.  
  7.     pid = fork();
  8.  
  9.     if (pid == 0) {
  10.  
  11.         /* The child process */
  12.  
  13.         ......
  14.     } else if (pid > 0) {
  15.         /* the parent process */
  16.     }
  17.  
  18.     return pid;
  19. }

可见,典型的pid处理方式:如果pid == 0,即当前处于子进程;如果pid>0,即处于父进程。 

再看一下主要代码文件列表:

1)相关代码文件:

Java代码:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
libcore/dalvik/src/main/java/dalvik/system/Zygote.java

Native代码:
frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp
dalvik/vm/native/dalvik_system_Zygote.cpp

 代码目录结构:

 

2)ZygoteInit中jni方法的注册:

frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp中,

  1. static JNINativeMethod gMethods[] = {
  2.     /* name, signature, funcPtr */
  3.     { "setreuid", "(II)I",
  4.       (void*) com_android_internal_os_ZygoteInit_setreuid },
  5.     { "setregid", "(II)I",
  6.       (void*) com_android_internal_os_ZygoteInit_setregid },
  7.     { "setpgid", "(II)I",
  8.       (void *) com_android_internal_os_ZygoteInit_setpgid },
  9.     { "getpgid", "(I)I",
  10.       (void *) com_android_internal_os_ZygoteInit_getpgid },
  11.     { "reopenStdio",
  12.         "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
  13.         "Ljava/io/FileDescriptor;)V",
  14.             (void *) com_android_internal_os_ZygoteInit_reopenStdio},
  15.     { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
  16.         (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
  17.     { "setCapabilities", "(JJ)V",
  18.         (void *) com_android_internal_os_ZygoteInit_setCapabilities },
  19.     { "capgetPermitted", "(I)J",
  20.         (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
  21.     { "selectReadable", "([Ljava/io/FileDescriptor;)I",
  22.         (void *) com_android_internal_os_ZygoteInit_selectReadable },
  23.     { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
  24.         (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
  25. };
  26. int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
  27. {
  28.     return AndroidRuntime::registerNativeMethods(env,
  29.             "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
  30. }

3)Zygote的jni方法的注册;

dalvik/vm/native/dalvik_system_Zygote.cpp中,

  1. const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
  2.     { "nativeFork", "()I",
  3.       Dalvik_dalvik_system_Zygote_fork },
  4.     { "nativeForkAndSpecialize", "(II[II[[I)I",
  5.       Dalvik_dalvik_system_Zygote_forkAndSpecialize },
  6.     { "nativeForkSystemServer", "(II[II[[IJJ)I",
  7.       Dalvik_dalvik_system_Zygote_forkSystemServer },
  8.     { "nativeExecShell", "(Ljava/lang/String;)V",
  9.       Dalvik_dalvik_system_Zygote_execShell },
  10.     { NULL, NULL, NULL },
  11. };

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

闽ICP备14008679号