转载

Android 6.0 系统学习之 Zygote

一次看到 Zygote 时,不明白这个名字什么意思,查了一下发现是受精卵的意思。Zygote 是 Android 系统中启动应用程序与系统服务的服务。

学习 Zygote 这个服务,我想弄明白这些问题:

  1. Zygote 自己是由谁启动的?
  2. Zygote 都能启动哪些东西?
  3. Zygote 是如何启动其他程序、服务的?

现有资源

现有的关于 Zygote 的文章已有很多。但是纸上得来终觉浅,绝知此事要孤行。前辈分享的知识,吃透理解后,沉淀成自己的东西才算是自己的。

在这篇文章中,我主要学习了 邓凡平的《Android深入浅出之Zygote》 、 老罗的《Android系统进程Zygote启动过程的源代码分析》 。感谢这些前辈的无私奉献,它们的努力,使我在后来的学习中减少了许多困难。

谁负责启动 Zygote?

既然 Zygote 负责启动 Android 系统的各个部分,我的第一个问题是它自己是如何自举的?

Android 以 Linux 为核心,这个问题交给了 Linux。init 程序 Linux 中负责载入 Linux 各个部分的程序,它在成功加载 Linux 系统后,按照 Android 启动脚本 init.rc 文件中的配置,加载 Zygote。

配置文件在 Android 6.0 代码中位于 system/core/rootdir/init.zygote32.rc,具体内容为:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server     class main     socket zygote stream 660 root system     onrestart write /sys/android_power/request_state wake     onrestart write /sys/power/state on     onrestart restart media     onrestart restart netd 

其中:

  1. 关键字 service 表示告诉 init 进程创建名为 zygote 的进程,所要执行的程序是 /system/bin/app_process,后面的都是传递的参数。
  2. 注意参数 --start-system-server,说明要启动 SystemServer
  3. socket zygote stream 660 root system 表示创建名为 zygote 的 socket。
  4. 后面的 onrestart 关键字表示 zygote 进程重启时所需执行的命令。

Zygote 的启动

从中我们可以得出结论: zygote 只是服务的名称,与此服务对应的程序是 app_process 程序,我们研究 zygote 的实现,就是要研究 app_process 程序。

app_process 程序

app_process 代码位于 frameworks/base/cmds/app_process/app_main.cpp,入口函数为 main。将 main 函数的主要逻辑抽象出来:

int main(int argc, char* const argv[]) {     ...     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));     ...     // 解析参数,设置 Flag...     ...     if (zygote) {         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);     } else if (className) {         runtime.start("com.android.internal.os.RuntimeInit", args, zygote);     } else {         ...         return 10;     } } 

main 的大体流程为:

  1. 创建一个 AppRuntime 实例 runtime
  2. 解析传入的命令行参数
  3. 判断调用哪一个 runtime.start,传入对应的参数

由于 init.zygote32.rc 中传入参数 -Xzygote /system/bin --zygote --start-system-server,因此将执行:

runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 

由此可知,app_process 没干什么主要的事情,只是跳转到 Java 类 com.android.internal.os.ZygoteInit,看来工作都在 ZygoteInit 中完成。

在跳到 ZygoteInit 之前,先来看看 app_process 中用到的 AppRuntime。

AndroidRuntime

start 方法来自于 AppRuntime 的父类 AndroidRuntime,代码位于 frameworks/base/core/jni/AndroidRuntime.cpp。来看 start 方法 (在 6.0 代码中位于 1007 行):

/*  * 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".  * 启动 Android 运行时。这包括启动虚拟机和调用 "className" 对应的类  * 的 "static void main(String[] args)" 方法。  *  * Passes the main function two arguments, the class name and the specified  * options string.  * 将会向指定类的 main 函数传入两个参数,也就是 start 函数的 className   * 和 options  */  void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)  {     ...     /* start the virtual machine */     JniInvocation jni_invocation;     jni_invocation.Init(NULL);     JNIEnv* env;     if (startVm(&mJavaVM, &env, zygote) != 0) {         return;     }     onVmCreated(env);      /*      * Register android functions.      */     if (startReg(env) < 0) {         ALOGE("Unable to register all android natives/n");         return;     }      ...      /*      * Start VM.  This thread becomes the main thread of the VM, and will      * not return until the VM exits.      */     char* slashClassName = toSlashClassName(className);     jclass startClass = env->FindClass(slashClassName);     if (startClass == NULL) {         ALOGE("JavaVM unable to locate class '%s'/n", slashClassName);         /* keep going */     } else {         jmethodID startMeth = env->GetStaticMethodID(startClass, "main",             "([Ljava/lang/String;)V");         if (startMeth == NULL) {             ALOGE("JavaVM unable to find main() in '%s'/n", className);             /* keep going */         } else {             env->CallStaticVoidMethod(startClass, startMeth, strArray);  #if 0             if (env->ExceptionCheck())                 threadExitUncaughtException(env); #endif         }     }     free(slashClassName);     ... } 

AndroidRuntime 的 runtime 主要做了三件事:

首先是创建虚拟机:

/* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) {    return; } onVmCreated(env); 

之后是调用 startReg 函数注册 JNI 方法:

/* * Register android functions. */ if (startReg(env) < 0) {    ALOGE("Unable to register all android natives/n");    return; } 

最后构建参数、创建 JNI 类对象,获取 main 方法,并最终执行下面一行执行 main 入口:

env->CallStaticVoidMethod(startClass, startMeth, strArray); 

这样我们就成功从 C 中启动了一个虚拟机,并加载了 Java 类 ZygoteInit,并进入到它的 main 方法中执行。

ZygoteInit

之后就来到了 ZygoteInit.java 的 main 方法,代码位于 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java。来看其 main 方法:

public static void main(String argv[]) {    try {        ...        registerZygoteSocket(socketName);        ...        if (startSystemServer) {            startSystemServer(abiList, socketName);        }        ...        runSelectLoop(abiList);        ...    } catch (...) { ... } } 

首先,调用 registerZygoteSocket 创建了一个名为 zygote 的 socket:

registerZygoteSocket(socketName); 

之后启动 SystemServer 组件:

if (startSystemServer) {  startSystemServer(abiList, socketName); } 

最后调用 runSelectLoopMode 进入一个死循环,等待接受 socket 上由 ActivityManagerService 发来的请求创建应用程序的请求:

runSelectLoop(abiList); 

下面我们就对后两个步骤详细分析。

一、启动 SystemServer 组件

SystemServer 名为系统服务进程,负责启动 Android 系统的关键服务。来看看函数的主要实现:

private static boolean startSystemServer(String abiList, String socketName)        throws MethodAndArgsCaller, RuntimeException {     ...     /* Request to fork the system server process */     pid = Zygote.forkSystemServer(         parsedArgs.uid, parsedArgs.gid,         parsedArgs.gids,         parsedArgs.debugFlags,         null,         parsedArgs.permittedCapabilities,         parsedArgs.effectiveCapabilities);     ...     /* For child process */     if (pid == 0) {         ...         handleSystemServerProcess(parsedArgs);     }     return true; } 

首先调用了 Zygote 的静态方法 forkSystemServer 来创建 SystemServer 进程。这也是我首次看到 Zygote 是如何孵♂化出东西来的。

我们进入 forkSystemServer 看看具体实现:

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,        int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {    ...    int pid = nativeForkSystemServer(            uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);    ...    return pid; } 

可见,这又调用了 nativeForkSystemServer,这是一个 jni 调用,对应的函数为 com_android_internal_os_Zygote_nativeForkSystemServer,位于:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp,来看看它的实现:

static jint com_android_internal_os_Zygote_nativeForkSystemServer(         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,         jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,         jlong effectiveCapabilities) {   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,                                       debug_flags, rlimits,                                       permittedCapabilities, effectiveCapabilities,                                       MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,                                       NULL, NULL);   ...   return pid; } 

在这里调用了 ForkAndSpecializeCommon 函数,它是一个静态函数,用来 fork Zygote 并设置子进程。代码比较多,看看它的主要实现:

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,                                      jint debug_flags, jobjectArray javaRlimits,                                      jlong permittedCapabilities, jlong effectiveCapabilities,                                      jint mount_external,                                      jstring java_se_info, jstring java_se_name,                                      bool is_system_server, jintArray fdsToClose,                                      jstring instructionSet, jstring dataDir) {   ...   pid_t pid = fork();   if (pid == 0) {     ...     // 对子线程进行了一大堆设置     ...   }   return pid; }  

首先,执行 fork() 创建了一个子进程。在子进程中进行了一大堆设置。

跳了这么一大堆,来梳理一下。启动 SystemServer,首先要创建一个新进程,可我们现在在 Java 中,需要会到 C 中进行 fork(),我们通过 forkSystemServer - com_android_internal_os_Zygote_nativeForkSystemServer - ForkAndSpecializeCommon 来实现 JNI 调用并成功 fork,这样新进程就有了。

让我们回到本节的一开始的 startSystemServer,现在子进程已经创建好了,接着往下看。在创建的子进程中,有一句 handleSystemServerProcess(parsedArgs),进入看看实现:

    /**      * Finish remaining work for the newly forked system server process.      */     private static void handleSystemServerProcess(             ZygoteConnection.Arguments parsedArgs)             throws ZygoteInit.MethodAndArgsCaller {     ...     final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");     ...     if (...) {         ...     } else {       ClassLoader cl = null;       if (systemServerClasspath != null) {           cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());           Thread.currentThread().setContextClassLoader(cl);       }        /*        * Pass the remaining arguments to SystemServer.        */       RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);     } 

从中可以看出,我们从环境变量 SYSTEMSERVERCLASSPATH 拿到 SystemServer 的类名,之后载入进来,最后使用 RuntimeInit.zygoteInit 来运行,它来执行 SystemServer 的 main 方法。

RuntimeInit.zygoteInit 的具体实现可以简单看一下:

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)         throws ZygoteInit.MethodAndArgsCaller {     ...     commonInit();   // 基本设置(异常捕获、时区、HTTP User-Agent 等)     nativeZygoteInit();     applicationInit(targetSdkVersion, argv, classLoader); // 调用 Main 方法 } 

其中 nativeZygoteInit() 是一个 jni 调用,位于 AndroidRuntime.cpp:

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {     gCurRuntime->onZygoteInit(); } 

onZygoteInit() 是 AppRuntime 中的方法,具体为:

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

可见是启动了一个线程池。nativeZygoteInit() 就分析到这里,由此可见,Zygote 启动 SystemServer 的过程就算完了,之后的,都是 SystemServer 内部的事情了。

二、runSelectLoop

下面看看 runSelectLoop 的实现。

/** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. *  * 运行 zygote 进程的 select 循环。接受新的连接,读取指令。 * * @throws MethodAndArgsCaller in a child process when a main() should * be executed. *  * 如果有 main() 需要被执行,抛出 MethodAndArgsCaller 异常。 */ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();     fds.add(sServerSocket.getFileDescriptor());    peers.add(null);     while (true) {        StructPollfd[] pollFds = new StructPollfd[fds.size()];        for (int i = 0; i < pollFds.length; ++i) {            pollFds[i] = new StructPollfd();            pollFds[i].fd = fds.get(i);            pollFds[i].events = (short) POLLIN;        }        try {            Os.poll(pollFds, -1);        } catch (...) {            ...        }        for (int i = pollFds.length - 1; i >= 0; --i) {            if ((pollFds[i].revents & POLLIN) == 0) {                continue;            }            if (i == 0) {                ZygoteConnection newPeer = acceptCommandPeer(abiList);                peers.add(newPeer);                fds.add(newPeer.getFileDesciptor());            } else {                boolean done = peers.get(i).runOnce();                if (done) {                    peers.remove(i);                    fds.remove(i);                }            }        }    } } 

首先获取 socket 并加入到 fds 中:

fds.add(sServerSocket.getFileDescriptor()); 

之后执行:

Os.poll(pollFds, -1); 

poll 会判断 pollFds 是否可读,若不可读则阻塞等待。

之后进入 for 循环:

for (int i = pollFds.length - 1; i >= 0; --i) {     if ((pollFds[i].revents & POLLIN) == 0) {         continue;     }     if (i == 0) {         ZygoteConnection newPeer = acceptCommandPeer(abiList);         peers.add(newPeer);         fds.add(newPeer.getFileDesciptor());     } else {         boolean done = peers.get(i).runOnce();         if (done) {             peers.remove(i);             fds.remove(i);         }     } } 

首先看是否已经在处理队列中,若已在,则处理下一个。之后看新加的(最后一个又是未处理,那就是新家的),那就解析参数加进去。最后,对于已经加入的,判断一下是否完成,完成了就从列表中删除。

注意,这些代码都套在 while(true) 死循环里,这个 poll 的过程会一直进行。

由此可见,Zygote 到这里就算启动完了,并进入了一个死循环,要想启动个东西,就从 socket 向它发指令,他就会孵♂化。

至此,我关于 Zygote 的疑问基本搞明白了。本文对于 Zygote 的机制挖掘并不很深,对于 Zygote 的底层操作也没有挖掘彻底。我想,对于了解来说,已经足够了。

正文到此结束
Loading...