Android 6.0 系统学习之 Zygote

jopen 9年前

一次看到 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 的底层操作也没有挖掘彻底。我想,对于了解来说,已经足够了。

来自:http://www.judymax.com/archives/1118