Skip to content

ZygoteInit.main

追踪 ZygoteInit.main 的参数解析、预加载、forkSystemServer、父子进程分流和 socket 循环交接。

基于android-17.0.0_r1
AndroidZygoteSystemServer源码阅读

ZygoteInit.main ​

SS003 已说明 AndroidRuntime.start() 如何把控制权交给 Java。现在进入 Java 入口 ZygoteInit.main():它不是普通的 main 函数,而是把“禁止过早建线程、预加载、初始 GC、native 状态、fork SystemServer、创建 ZygoteServer、进入命令循环”排成严格顺序。本文只负责这条启动编排;预加载子项、SystemServer 服务组和应用 fork 参数将在后续文章分别展开。

1. 入口状态 ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

相关函数:main(String[] argv)

java
public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;
    ZygoteHooks.startZygoteNoThreadCreation();
    try {
        Os.setpgid(0, 0);
        final long startTime = SystemClock.elapsedRealtime();
        final boolean isRuntimeRestarted = "1".equals(
                SystemProperties.get("sys.boot_completed"));
        String bootTimeTag = Process.is64Bit()
                ? "Zygote64Timing" : "Zygote32Timing";
        TimingsTraceLog bootTimingsTraceLog =
                new TimingsTraceLog(bootTimeTag, Trace.TRACE_TAG_DALVIK);
        RuntimeInit.preForkInit();

startZygoteNoThreadCreation() 先把 fork 前的线程创建约束设置好;setpgid(0, 0) 让 Zygote 进入自己的进程组,便于后续管理。启动计时和 RuntimeInit.preForkInit() 属于运行时准备,不是服务注册,也不是应用进程 specialization。

2. 参数解析与ABI ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

java
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
    if ("start-system-server".equals(argv[i])) {
        startSystemServer = true;
    } 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]);
    }
}

if (abiList == null) {
    throw new RuntimeException("No ABI list supplied.");
}

start-system-server 控制是否执行 forkSystemServer();--enable-lazy-preload 延后预加载;ABI 列表供 ZygoteServer 和后续连接选择可用指令集;socket 名称区分 primary/secondary Zygote。未知参数直接抛异常,说明这不是可忽略的业务 option,而是 Zygote 启动协议错误。

3. 预加载与初始GC ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

java
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();
}

bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd();

预加载默认发生在第一次 fork 之前,使子进程可以通过 COW 共享已加载的类、资源和运行时结构。启用 lazy preload 时,这里跳过即时加载,但代码仍在第一次 fork 前通过其他路径补齐所需资源。gcAndFinalize() 清理启动阶段临时对象;它不是“回收所有未来应用对象”,而是为 fork 建立更稳定的初始堆状态。

4. Native状态 ​

java
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
zygoteServer = new ZygoteServer(isPrimaryZygote);

这三步分别完成 native Zygote 状态初始化、解除“禁止创建线程”的启动阶段限制、建立 Java ZygoteServer。顺序不能交换:服务器对象要在 native 状态准备后创建;解除限制也必须发生在 fork 前准备完成之后。

5. 父子分流 ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

java
if (startSystemServer) {
    Runnable r = forkSystemServer(
            abiList, zygoteSocketName, zygoteServer);
    // parent: null; child: Runnable
    if (r != null) {
        r.run();
        return;
    }
}

forkSystemServer() 在子进程返回一个进入 SystemServer 的 Runnable,在父 Zygote 返回 null。子进程运行 Runnable 后直接 return,不再继续监听 Zygote socket;父进程则继续执行下面的 runSelectLoop()。这正是“SystemServer 是 Zygote fork 的子进程,而不是 ZygoteServer 的一个普通客户端”的源码证据。

6. Socket收尾 ​

java
} catch (Throwable ex) {
    Log.e(TAG, "System zygote died with fatal exception", ex);
    throw ex;
} finally {
    if (zygoteServer != null) {
        zygoteServer.closeServerSocket();
    }
}

if (caller != null) {
    caller.run();
}

finally 无论异常还是 select loop 提前返回都会尝试关闭 server socket。正常父 Zygote 的 select loop 不返回;子进程在 fork 后提前返回时,closeServerSocket() 防止继承的监听 fd 留在 SystemServer。若 caller 非空,表示当前已是 fork 后的子进程,需要执行连接命令对应的 Runnable。

7. 命令循环边界 ​

源码文件:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

runSelectLoop() 构造 pollfd 数组,把主 Zygote socket、USAP 事件 fd 和已有 ZygoteConnection fd 纳入同一次 Os.poll()。poll 超时用于 USAP pool refill;fd 可读时,索引 0 接受新连接,其余 fd 交给对应连接处理。这个循环的消费者是 fork 请求和 USAP 管理,不是 SystemServer 的 Binder Looper。

8. 失败定位 ​

bash
# 入口参数、预加载、fork 和 finally 收尾
rg -n "startZygoteNoThreadCreation|startSystemServer|enableLazyPreload|preload\(|gcAndFinalize|forkSystemServer|runSelectLoop|closeServerSocket" \
  frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

# poll fd、连接接受、USAP refill 与子进程连接处理
rg -n "runSelectLoop|Os\.poll|acceptCommandPeer|fillUsapPool|closeServerSocket" \
  frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

常见误读是把 forkSystemServer() 的父返回值和子返回值混在一起,或者看到 closeServerSocket() 就认为 Zygote 已退出。正确判断必须结合当前进程分支:父进程关闭动作通常只发生在最终退出/异常,子进程则在进入 SystemServer 前主动关闭继承的监听 socket。

下一篇将只展开 registerServerSocketFromEnv():init 创建的 socket fd 如何通过环境变量进入 ZygoteServer,以及 fd 包装、命名和关闭 owner 如何衔接。