Zygote 如何孵化 system_server
Zygote 如何孵化 system_server
问题场景
init 已把 app_process64 --zygote --start-system-server 启动起来,但此时 Java 系统服务还不存在。Zygote 如何从 Native 可执行文件进入 Java,为什么要预加载,又如何让父进程继续孵化应用、子进程转而执行 SystemServer?
主线按 Android 14 的 app_process → AndroidRuntime → ZygoteInit → forkSystemServer() → SystemServer.main() 推进。普通应用孵化协议和 USAP 不在本文展开, 阅读时只跟踪 Native/Java、父/子进程和 fork 前后线程状态。
核心结论
app_process创建 AndroidRuntime,并把 Java 入口类设为com.android.internal.os.ZygoteInit。- Zygote 在单线程安全点完成预加载后 fork;父进程进入 socket select loop,子进程进入 SystemServer。
- fork 不是 Binder 调用,也不是启动一个普通 App;子进程继承已映射的运行时与预加载页。
handleSystemServerProcess()返回的 Runnable 最终通过运行时反射路径调用SystemServer.main()。
主流程
阶段一:app_process 进入 Java ZygoteInit
- 执行者:Zygote Native 主线程;输入:
--zygote --start-system-server。 - 动作:解析参数,调用
runtime.start("com.android.internal.os.ZygoteInit", args, true)。 - 下一跳:
ZygoteInit.main();边界:Native 到 Java,同一进程/线程。
阶段二:预加载并 fork
- 执行者:Zygote Java 主线程;输入:ABI、socket、预加载配置。
- 动作:预加载类/资源,停止创建额外线程的风险点,准备 SystemServer 参数并 fork。
- 下一跳:父进程继续 select loop,子进程执行返回的 Runnable;边界:进程分叉。
阶段三:子进程进入 SystemServer
- 执行者:新
system_server主线程。 - 输入:
com.android.server.SystemServer入口与继承的运行时状态。 - 动作:关闭不需要的 Zygote socket,完成进程专用初始化,调用 Java main。
- 下一跳:
SystemServer.run()。
关键源码
源码节点:app_process 选择 Zygote 入口
- 方法:
main();路径:frameworks/base/cmds/app_process/app_main.cpp。
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}结论:同一 app_process 可按参数进入 Zygote 或普通 Java class 启动路径。
源码节点:fork SystemServer
- 类/方法:
ZygoteInit.main()、forkSystemServer();路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java。
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
caller = zygoteServer.runSelectLoop(abiList);结论:r != null 对应子进程路径;父 Zygote 继续处理孵化请求。两条路径从 fork 返回值处分流。
源码节点:SystemServer 类名
forkSystemServer() 构造的参数包含 com.android.server.SystemServer,子进程经 handleSystemServerProcess() 创建 Runnable。这个真实类名把 Zygote 阶段与下一篇的 SystemServer.main() 闭环连接起来。
验证与排障
# adb shell,无需 root 即可观察常规进程关系
adb shell 'ps -A -o USER,PID,PPID,NAME | grep -E "zygote|system_server"'
adb shell getprop init.svc.zygote
adb logcat -b all -d -s Zygote SystemServer AndroidRuntime预期 system_server 的父进程是主 Zygote(不同工具输出名可能不同)。若 Zygote 稳定而 SystemServer PID 不断变化,问题通常已越过 init service 启动,应查 SystemServer Java 崩溃、watchdog 或关键服务异常。PPID 只能证明进程亲缘,不能证明预加载内容全部共享驻留内存。
常见误区
- Zygote 不是注册到 ServiceManager 的普通 Binder 系统服务。
- SystemServer 不是 init 直接 exec 出来的,而是主 Zygote fork 出来的。
- fork 后父子不会继续执行相同职责;源码立刻按返回路径分流。
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
| 见本章“关键源码”各节点 | 类名 / 方法名 | 证明主流程的关键动作 |
| Android 14 r75 对应源码文件 | 使用 rg -n 核对 | 发布前记录真实行号,避免跨 tag 漂移 |