init 如何建立 Android 用户空间并启动 Zygote
2026/7/26大约 3 分钟系统启动Android 14initZygote
init 如何建立 Android 用户空间并启动 Zygote
问题场景
PID 1 已经运行后,Android 仍要完成挂载、属性、SELinux、设备节点和服务启动。为什么 Zygote 不是 init 一进入 main() 就立即启动?答案藏在 init 的两阶段启动和 rc 事件模型中。
下面基于 AOSP Android 14 android-14.0.0_r75 追踪 /init 到 zygote service。设备 fstab、 厂商 rc 和加密策略存在差异;主线止于 Zygote 进程进入 app_process,Java 预加载留给下一篇。
核心结论
- first-stage init 解决最早期挂载问题,second-stage init 才建立完整属性、SELinux 与 rc 事件循环。
- rc 文件声明“条件满足时执行什么”和“服务如何启动”,不是按文本顺序执行的 shell 脚本。
- Android 14 的
init.rc在合适条件下触发zygote-start,该 action 最终执行start zygote。 - zygote service 的可执行文件是
app_process,参数包含--zygote --start-system-server。
主流程
阶段一:first stage 准备可挂载环境
- 执行者:init PID 1;输入:ramdisk、fstab、内核参数。
- 动作:创建早期目录和设备节点,挂载启动所需分区,装载策略所需内容。
- 下一跳:重新执行 init 进入 second stage;边界:仍是 PID 1,但执行阶段改变。
阶段二:second stage 建立控制平面
- 执行者:init 主线程;输入:属性、SELinux、rc 文件。
- 动作:初始化属性系统、epoll/signalfd,调用
LoadBootScripts()解析 action 与 service。 - 下一跳:事件队列执行
early-init、init、late-init等 trigger。
阶段三:触发并启动 Zygote
- 执行者:init action manager 与 service manager。
- 输入:
zygote-starttrigger 和service zygote定义。 - 动作:满足前置条件后执行
start zygote,fork/execapp_process64(或设备 ABI 对应版本)。 - 下一跳:
app_process进入 AndroidRuntime;边界:创建新进程。
关键源码
源码节点:second-stage 载入启动脚本
- 方法:
SecondStageMain()、LoadBootScripts();路径:system/core/init/init.cpp。
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
LoadBootScripts(am, sm);
// 省略事件循环初始化结论:解析结果进入 ActionManager 与 ServiceList,之后由 trigger 和属性事件推进,不是把 rc 当 shell 顺序执行。
源码节点:zygote-start action
- 路径:
system/core/rootdir/init.rc。
on zygote-start
wait_for_prop odsign.verification.success 1
exec_start odsign
start statsd
start netd
start zygote结论:Android 14 在启动 Zygote 前还有 odsign 等条件与动作;直接删掉这些依赖会改变安全与运行时准备。
源码节点:zygote service
- 路径:
system/core/rootdir/init.zygote64.rc(具体文件由产品 ABI 选择)。
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote \
--start-system-server --socket-name=zygote
class main
priority -20
user root结论:init 启动的是 Native 可执行文件 app_process64;它随后建立 ART 并调用 Java ZygoteInit。
验证与排障
环境:adb shell;普通 user build 通常可读取属性和进程,完整 init 日志依厂商配置。
adb shell getprop init.svc.zygote
adb shell getprop init.svc_debug_pid.zygote
adb shell 'ps -A | grep zygote'
adb logcat -b all -d -s init Zygote正常情况下 init.svc.zygote 为 running。若反复在 restarting/stopping 间变化,检查 app_process/ART 崩溃及 service 的 onrestart 连锁影响;若始终未启动,向前检查 zygote-start 前置属性、挂载、SELinux denial 和 rc 导入。属性是瞬时状态,不足以单独证明 Zygote 已完成预加载。
常见误区
init.rc不是 shell 脚本;声明顺序不等于全部执行顺序。- init 不直接调用
SystemServer.main();它先 exec app_process 启动 Zygote。 - 设备可能有主、次两个 Zygote,ABI 配置决定使用哪个 rc 文件。
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
| 见本章“关键源码”各节点 | 类名 / 方法名 | 证明主流程的关键动作 |
| Android 14 r75 对应源码文件 | 使用 rg -n 核对 | 发布前记录真实行号,避免跨 tag 漂移 |