Android FrameWork - Zygote 启动流程分析
基于 Android 12 源码
涉及文件:
system/core/rootdir/init.rc
system/core/rootdir/init.zygote64.rc
system/core/rootdir/init.zygote32.rc
frameworks/base/cmds/app_process/app_main.cpp
frameworks/base/core/jni/AndroidRuntime.cpp
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
Zygote 进程是由 init 进程通过解析 init.rc 文件而创建的。在 init.rc
中,有以下关键代码段,负责触发 Zygote 进程的启动:
on late-init# ... 其他 late-init 动作 ...# Now we can start zygote for devices with file based encryptiontrigger zygote-start
这个 trigger zygote-start
语句是一个事件触发器,当 late-init
事件发生时,它会触发 zygote-start
事件。
当 zygote-start
事件被触发后,init
会开始寻找定义了该事件的 service
(服务)
在 Android 12 中,Zygote 服务的定义位于特定的 .rc
文件中,以支持不同的架构:
init.zygote64.rc
: 针对 64 位设备,定义了 64 位 Zygote 服务。init.zygote32.rc
: 针对 32 位设备,定义了 32 位 Zygote 服务。init.zygote64_32.rc
: 针对 64 位设备但需要兼容 32 位应用程序的情况,定义了 64 位和 32 位 Zygote 服务。
以 init.zygote64.rc
为例:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart exec_background - system system -- /system/bin/vdc volume abort_fuseonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/taskscritical window=${zygote.critical_window.minute:-off} target=zygote-fatal
当 zygote-start
事件发生时,这些代码就会被执行,-Xzygote
: 告诉 app_process
这个进程是 Zygote。--start-system-server
: 告诉 Zygote 进程在自身启动完成后,立即启动 System Server
进程。
这里 /system/bin/app_process64
是由源码编译生成的二进制,不要纠结为什么找不到该文件,而frameworks/base/cmds/app_process/app_main.cpp
才是 Zygote 的原生入口,无论 app_process32
还是 app_process64
,它们的 C++ 主函数入口都是 app_main.cpp
中的 main()
函数。
main 函数源码:
int main(int argc, char* const argv[])
{// ...// AppRuntime 是 AndroidRuntime 的子类(定义在 app_main.cpp 中)。// 初始化 JNI 环境 > 启动 ART/Dalvik 虚拟机 > 注册 JNI 方法 > 最终调用 Java 类的 main() 方法// argv[0] 是可执行文件路径(如/system/bin/app_process64)AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments// ignore argv[0]argc--;argv++;const char* spaced_commands[] = { "-cp", "-classpath" };// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).bool known_command = false;// 下面代码是把以 - 开头的参数(如 -Xzygote、-Dxxx)作为 虚拟机参数,添加到 runtime 中。// 这些参数会传递给 ART 虚拟机(类似 JVM 的 -Xmx, -XX: ..)int i;for (i = 0; i < argc; i++) {if (known_command == true) {runtime.addOption(strdup(argv[i]));// The static analyzer gets upset that we don't ever free the above// string. Since the allocation is from main, leaking it doesn't seem// problematic. NOLINTNEXTLINEALOGV("app_process main add known option '%s'", argv[i]);known_command = false;continue;}for (int j = 0;j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));++j) {if (strcmp(argv[i], spaced_commands[j]) == 0) {known_command = true;ALOGV("app_process main found known command '%s'", argv[i]);}}if (argv[i][0] != '-') {break;}if (argv[i][1] == '-' && argv[i][2] == 0) {++i; // Skip --.break;}runtime.addOption(strdup(argv[i]));// The static analyzer gets upset that we don't ever free the above// string. Since the allocation is from main, leaking it doesn't seem// problematic. NOLINTNEXTLINEALOGV("app_process main add option '%s'", argv[i]);}// Parse runtime arguments. Stop at first unrecognized option.bool zygote = false;bool startSystemServer = false;bool application = false;String8 niceName;String8 className;// 解析参数// 最关键的分支,通过设置 zygote 变量决定进程是 Zygote 还是普通应用!++i; // Skip unused "parent dir" argument.while (i < argc) {const char* arg = argv[i++];if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = ZYGOTE_NICE_NAME;} 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.setTo(arg + 12);} else if (strncmp(arg, "--", 2) != 0) {className.setTo(arg);break;} else {--i;break;}}Vector<String8> args;if (!className.isEmpty()) {// 非 Zygote 模式:启动普通应用// We're not in zygote mode, the only argument we need to pass// to RuntimeInit is the application argument.//// The Remainder of args get passed to startup class main(). Make// copies of them before we overwrite them with the process name.args.add(application ? String8("application") : String8("tool"));runtime.setClassNameAndArgs(className, argc - i, argv + i);if (!LOG_NDEBUG) {String8 restOfArgs;char* const* argv_new = argv + i;int argc_new = argc - i;for (int k = 0; k < argc_new; ++k) {restOfArgs.append(""");restOfArgs.append(argv_new[k]);restOfArgs.append("" ");}ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());}} else {// Zygote 模式// We're in zygote mode.maybeCreateDalvikCache();if (startSystemServer) {args.add(String8("start-system-server"));}char prop[PROP_VALUE_MAX];if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",ABI_LIST_PROPERTY);return 11;}String8 abiFlag("--abi-list=");abiFlag.append(prop);args.add(abiFlag);// In zygote mode, pass all remaining arguments to the zygote// main() method.for (; i < argc; ++i) {args.add(String8(argv[i]));}}// 设置进程名,默认 static const char ZYGOTE_NICE_NAME[] = "zygote";if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string(), true /* setProcName */);}// 启动 Java 层,准备起飞~// Java层入口为 ZygoteInit.main()if (zygote) {runtime.start("com.android.internal.os.ZygoteInit", args, zygote);} else if (className) {runtime.start("com.android.internal.os.RuntimeInit", args, zygote);} else {fprintf(stderr, "Error: no class name or --zygote supplied.\n");app_usage();LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");}
}
runtime 源码位置位于 frameworks/base/core/jni/AndroidRuntime.cpp
这是 Android 原生(C++)代码的一部分,属于 JNI 框架层。
runtime.start 源码:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{// ...// ========================================================================// STEP 1: 初始化 JNI 调用环境(JniInvocation)// ========================================================================JniInvocation jni_invocation;jni_invocation.Init(NULL); // 初始化 JNI 层调用框架(加载 libart.so 等)JNIEnv* env;// 调用 startVm() 实际启动 ART 虚拟机if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {ALOGE("startVm failed");return;}// 虚拟机创建成功后的回调onVmCreated(env);// ========================================================================// STEP 2: 注册所有系统级 JNI 方法// 如:android.os, android.app, android.content 等包下的 native 函数// ========================================================================if (startReg(env) < 0) {ALOGE("Unable to register all android natives\n");return;}// 示例:注册后,Java 层调用 android.os.SystemClock.uptimeMillis()// 才能正确跳转到 native 对应的 C++ 函数// ========================================================================// STEP 3: 构造 Java 层 main(String[] args) 所需的参数数组// ========================================================================jclass stringClass;jobjectArray strArray; // 对应 String[]jstring classNameStr; // 对应 className 参数// 查找 java.lang.String 类stringClass = env->FindClass("java/lang/String");assert(stringClass != NULL);// 创建 String 数组,长度 = 参数个数 + 1(+1 是主类名)strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);assert(strArray != NULL);// 第一个元素:主类名(如 com.android.internal.os.ZygoteInit)classNameStr = env->NewStringUTF(className);assert(classNameStr != NULL);env->SetObjectArrayElement(strArray, 0, classNameStr);// 后续元素:传入的 options 参数(如 start-system-server, --abi-list=...)for (size_t i = 0; i < options.size(); ++i) {jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());assert(optionsStr != NULL);env->SetObjectArrayElement(strArray, i + 1, optionsStr);}// ========================================================================// STEP 4: 查找并调用 Java 主类的 main() 方法// 实现从 Native 到 Java 的“点火”// ========================================================================char* slashClassName = toSlashClassName(className != NULL ? className : "");// 将点号分隔类名转为斜杠分隔,如 com.example.App → com/example/App// 查找 Java 类jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);} else {// 获取 main 方法的 Method ID// 签名:([Ljava/lang/String;)V → 接收 String[],返回 voidjmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");if (startMeth == NULL) {ALOGE("JavaVM unable to find main() in '%s'\n", className);} else {// 正式调用 Java 层 main 方法!// 控制权从此转移到 Java 层 🛫env->CallStaticVoidMethod(startClass, startMeth, strArray);// !!!无限循环开始,后续代码不会被执行!!!// 程序“进入” Java 层,永不返回// 可选:检查是否有未捕获异常
#if 0if (env->ExceptionCheck())threadExitUncaughtException(env);
#endif}}free(slashClassName); // 释放转换后的类名字符串// ========================================================================// STEP 5: 收尾工作(正常情况下不会执行到这里)// 因为 main() 是无限循环,不会返回// ========================================================================ALOGD("Shutting down VM\n");// 尝试分离当前线程(主线程)if (mJavaVM->DetachCurrentThread() != JNI_OK)ALOGW("Warning: unable to detach main thread\n");// 销毁虚拟机(通常不会执行)if (mJavaVM->DestroyJavaVM() != 0)ALOGW("Warning: VM did not shut down cleanly\n");
}
虚拟机已经被启动,通过 JNI 调用 Java 代码,Java 代码就可以在虚拟机跑起来了,接下来完全进入 Java 代码内容,呜呜呜~,终于到能看懂的代码了
接下来就来到了 ZygoteInit.java
,源码位置:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
在线查看:https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/com/android/internal/os/ZygoteInit.java
入口函数 main() 源码分析:
@UnsupportedAppUsagepublic static void main(String[] argv) {ZygoteServer zygoteServer = null;// Mark zygote start. This ensures that thread creation will throw// an error.// 🔹 防止在 Zygote 初始化过程中创建线程// 因为 fork() 前不能有多余线程(否则会导致 fork 安全问题)// 调用此方法后,任何尝试创建线程的操作都会抛出异常ZygoteHooks.startZygoteNoThreadCreation();// Zygote goes into its own process group.try {Os.setpgid(0, 0); // setpgid(pid, pgid): pid=0 表示当前进程} catch (ErrnoException ex) {throw new RuntimeException("Failed to setpgid(0,0)", ex);}Runnable caller;try {// Store now for StatsLogging later.// 判断是否是“运行时重启”(如 system_server 崩溃后重启)// sys.boot_completed=1 表示系统已启动完成final long startTime = SystemClock.elapsedRealtime();final boolean isRuntimeRestarted = "1".equals(SystemProperties.get("sys.boot_completed"));// 根据是 32 位还是 64 位 Zygote 选择不同的 trace tagString bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);bootTimingsTraceLog.traceBegin("ZygoteInit");RuntimeInit.preForkInit();// 解析启动参数boolean startSystemServer = false; // 是否启动 system_serverString zygoteSocketName = "zygote"; // Zygote socket 名称String abiList = null; // 支持的 ABI 列表(如 arm,x86,arm64)boolean enableLazyPreload = false; // 是否延迟预加载// 🔹 解析命令行参数(来自 app_process 的启动参数)for (int i = 1; i < argv.length; i++) {if ("start-system-server".equals(argv[i])) {startSystemServer = true; // 标记:需要 fork system_server} else if ("--enable-lazy-preload".equals(argv[i])) {enableLazyPreload = true; // 延迟预加载(节省启动时间)} else if (argv[i].startsWith(ABI_LIST_ARG)) {abiList = argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException("Unknown command line argument: " + argv[i]);}}// 判断是否为主 Zygote(即 zygote 或 zygote64)final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);if (!isRuntimeRestarted) {if (isPrimaryZygote) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,startTime);} else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,startTime);}}// 必须提供 ABI 列表,否则无法知道支持哪些指令集if (abiList == null) {throw new RuntimeException("No ABI list supplied.");}// In some configurations, we avoid preloading resources and classes eagerly.// In such cases, we will preload things prior to our first fork.// 🔹 预加载核心资源(类、资源、共享库)// 如果未启用“延迟预加载”,则在此处立即执行if (!enableLazyPreload) {bootTimingsTraceLog.traceBegin("ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());// 执行预加载(核心优化:让所有应用共享这些已加载的类)preload(bootTimingsTraceLog);EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload}// Do an initial gc to clean up after startup// 🔹 执行一次 GC,清理启动期间产生的垃圾对象// 因为 preload() 加载了大量类,可能产生临时对象bootTimingsTraceLog.traceBegin("PostZygoteInitGC");gcAndFinalize();// 显式触发 GC 和 finalizebootTimingsTraceLog.traceEnd(); // PostZygoteInitGCbootTimingsTraceLog.traceEnd(); // ZygoteInit// 🔹 初始化 native 层状态(如注册 fork hook、设置信号处理等)Zygote.initNativeState(isPrimaryZygote);// 🔹 允许线程创建(Zygote 初始化阶段结束)// 之前调用 startZygoteNoThreadCreation() 禁止了线程创建ZygoteHooks.stopZygoteNoThreadCreation();// 🔹 创建 ZygoteServer,用于监听 socket 连接// 它会监听来自 ActivityManagerService 的启动请求zygoteServer = new ZygoteServer(isPrimaryZygote);// 🔹 尝试 fork 出 system_server 进程(系统服务宿主)if (startSystemServer) {// forkSystemServer() 在父进程(Zygote)中返回 null// 在子进程(system_server)中返回一个 Runnable 任务Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {@code r == null} in the parent (zygote) process, and {@code r != null} in the// child (system_server) process.if (r != null) {r.run();return;// 子进程执行完后退出,不再继续下面的 select loop}// 注意:父进程(Zygote)继续向下执行}Log.i(TAG, "Accepting command socket connections");// The select loop returns early in the child process after a fork and// loops forever in the zygote.// 🔹 进入无限循环,监听 socket// - 在 Zygote 父进程中:永远循环,等待 fork 请求// - 在 fork 出的子进程中:立即返回一个 Runnable 任务caller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with fatal exception", ex);throw ex;} finally {// 异常清理:关闭 socket(正常流程不会执行到这里)if (zygoteServer != null) {zygoteServer.closeServerSocket();}}// We're in the child process and have exited the select loop. Proceed to execute the// command.// 🔹 只有在子进程中才会执行到这里(caller != null)// caller 是从 runSelectLoop() 返回的 Runnable 任务// 通常是启动某个应用进程的初始化逻辑if (caller != null) {caller.run();}}
ZygoteInit.main()
是 Android 的“生命之源”——它预加载万物,孵化系统,静候召唤,永不停歇。
这里有一点反直觉的代码,ZygoteInit.main()
只被执行一次,而 这段代码却有两个分支,一个是子进程一个是父进程的:
// 🔹 尝试 fork 出 system_server 进程(系统服务宿主)if (startSystemServer) {// forkSystemServer() 在父进程(Zygote)中返回 null// 在子进程(system_server)中返回一个 Runnable 任务Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {@code r == null} in the parent (zygote) process, and {@code r != null} in the// child (system_server) process.if (r != null) {r.run();return;// 子进程执行完后退出,不再继续下面的 select loop}// 注意:父进程(Zygote)继续向下执行}
相当于 forkSystemServer 返回了两个值!一个为 null 一个不为 null,神不神奇,其实 forkSystemServer 仍只会返回一个值,开机的时候 系统服务一定会被创建,Zygote 更会被创建,代表着 forkSystemServer 之上的代码仍会被执行一次,forkSystemServer 及以下的代码会被执行两次。
why?神奇之处就在与 多进程,fork()
之后,这个方法的后续代码会被两个进程执行,举个例子,把 fork 当成克隆,想象科学家有一个“启动程序”:
1. 准备实验材料
2. 克隆一个自己(fork)
3. 如果我是克隆人(r != null):执行任务:去火星完成后死亡
4. 如果我是原版(r == null):继续在地球等待,准备下一次克隆
这就是Linux 的 fork()
行为,神奇所在:
在 C 语言里你可能见过这样的写法:
pid_t pid = fork();
if (pid == 0) {// 子进程逻辑
} else if (pid > 0) {// 父进程逻辑
}
一次调用,两次返回!
这里最神奇的就是:
- 只有 一次调用
fork()
,但它会在 父进程返回子进程 PID ,在 子进程返回 0 。 - 所以,父子进程都会“继续执行 fork() 之后的代码”,但执行路径不同。
zygote进程内加载了preload()方法中的所有资源,当需要fork新进程时,采用copy on write技术,如下:
完整流程图:
- 解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法;
- 调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
- 通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
- registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
- preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高ap启动效率;
- zygote完毕大部分工作,接下来再通过startSystemServer(),fork得力帮手system_server进程,也是上层framework的运行载体。
- zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。