Android系统的心脏-Zygote进程如何fork一个新的应用进程
简介:
在Android系统中,所有的应用程序进程都是有Zygote进程创建的。那么,到底是如何创建出来的呢?本节来分析一下这个创建流程。
ZygoteInit代码回顾:
在Android初始化流程中,init进程创建了zygote进程,(通过init.rc中的指令),而且,在zygote这个进程中,注册了zygote socket, 而且,会根据是否是ZYGOTE_FORK_MODE模式,去执行zygote的创建,或进入selectLoop监听循环中,代码在ZygoteInit.java中,如下:
public static void main(String argv[]) { ...... registerZygoteSocket(); ...... if (argv[1].equals("start-system-server")) { startSystemServer(); } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (ZYGOTE_FORK_MODE) { runForkMode(); } else { runSelectLoopMode(); } }
ZYGOTE_FORK_MODE的定义:
private static final boolean ZYGOTE_FORK_MODE = false;
所以,会执行到runSelectLoopMode,即在创建了SystemServer进程之后,就进入了这个runSelectLoopMode方法的执行。
从runSelectLoopMode开始分析:
private static void runSelectLoopMode() throws MethodAndArgsCaller { ArrayList fds = new ArrayList(); ArrayList peers = new ArrayList(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; ...... try { fdArray = fds.toArray(fdArray); index = selectReadable(fdArray); } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); } if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) { ZygoteConnection newPeer = acceptCommandPeer(); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else { boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }
分析:
1)通过前面注册的socket来获取文件描述符,通过这个描述符来处理来自外部的请求;这个描述符什么时候创建的呢?看下面的代码(ZygoteInit.java的registerZygoteSocket方法:
private static void registerZygoteSocket() { if (sServerSocket == null) { int fileDesc; try { String env = System.getenv(ANDROID_SOCKET_ENV); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException( ANDROID_SOCKET_ENV + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }
这里的
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的调用如下:
static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer){ pid_t pid; ...... pid = fork(); if (pid == 0) { /* The child process */ ...... } else if (pid > 0) { /* the parent process */ } return pid;}
可见,典型的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.javaNative代码:
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中,
static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "setreuid", "(II)I", (void*) com_android_internal_os_ZygoteInit_setreuid }, { "setregid", "(II)I", (void*) com_android_internal_os_ZygoteInit_setregid }, { "setpgid", "(II)I", (void *) com_android_internal_os_ZygoteInit_setpgid }, { "getpgid", "(I)I", (void *) com_android_internal_os_ZygoteInit_getpgid }, { "reopenStdio", "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;" "Ljava/io/FileDescriptor;)V", (void *) com_android_internal_os_ZygoteInit_reopenStdio}, { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V", (void *) com_android_internal_os_ZygoteInit_setCloseOnExec}, { "setCapabilities", "(JJ)V", (void *) com_android_internal_os_ZygoteInit_setCapabilities }, { "capgetPermitted", "(I)J", (void *) com_android_internal_os_ZygoteInit_capgetPermitted }, { "selectReadable", "([Ljava/io/FileDescriptor;)I", (void *) com_android_internal_os_ZygoteInit_selectReadable }, { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;", (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }};int register_com_android_internal_os_ZygoteInit(JNIEnv* env){ return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));}
3)Zygote的jni方法的注册;
dalvik/vm/native/dalvik_system_Zygote.cpp中,
const DalvikNativeMethod dvm_dalvik_system_Zygote[] = { { "nativeFork", "()I", Dalvik_dalvik_system_Zygote_fork }, { "nativeForkAndSpecialize", "(II[II[[I)I", Dalvik_dalvik_system_Zygote_forkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", Dalvik_dalvik_system_Zygote_forkSystemServer }, { "nativeExecShell", "(Ljava/lang/String;)V", Dalvik_dalvik_system_Zygote_execShell }, { NULL, NULL, NULL },};