> 文档中心 > Android系统的心脏-Zygote进程如何fork一个新的应用进程

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.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中,

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 },};