Android系统zygote进程启动过程源码分析

时间:2022-09-11 16:49:18

一、简介

 在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因。

zygoteps中看到的进程名叫zygote,其最初的名字是app_process,通过直接调用pctrl把名字给改成了”zygote”


    二、zygote在android中主要有三个作用:

 1. 系统启动时init进程会创建Zygote进程,Zygote进程负责后续Android应用程序框架层的其它进程的创建和启动工作。

 2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,如包管理服务PackageManagerService和应用程序组件管理服务ActivityManagerService。

3. 当我们需要启动一个Android应用程序时,ActivityManagerService会通过Socket进程间通信机制,通知Zygote进程为这个应用程序创建一个新的进程。

三、zygote代码组成


在android中提到zygote,主要两块:

一个是C/C++编写的zygote,主要用来为应用和SystemService fork进程的。

/dalvik/vm/native/dalvik_system_Zygote.c 


一个是java编写的zygote接口,负责为应用和service调用C/C++ zygote的接口执行fork,从而创建VM进程。

Zygote系统代码组成及其调用结构:

  • Zygote.java

                提供访问Dalvik “zygote”的接口。主要是包装Linux系统的Fork,以建立一个新的VM实例进程。

  • ZygoteConnection.java

                Zygote的套接口连接管理及其参数解析。其他Actvitiy建立进程请求是通过套接口发送命令参数给Zygote。

  • ZygoteInit.java

                Zygote的main函数入口。

说明:在android中,service主要有NativeService和SystemService。SystemService主要是指系统中service,比如,InputMethodService、ActivityManagerService等。


Zygote系统代码层次调用(frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中

main()

        registerZygoteSocket();

        startSystemServer()…

        runSelectLoopMode()

                Accept socket connection

                        Conntecion.RunOnce()

                        Read argument

                                folkAndSpecialize



folkAndSpecialize使用Native函数Dalvik_dalvik_system_Zygote_forkAndSpecialize(/dalvik/vm/native/dalvik_system_Zygote.c 



五、启动流程

Android系统 所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程的脚本命令:

[plain] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server  
  2.     socket zygote stream 666  
  3.     onrestart write /sys/android_power/request_state wake  
  4.     onrestart write /sys/power/state on  
  5.     onrestart restart media  
  6.     onrestart restart netd  
        前面的关键字service告诉init进程创建一个名为"zygote"的进程,这个 zygote进程要执行的程序是/system/bin/app_process ,后面是要传给app_process的参数。

        接下来的socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源,这样,系统启动后,我们就可以在/dev/socket目录下看到有一个名为zygote的文件。这里定义的socket的类型为unix domain socket,它是用来作本地进程间通信用的,具体可以参考前面一篇文章Android学习启动篇提到的一书《Linux内核源代码情景分析》的第七章--基于socket的进程间通信。前面我们说到的ActivityManagerService就是通这个socket来和zygote进程通信请求fork一个应用程序进程的了。

        最后的一系列onrestart关键字表示这个zygote进程重启时需要执行的命令。


我们先来看看它的启动序列图:

Android系统zygote进程启动过程源码分析

        下面我们就详细分析每一个步骤。

 Step 1、我们就知道Zygote进程要执行的程序便是system/bin/app_process了,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。

源码:

/*
 * Main entry of app process.
 * 
 * Starts the interpreted runtime, then starts up the application.
 * 
 */


#define LOG_TAG "appproc"


#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/process_name.h>
#include <cutils/memory.h>
#include <android_runtime/AndroidRuntime.h>


#include <stdio.h>
#include <unistd.h>


namespace android {


void app_usage()
{
    fprintf(stderr,
        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
}


status_t app_init(const char* className, int argc, const char* const argv[])
{
    LOGV("Entered app_init()!\n");


    AndroidRuntime* jr = AndroidRuntime::getRuntime();
    jr->callMain(className, argc, argv);
    
    LOGV("Exiting app_init()!\n");
    return NO_ERROR;
}


//定义AppRuntime类
//继承于AndroidRuntime类, AndroidRuntime类定义在frameworks/base/core/jni/AndroidRuntime.cpp

//当AppRuntime对象创建时,会调用其父类AndroidRuntime的构造函数,而在AndroidRuntime类的构造函数里面,会将this指针保存在静态全局变量gCurRuntime中,这样,当其它地方需要使用这个AppRuntime对象时,就可以通过同一个文件中的getRuntime()函数来获取这个对象的指针
class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime()
        : mParentDir(NULL)
        , mClassName(NULL)
        , mArgC(0)
        , mArgV(NULL)
    {
    }


#if 0
    // this appears to be unused
    const char* getParentDir() const
    {
        return mParentDir;
    }
#endif


    const char* getClassName() const
    {
        return mClassName;
    }


    virtual void onStarted()
    {
        sp<ProcessState> proc = ProcessState::self();
        if (proc->supportsProcesses()) {
            LOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
        }
        
        app_init(mClassName, mArgC, mArgV);


        if (ProcessState::self()->supportsProcesses()) {
            IPCThreadState::self()->stopProcess();
        }
    }


    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        if (proc->supportsProcesses()) {
            LOGV("App process: starting thread pool.\n");
            proc->startThreadPool();
        }       
    }


    virtual void onExit(int code)
    {
        if (mClassName == NULL) {
            // if zygote
            if (ProcessState::self()->supportsProcesses()) {
                IPCThreadState::self()->stopProcess();
            }
        }


        AndroidRuntime::onExit(code);
    }


    
    const char* mParentDir;
    const char* mClassName;
    int mArgC;
    const char* const* mArgV;
};


}


using namespace android;


/*
 * sets argv0 to as much of newArgv0 as will fit
 */
static void setArgv0(const char *argv0, const char *newArgv0)
{
    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
}

//主要做了什么?

//初始化了运行时环境,并且建立虚拟机创建一个AppRuntime变量,然后调用它的start成员函数

//运行再com.android.internal.os.ZygoteInit的main函数
int main(int argc, const char* const argv[])
{

//这几个参数重要,参数都在argv[]里面传进来的

//service   zygote   /system/bin/app_process  -Xzygote  /system/bin    --zygote   --start-system-server

    // These are global variables in ProcessState.cpp
    mArgC = argc;
    mArgV = argv;
    
    mArgLen = 0;
    for (int i=0; i<argc; i++) {
        mArgLen += strlen(argv[i]) + 1;
    }
    mArgLen--;


    AppRuntime runtime;
    const char* argv0 = argv[0];


    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;


    // Everything up to '--' or first non '-' arg goes to the vm
    
    int i = runtime.addVmArguments(argc, argv);


    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    const char* parentDir = NULL;
    const char* niceName = NULL;
    const char* className = NULL;
    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = arg + 12;
        } else {
            className = arg;
            break;
        }
    }


    if (niceName && *niceName) {
        setArgv0(argv0, niceName);

//改名字为zygote,不知道windows下的怎么改、linux下的可以用pctrl系统调用
        set_process_name(niceName);
    }


    runtime.mParentDir = parentDir;


    if (zygote) {

//在init.rc文件中,设置了app_process(也就是zygote)启动参数--zygote和--start-system-server,最终会执行

//这里的参数startSystemServer为true,表示要启动SystemServer组件。由于AppRuntime没有实现自己的start函数,它继承了父类AndroidRuntime的start函数
        runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");

    } else if (className) {
        // Remainder of args get passed to startup class main()
        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        runtime.start("com.android.internal.os.RuntimeInit",
                application ? "application" : "tool");
    } else {
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        return 10;
    }
}


Step2、frameworks/base/core/jni/AndroidRuntime.cpp文件

[cpp] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. /* 
  2. * Start the Android runtime.  This involves starting the virtual machine 
  3. * and calling the "static void main(String[] args)" method in the class 
  4. * named by "className". 
  5. */  

  6. void AndroidRuntime::start(const char* className, const bool startSystemServer)  
  7. {  
  8. //传人参数为:"com.android.internal.os.ZygoteInit""start-system-server"
  9.     ......  
  10.   
  11.     char* slashClassName = NULL;  
  12.     char* cp;  
  13.     JNIEnv* env;  
  14.   
  15.     ......  
  16.   
  17.     /* start the virtual machine */  
  18. //启动虚拟机,自己可以进去看它的源码
  19.     if (startVm(&mJavaVM, &env) != 0)  
  20.         goto bail;  
  21.   
  22.     /* 
  23.     * Register android functions. 
  24.     */ 
  25. //JNI注册,其实就是注册一些JAVAnative函数在C++层对应的实现函数 
  26.     if (startReg(env) < 0) {  
  27.         LOGE("Unable to register all android natives\n");  
  28.         goto bail;  
  29.     }  
  30.   
  31.     /* 
  32.     * We want to call main() with a String array with arguments in it. 
  33.     * At present we only have one argument, the class name.  Create an 
  34.     * array to hold it. 
  35.     */  
  36. //下面这些话,都是把c++的字符串转成JNI字符串
  37.     jclass stringClass;  
  38.     jobjectArray strArray;  
  39.     jstring classNameStr;  
  40.     jstring startSystemServerStr;  
  41.     stringClass = env->FindClass("java/lang/String");  
  42.     assert(stringClass != NULL);  
  43.     strArray = env->NewObjectArray(2, stringClass, NULL);  
  44.     assert(strArray != NULL);  
  45.     classNameStr = env->NewStringUTF(className);  
  46.     assert(classNameStr != NULL);  
  47.     env->SetObjectArrayElement(strArray, 0, classNameStr);  
  48.     startSystemServerStr = env->NewStringUTF(startSystemServer ?  
  49.         "true" : "false");  
  50.     env->SetObjectArrayElement(strArray, 1, startSystemServerStr);  
  51.   
  52.     /* 
  53.     * Start VM.  This thread becomes the main thread of the VM, and will 
  54.     * not return until the VM exits. 
  55.     */  
  56.     jclass startClass;  
  57.     jmethodID startMeth;  
  58.   
  59.     slashClassName = strdup(className);  
  60.     for (cp = slashClassName; *cp != '\0'; cp++)  
  61.         if (*cp == '.')  
  62.             *cp = '/';  
  63.   
  64.     startClass = env->FindClass(slashClassName);  
  65.     if (startClass == NULL) {  
  66.         ......  
  67.     } else { 

  68. // 下面调用的就是com.android.internal.os.ZygoteInit类的main函数
  69.         startMeth = env->GetStaticMethodID(startClass, "main",  
  70.             "([Ljava/lang/String;)V");  
  71.         if (startMeth == NULL) {  
  72.             ......  
  73.         } else {  
  74.             env->CallStaticVoidMethod(startClass, startMeth, strArray);  
  75.             ......  
  76.         }  
  77.     }  
  78.   
  79.     ......  
  80. }  

        这个函数的作用是启动Android系统运行时库,它主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数。


Step 3.frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

Android系统zygote进程启动过程源码分析

Android系统zygote进程启动过程源码分析

[java] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. public class ZygoteInit {  
  2.     ......  
  3.   
  4.     public static void main(String argv[]) {  
  5.         try {  
  6.             ......  
  7.   
  8.             registerZygoteSocket();  //创建了一个socket接口,用来和                            ActivityManagerService通讯
  9.               
  10.             ......  
  11.   
  12.             ......  
  13.   
  14.             if (argv[1].equals("true")) {  
  15.                 startSystemServer();  //启动SystemServer组件
  16.             } else if (!argv[1].equals("false")) {  
  17.                 ......  
  18.             }  
  19.   
  20.             ......  
  21.   
  22.             if (ZYGOTE_FORK_MODE) {  
  23.                 ......  
  24.             } else {  
  25.                 runSelectLoopMode(); //进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程
  26.             }  
  27.   
  28.             ......  
  29.         } catch (MethodAndArgsCaller caller) {  
  30.             ......  
  31.         } catch (RuntimeException ex) {  
  32.             ......  
  33.         }  
  34.     }  
  35.   
  36.     ......  
  37. }  

3.1、registerZygoteSocket函数

[java] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. public class ZygoteInit {  
  2.     ......
  3.     
  4.    private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote"  
  5.     ......
  6.     /** 
  7.     * Registers a server socket for zygote command connections 
  8.     * 
  9.     * @throws RuntimeException when open fails 
  10.     */  
  11.     private static void registerZygoteSocket() {  
  12.         if (sServerSocket == null) {  
  13.             int fileDesc;  
  14.             try {  
  15.                 String env = System.getenv(ANDROID_SOCKET_ENV);  
  16.                 fileDesc = Integer.parseInt(env);  
  17.             } catch (RuntimeException ex) {  
  18.                 ......  
  19.             }  
  20.   
  21.             try {  
  22.                //这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的
  23.                 sServerSocket = new LocalServerSocket(  
  24.                     createFileDescriptor(fileDesc));  
  25.             } catch (IOException ex) {  
  26.                 .......  
  27.             }  
  28.         }  
  29.     }  
  30.           
  31.     ......  
  32. }  
那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:

[cpp] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. void service_start(struct service *svc, const char *dynamic_args)  
  2. {  
  3.     ......  
  4.   
  5.     pid_t pid;  
  6.   
  7.     ......  
  8.   
  9.     pid = fork();  
  10.   
  11.     if (pid == 0) {  
  12.         struct socketinfo *si;  
  13.   
  14.         ......  
  15.   
  16.         for (si = svc->sockets; si; si = si->next) {  
  17.             int socket_type = (  
  18.                 !strcmp(si->type, "stream") ? SOCK_STREAM :  
  19.                 (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
  20.             int s = create_socket(si->name, socket_type,  
  21.                 si->perm, si->uid, si->gid);  
  22.             if (s >= 0) {  
  23.                 publish_socket(si->name, s);  
  24.             }  
  25.         }  
  26.   
  27.         ......  
  28.     }  
  29.   
  30.     ......  
  31. }  
        每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_socket函数写入到环境变量中去:

[cpp] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. static void publish_socket(const char *name, int fd)  
  2. {  
  3.     char key[64] = ANDROID_SOCKET_ENV_PREFIX;  
  4.     char val[64];  
  5.   
  6.     strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
  7.             name,  
  8.             sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
  9.     snprintf(val, sizeof(val), "%d", fd);  
  10.     add_environment(key, val);  
  11.   
  12.     /* make sure we don't close-on-exec */  
  13.     fcntl(fd, F_SETFD, 0);  
  14. }  
       这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:

[cpp] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. #define ANDROID_SOCKET_ENV_PREFIX   "ANDROID_SOCKET_"  
        因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了,ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的:

[java] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. public class Process {    
  2.     ......    
  3.    
  4.     private static void openZygoteSocketIfNeeded()    
  5.             throws ZygoteStartFailedEx {    
  6.   
  7.         ......  
  8.   
  9.         for (int retry = 0    
  10.             ; (sZygoteSocket == null) && (retry < (retryCount + 1))    
  11.             ; retry++ ) {    
  12.   
  13.                 ......  
  14.   
  15.                 try {    
  16.                     sZygoteSocket = new LocalSocket();    
  17.                     sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,    
  18.                         LocalSocketAddress.Namespace.RESERVED));    
  19.   
  20.                     sZygoteInputStream    
  21.                         = new DataInputStream(sZygoteSocket.getInputStream());    
  22.   
  23.                     sZygoteWriter =    
  24.                         new BufferedWriter(    
  25.                         new OutputStreamWriter(    
  26.                         sZygoteSocket.getOutputStream()),    
  27.                         256);    
  28.   
  29.                     ......    
  30.                 } catch (IOException ex) {    
  31.                     ......    
  32.                 }    
  33.         }    
  34.   
  35.         ......    
  36.     }    
  37.   
  38.     ......    
  39. }  
        这里的ZYGOTE_SOCKET定义为:

[java] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. public class Process {    
  2.     ......    
  3.    
  4.     private static final String ZYGOTE_SOCKET = "zygote";    
  5.   
  6.     ......    
  7. }   
        它刚好就是对应/dev/socket目录下的zygote文件了。

3.2、startSystemServer函数

    SystemServer进程启动参见下一篇Android系统SystemServer进程启动过程源码分析

3.3、runSelectLoopMode函数

[java] view plaincopyAndroid系统zygote进程启动过程源码分析Android系统zygote进程启动过程源码分析
  1. public class ZygoteInit {  
  2.     ......  
  3.   
  4.     private static void runSelectLoopMode() throws MethodAndArgsCaller {  
  5.         ArrayList<FileDescriptor> fds = new ArrayList();  
  6.         ArrayList<ZygoteConnection> peers = new ArrayList();  
  7.         FileDescriptor[] fdArray = new FileDescriptor[4];  
  8.   
  9.         fds.add(sServerSocket.getFileDescriptor());  
  10.         peers.add(null);  
  11.   
  12.         int loopCount = GC_LOOP_COUNT; 
  13. //无限循环,等待ActivityManagerService来连接这个Socket 
  14. //ZygoteInit会监听domain socket “dev/socket/zygote”,以执行framework层指定的fork操作
  15.         while (true) {  
  16.             int index;  
  17.   
  18.             ......  
  19.   
  20.   
  21.             try {  
  22.                 fdArray = fds.toArray(fdArray);  
  23.                 index = selectReadable(fdArray);  
  24.             } catch (IOException ex) {  
  25.                 throw new RuntimeException("Error in select()", ex);  
  26.             }  
  27.   
  28.             if (index < 0) {  
  29.                 throw new RuntimeException("Error in select()");  
  30.             } else if (index == 0) {  
  31.                 ZygoteConnection newPeer = acceptCommandPeer();  
  32.                 peers.add(newPeer);  
  33.                 fds.add(newPeer.getFileDesciptor());  
  34.             } else {  
  35.                 boolean done;  
  36. //调用ZygoteConnection.runOnce函数来创建新的应用程序
  37.                 done = peers.get(index).runOnce();  
  38.   
  39.                 if (done) {  
  40.                     peers.remove(index);  
  41.                     fds.remove(index);  
  42.                 }  
  43.             }  
  44.         }  
  45.     }  
  46.   
  47.     ......  
  48. }