Android 6.0 系统学习之 Zygote
一次看到 Zygote 时,不明白这个名字什么意思,查了一下发现是受精卵的意思。Zygote 是 Android 系统中启动应用程序与系统服务的服务。
学习 Zygote 这个服务,我想弄明白这些问题:
- Zygote 自己是由谁启动的?
- Zygote 都能启动哪些东西?
- 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
其中:
- 关键字 service 表示告诉 init 进程创建名为 zygote 的进程,所要执行的程序是 /system/bin/app_process,后面的都是传递的参数。
- 注意参数 --start-system-server,说明要启动 SystemServer
- socket zygote stream 660 root system 表示创建名为 zygote 的 socket。
- 后面的 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 的大体流程为:
- 创建一个 AppRuntime 实例 runtime
- 解析传入的命令行参数
- 判断调用哪一个 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 的底层操作也没有挖掘彻底。我想,对于了解来说,已经足够了。