[原]Android系统进程Zygote启动过程的源代码分析

在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,这也许就是为什么要把它称为Zygote(受精卵)的原因吧。由于Zygote进程在Android系统中有着如此重要的地位,本文将详细分析它的启动过程。

在前面一篇文章Android应用程序进程启动过程的源代码分析中,我们看到了,当ActivityManagerService启动一个应用程序的时候,就会通过Socket与Zygote进程进行通信,请求它fork一个子进程出来作为这个即将要启动的应用程序的进程;在前面两篇文章Android应用程序安装过程源代码分析和Android系统默认Home应用程序(Launcher)的启动过程源代码分析中,我们又看到了,系统中的两个重要服务PackageManagerService和ActivityManagerService,都是由SystemServer进程来负责启动的,而SystemServer进程本身是Zygote进程在启动的过程中fork出来的。

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

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    socket zygote stream 666    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    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进程重启时需要执行的命令。

关于init.rc文件的更多信息,请参考system/core/init/readme.txt文件。

了解了这个信息之后,我们就知道Zygote进程要执行的程序便是system/bin/app_process了,它的源代码位于frameworks/base/cmds/app_process/app_main.cpp文件中,入口函数是main。在继续分析Zygote进程启动的过程之前,我们先来看看它的启动序列图:


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

Step 1. app_process.main

这个函数定义在frameworks/base/cmds/app_process/app_main.cpp文件中:

int main(int argc, const char* const argv[]){// These are global variables in ProcessState.cppmArgC = argc;mArgV = argv;mArgLen = 0;for (int i=0; i<argc; i++) {mArgLen += strlen(argv[i]) + 1;}mArgLen--;AppRuntime runtime;const char *arg;argv0 = argv[0];// Process command line arguments// ignore argv[0]argc--;argv++;// Everything up to '--' or first non '-' arg goes to the vmint i = runtime.addVmArguments(argc, argv);// Next arg is parent directoryif (i < argc) {runtime.mParentDir = argv[i++];}// Next arg is startup classname or "--zygote"if (i < argc) {arg = argv[i++];if (0 == strcmp("--zygote", arg)) {bool startSystemServer = (i < argc) ?strcmp(argv[i], "--start-system-server") == 0 : false;setArgv0(argv0, "zygote");set_process_name("zygote");runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);} else {set_process_name(argv0);runtime.mClassName = arg;// Remainder of args get passed to startup class main()runtime.mArgC = argc-i;runtime.mArgV = argv+i;LOGV("App process is starting with pid=%d, class=%s.\n",getpid(), runtime.getClassName());runtime.start();}} 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;}}
这个函数的主要作用就是创建一个AppRuntime变量,然后调用它的start成员函数。AppRuntime这个类我们在 Android应用程序进程启动过程的源代码分析一文中已经有过介绍了,它同样是在frameworks/base/cmds/app_process/app_main.cpp文件中定义:

class AppRuntime : public AndroidRuntime{......};
它约继承于AndroidRuntime类,AndroidRuntime类定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

......static AndroidRuntime* gCurRuntime = NULL;......AndroidRuntime::AndroidRuntime(){......assert(gCurRuntime == NULL);        // one per processgCurRuntime = this;}
当AppRuntime对象创建时,会调用其父类AndroidRuntime的构造函数,而在AndroidRuntime类的构造函数里面,会将this指针保存在静态全局变量gCurRuntime中,这样,当其它地方需要使用这个AppRuntime对象时,就可以通过同一个文件中的这个函数来获取这个对象的指针:

AndroidRuntime* AndroidRuntime::getRuntime(){    return gCurRuntime;}
回到上面的main函数中,由于我们在init.rc文件中,设置了app_process启动参数--zygote和--start-system-server,因此,在main函数里面,最终会执行下面语句:

    runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
这里的参数startSystemServer为true,表示要启动SystemServer组件。由于AppRuntime没有实现自己的start函数,它继承了父类AndroidRuntime的start函数,因此,下面会执行AndroidRuntime类的start函数。

Step 2.AndroidRuntime.start

这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

/** Start the Android runtime.  This involves starting the virtual machine* and calling the "static void main(String[] args)" method in the class* named by "className".*/void AndroidRuntime::start(const char* className, const bool startSystemServer){......char* slashClassName = NULL;char* cp;JNIEnv* env;....../* start the virtual machine */if (startVm(&mJavaVM, &env) != 0)goto bail;/** Register android functions.*/if (startReg(env) < 0) {LOGE("Unable to register all android natives\n");goto bail;}/** We want to call main() with a String array with arguments in it.* At present we only have one argument, the class name.  Create an* array to hold it.*/jclass stringClass;jobjectArray strArray;jstring classNameStr;jstring startSystemServerStr;stringClass = env->FindClass("java/lang/String");assert(stringClass != NULL);strArray = env->NewObjectArray(2, stringClass, NULL);assert(strArray != NULL);classNameStr = env->NewStringUTF(className);assert(classNameStr != NULL);env->SetObjectArrayElement(strArray, 0, classNameStr);startSystemServerStr = env->NewStringUTF(startSystemServer ?"true" : "false");env->SetObjectArrayElement(strArray, 1, startSystemServerStr);/** Start VM.  This thread becomes the main thread of the VM, and will* not return until the VM exits.*/jclass startClass;jmethodID startMeth;slashClassName = strdup(className);for (cp = slashClassName; *cp != '\0'; cp++)if (*cp == '.')*cp = '/';startClass = env->FindClass(slashClassName);if (startClass == NULL) {......} else {startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");if (startMeth == NULL) {......} else {env->CallStaticVoidMethod(startClass, startMeth, strArray);......}}......}

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

Step 3.ZygoteInit.main

这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {......public static void main(String argv[]) {try {......registerZygoteSocket();............if (argv[1].equals("true")) {startSystemServer();} else if (!argv[1].equals("false")) {......}......if (ZYGOTE_FORK_MODE) {......} else {runSelectLoopMode();}......} catch (MethodAndArgsCaller caller) {......} catch (RuntimeException ex) {......}}......}
它主要作了三件事情,一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯,二是调用startSystemServer函数来启动SystemServer组件,三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。

Step 4.ZygoteInit.registerZygoteSocket

这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {....../*** Registers a server socket for zygote command connections** @throws RuntimeException when open fails*/private static void registerZygoteSocket() {if (sServerSocket == null) {int fileDesc;try {String env = System.getenv(ANDROID_SOCKET_ENV);fileDesc = Integer.parseInt(env);} catch (RuntimeException ex) {......}try {sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));} catch (IOException ex) {.......}}}......}
这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:

public class ZygoteInit {......private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";......}
那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:

void service_start(struct service *svc, const char *dynamic_args){......pid_t pid;......pid = fork();if (pid == 0) {struct socketinfo *si;......for (si = svc->sockets; si; si = si->next) {int socket_type = (!strcmp(si->type, "stream") ? SOCK_STREAM :(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));int s = create_socket(si->name, socket_type,si->perm, si->uid, si->gid);if (s >= 0) {publish_socket(si->name, s);}}......}......}
每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_socket函数写入到环境变量中去:

static void publish_socket(const char *name, int fd){    char key[64] = ANDROID_SOCKET_ENV_PREFIX;    char val[64];    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,            name,            sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));    snprintf(val, sizeof(val), "%d", fd);    add_environment(key, val);    /* make sure we don't close-on-exec */    fcntl(fd, F_SETFD, 0);}
这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:

#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了,参考 Android应用程序进程启动过程的源代码分析一文中的Step 4,ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的:

public class Process {  ......   private static void openZygoteSocketIfNeeded()  throws ZygoteStartFailedEx {  ......for (int retry = 0  ; (sZygoteSocket == null) && (retry < (retryCount + 1))  ; retry++ ) {  ......try {  sZygoteSocket = new LocalSocket();  sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,  LocalSocketAddress.Namespace.RESERVED));  sZygoteInputStream  = new DataInputStream(sZygoteSocket.getInputStream());  sZygoteWriter =  new BufferedWriter(  new OutputStreamWriter(  sZygoteSocket.getOutputStream()),  256);  ......  } catch (IOException ex) {  ......  }  }  ......  }  ......  }
这里的ZYGOTE_SOCKET定义为:

public class Process {  ......   private static final String ZYGOTE_SOCKET = "zygote";  ......  } 
它刚好就是对应/dev/socket目录下的zygote文件了。

Android系统中的socket机制和binder机制一样,都是可以用来进行进程间通信,读者可以自己对比一下这两者的不同之处,Binder进程间通信机制可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。

Step 5.ZygoteInit.startSystemServer
这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {......private static boolean startSystemServer()throws MethodAndArgsCaller, RuntimeException {/* Hardcoded command line to start the system server */String args[] = {"--setuid=1000","--setgid=1000","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003","--capabilities=130104352,130104352","--runtime-init","--nice-name=system_server","com.android.server.SystemServer",};ZygoteConnection.Arguments parsedArgs = null;int pid;try {parsedArgs = new ZygoteConnection.Arguments(args);....../* Request to fork the system server process */pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities);} catch (IllegalArgumentException ex) {......}/* For child process */if (pid == 0) {handleSystemServerProcess(parsedArgs);}return true;}......}
这里我们可以看到,Zygote进程通过Zygote.forkSystemServer函数来创建一个新的进程来启动SystemServer组件,返回值pid等0的地方就是新的进程要执行的路径,即新创建的进程会执行handleSystemServerProcess函数。

Step 6.ZygoteInit.handleSystemServerProcess
这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {......private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)throws ZygoteInit.MethodAndArgsCaller {closeServerSocket();/** Pass the remaining arguments to SystemServer.* "--nice-name=system_server com.android.server.SystemServer"*/RuntimeInit.zygoteInit(parsedArgs.remainingArgs);/* should never reach here */}......} 
由于由Zygote进程创建的子进程会继承Zygote进程在前面Step 4中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。

Step 7.RuntimeInit.zygoteInit

这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class RuntimeInit {  ......  public static final void zygoteInit(String[] argv)  throws ZygoteInit.MethodAndArgsCaller {  ......    zygoteInitNative();  ......  // Remaining arguments are passed to the start class's static main  String startClass = argv[curArg++];  String[] startArgs = new String[argv.length - curArg];  System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  invokeStaticMain(startClass, startArgs);  }  ......  }
这个函数会执行两个操作,一个是调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作,这个工作完成之后,这个进程中的Binder对象就可以方便地进行进程间通信了,另一个是调用上面Step 5传进来的com.android.server.SystemServer类的main函数。

Step 8.RuntimeInit.zygoteInitNative

这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

public class RuntimeInit {  ......  public static final native void zygoteInitNative();  ......  }
这里可以看出,函数zygoteInitNative是一个Native函数,实现在frameworks/base/core/jni/AndroidRuntime.cpp文件中,这里我们就不再细看了,具体可以参考 Android应用程序进程启动过程的源代码分析一文的Step 9,完成这一步后,这个进程的Binder进程间通信机制基础设施就准备好了。

回到Step 7中的RuntimeInit.zygoteInitNative函数,下一步它就要执行com.android.server.SystemServer类的main函数了。

Step 9.SystemServer.main

这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中:

public class SystemServer  {  ......  native public static void init1(String[] args);  ......  public static void main(String[] args) {  ......  init1(args);  ......  } public static final void init2() {  Slog.i(TAG, "Entered the Android system server!");  Thread thr = new ServerThread();  thr.setName("android.server.ServerThread");  thr.start();  }  ......  }
这里的main函数首先会执行JNI方法init1,然后init1会调用这里的init2函数,在init2函数里面,会创建一个ServerThread线程对象来执行一些系统关键服务的启动操作,例如我们在前面两篇文章 Android应用程序安装过程源代码分析和 Android系统默认Home应用程序(Launcher)的启动过程源代码分析中提到的PackageManagerService和ActivityManagerService。
这一步的具体执行过程可以参考 Android应用程序安装过程源代码分析一文,这里就不再详述了。

这里执行完成后,层层返回,最后回到上面的Step 3中的ZygoteInit.main函数中,接下来它就要调用runSelectLoopMode函数进入一个无限循环在前面Step 4中创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程了。

Step 10.ZygoteInit.runSelectLoopMode

这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

public class ZygoteInit {......private static void runSelectLoopMode() throws MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList();ArrayList<ZygoteConnection> 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);}}}}......}      
这个函数我们已经在 Android应用程序进程启动过程的源代码分析一文的Step 5中分析过了,这就是在等待ActivityManagerService来连接这个Socket,然后调用ZygoteConnection.runOnce函数来创建新的应用程序,有兴趣的读者可以参考 Android应用程序进程启动过程的源代码分析这篇文章,这里就不再详述了。

这样,Zygote进程就启动完成了,学习到这里,我们终于都对Android系统中的进程有了一个深刻的认识了,这里总结一下:

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

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

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

作者:Luoshengyang 发表于2011-9-19 0:59:08 原文链接 阅读:5235 评论:8 查看评论


更多相关文章

  1. C语言函数的递归(上)
  2. Android跨进程数据通讯-剪切板Clipboard
  3. android : 修改frameworks/base/ 代码需要注意的地方
  4. android编写Service入门用法与教程
  5. Android开发中完全退出程序的三种方法
  6. MyEclipse安装Android(安卓)ADT 方法,亲测,能用
  7. Android(安卓)suspend底层流程解析
  8. Android导入一个工程时提示 Invalid project description的解决
  9. Android(安卓)获取mp4文件中任意时间点的帧图片(MediaMetadataRe

随机推荐

  1. android 中文 api (71) ―― BluetoothServ
  2. React native Android(安卓)命令 打包apk
  3. 51. (android开发)线性布局、相对布局、
  4. Android札记
  5. 关于“Only the original thread that cr
  6. Android换肤机制
  7. Android点击事件的四种写法
  8. Android编程: 环境搭建、基本知识
  9. 杂七杂八2
  10. Android去除标题栏及自定义title栏