关于 system_server 的来源,常见两句话看起来互相冲突:
csharp
Android 的服务都是 init 启动的;
system_server 是 Zygote fork 出来的。
冲突来自"启动"这个词太宽。它可能表示"位于整棵进程树的上游",也可能表示"直接调用 fork 创建子进程"。
先给出判定:
init 通过 fork/exec
app_process64建立主 Zygote;主 Zygote 在自己的初始化流程中直接调用forkSystemServer()创建 system_server。init 是上游祖先进程与 Zygote 的监督者,Zygote 才是 system_server 的直接创建者。system_server 也不是通过普通 App 使用的 Zygote socket 请求创建的。
准确进程树是:
csharp
init,PID 1
└─ app_process64 / zygote64
└─ system_server
本文只追 system_server 的出生路径;进入 SystemServer.run() 后如何装配服务,留到第七篇。
源码基线: Android 16 QPR2
android-16.0.0_r4,frameworks/basecommit45034f0663f960d9ee5fb0a101a4732b71f6e2f4。
一、先用三个问题拆掉"谁启动谁"
| 问题 | Android 16 的答案 |
|---|---|
| 谁通过 init Service 配置启动 Zygote? | init |
谁直接执行 fork() 得到 system_server PID? |
主 Zygote |
| 谁在 system_server 死亡后参与整组重启? | Zygote 检测死亡并退出,init 再按 Service 策略重启 Zygote |
所以两句话可以改写为:
csharp
init 建立并监督"Zygote → system_server"这组关键启动单元;
Zygote 直接 fork 出 system_server。
这样就不再把"上游负责"与"直接父进程"混为一谈。
二、ZygoteInit.main() 中的顺序没有经过 socket
主 Zygote 在 ZygoteInit.main() 完成参数解析和预加载后,根据 rc 传入的 --start-system-server 走下面的分支:
ini
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
caller = zygoteServer.runSelectLoop(abiList);
这段顺序揭示了两个事实:
markdown
1. forkSystemServer() 发生在 Zygote 进入普通请求 select loop 之前;
2. 调用来自 Zygote 自己的初始化控制流,不需要 system_server 先连 socket。
这也符合因果关系:如果"system_server 通过 socket 请求创建自己",它必须在出生前先运行客户端代码,形成循环前提。
三、forkSystemServer() 给这个子进程准备了什么身份?
ZygoteInit.forkSystemServer() 组装一组专用参数。Android 16 固定基线中的核心信息包括:
ini
--setuid=1000
--setgid=1000
--setgroups=...一组系统 supplementary groups
--capabilities=...
--nice-name=system_server
com.android.server.SystemServer
这些参数分别解决:
| 参数 | 作用 |
|---|---|
| UID/GID 1000 | 让子进程成为 Android system 身份,而不是继续作为 root Zygote |
| supplementary groups | 获得 system_server 所需的特定设备/系统组访问能力 |
| capabilities | 在放弃 root UID 后保留经过计算的必要 Linux capability |
nice-name |
设置可见进程名 system_server |
com.android.server.SystemServer |
指定最终 Java 入口类 |
这里也要避免反向夸大:system_server 使用 system UID 并持有一组能力,不代表它"绕过全部权限系统"。SELinux、Binder 身份检查、Linux DAC、capability、进程沙箱和服务自身权限仍共同约束它。
四、真正的 fork 在 Native 层

Java 层调用链可以压缩为:
scss
ZygoteInit.forkSystemServer()
→ Zygote.forkSystemServer()
→ nativeForkSystemServer()
→ com_android_internal_os_Zygote_nativeForkSystemServer()
→ zygote::ForkCommon(..., is_system_server=true)
→ fork()
Android 16 的 Native 入口在 com_android_internal_os_Zygote.cpp。它先准备 system_server 不应继承的 USAP / system server socket FD,再调用 ForkCommon()。
fork 的返回值让同一段调用栈分成父子两条路:
ini
pid > 0:当前仍是 Zygote 父进程,pid 是 system_server 的 PID;
pid == 0:当前已经是 system_server 子进程;
pid < 0:fork 失败。
"fork 返回两次"不是两个线程拿到不同结果,而是父、子两个进程从同一个代码位置继续执行。
五、子分支:模板副本怎样进入 SystemServer.main()?
1. Native specialize
在 pid == 0 分支,nativeForkSystemServer() 调用 SpecializeCommon(),应用 UID/GID、group、capability、system seccomp 与运行时子进程钩子。
它把刚 fork 出来、仍像 Zygote 的模板副本改造成 system_server 身份。
2. Java child 分支关闭 Zygote server socket
回到 ZygoteInit.forkSystemServer(),pid == 0 的子进程进入 handleSystemServerProcess()。它会关闭当前子进程不应继续持有的 Zygote server socket。
这一步非常关键:system_server 不应冒充另一个 Zygote 接收 App 创建请求。
3. RuntimeInit 找到 SystemServer.main()
handleSystemServerProcess() 最终走向:
scss
ZygoteInit.zygoteInit()
→ RuntimeInit.commonInit()
→ ZygoteInit.nativeZygoteInit()
→ RuntimeInit.applicationInit()
→ RuntimeInit.findStaticMain("com.android.server.SystemServer")
→ 返回 Runnable(当前实现为 MethodAndArgsCaller)
findStaticMain() 的 API 返回类型是 Runnable;Android 16 当前返回的具体实现对象是 MethodAndArgsCaller。ZygoteInit.main() 的 child 路径拿到这个 Runnable 后调用 r.run(),最终执行:
arduino
SystemServer.main(String[] args)
上面描述的是正常的无 wrapper 路径;调试配置若设置 invoke-with,handleSystemServerProcess() 还可以转入 WrapperInit.execApplication()。这类可选分支不改变"主 Zygote 直接 fork system_server"的进程出生结论,但会改变进入最终 Java 类之前的执行细节。
在上述正常路径中,没有再 exec 一个 system_server ELF。system_server 仍然运行在从 app_process/Zygote 继承来的 ART 进程映像里,只是权限、名字、运行时状态与 Java 入口已经改变。
六、Binder 线程池是在 SystemServer.main() 里才启动的吗?
不是。
child 进入通用初始化路径时,Binder 线程池的完整事实链是:
scss
Zygote child
→ RuntimeInit.zygoteInit()
→ ZygoteInit.nativeZygoteInit()
→ AppRuntime::onZygoteInit()
→ ProcessState::self()->startThreadPool()
其中 Native 回调最终落到 AppRuntime::onZygoteInit():
css
ProcessState::self()->startThreadPool();
所以,Binder 线程池的启动位于 fork 后通用 child 初始化路径,早于 SystemServer.main()。但这不表示此时 Framework 服务已经注册:
markdown
Binder 驱动与线程池可用
≠
ActivityManagerService / WindowManagerService 已创建并发布
传输基础设施准备好,与具体服务对象进入 ServiceManager 是两个里程碑。
七、父分支:Zygote 没有变成 system_server
在父进程中,forkSystemServer() 返回 null;主 Zygote 随后进入 ZygoteServer.runSelectLoop(),继续承担普通 App 进程孵化职责。
因此,下面这两句话都错:
scss
Zygote 调用 SystemServer.main() 后自己变成了 system_server;
system_server 创建以后 Zygote 的任务就结束了。
实际状态是两个独立进程:
perl
zygote64
├─ 继续监听 socket、fork App / USAP
└─ 作为 system_server 的父进程监视其死亡
system_server
└─ 执行 SystemServer.main()、创建 Framework 服务
它们最初复用一部分预加载物理页,但拥有独立 PID、地址空间演化、线程集合与职责。
八、system_server 死亡为什么会连带 Zygote 重启?
Native 父分支保存 gSystemServerPid。SIGCHLD 处理路径发现退出的 PID 正是 system_server 时,会记录错误并杀掉当前 Zygote,注释明确说明:让 init 重启 Zygote,再从那里重建 system_server,见 SigChldHandler()。
恢复链是:
csharp
system_server 退出
→ Zygote 收到并回收 child
→ 确认 PID == gSystemServerPid
→ Zygote 退出
→ init 观察到 zygote Service 退出
→ init 按 rc / service 策略处理重启
→ 新 Zygote 再 fork 新 system_server
为什么不只在旧 Zygote 中再 fork 一次 system_server?源码能够直接证明的是"system_server 死亡后,Zygote 主动退出,把恢复交回 init";SigChldHandler() 并没有给出唯一的官方设计理由。
从整体恢复设计看,可以作出一项工程解释 :长期运行的 Zygote 已经历更多状态变化,连同 Zygote 一起重建,能够让核心运行时重新走一遍受控的干净启动路径。这个解释用于理解恢复策略,不应冒充 SigChldHandler() 注释明确证明的事实。
这不意味着每台设备的最终故障表现都完全相同:critical、onrestart、崩溃窗口、bootloader 配置和厂商 rc 会进一步决定是否重启服务、重启 Framework 乃至重启设备。
九、三种创建路径放在一起比较
| 目标 | 直接创建者 | 触发方式 | 是否 exec 新 ELF | 最终 Java 入口 |
|---|---|---|---|---|
| 主 Zygote | init | rc start zygote |
是,exec app_process64 | ZygoteInit.main() |
| system_server | 主 Zygote | 初始化时直接 forkSystemServer() |
否 | SystemServer.main() |
| 普通 App | Zygote / USAP | system_server 运行期经 Zygote socket 请求 | 否 | 通常 ActivityThread.main() |
这张表是后续阅读所有 Framework 启动源码的坐标系。
十、直接创建者已经确定,容器装配仍未开始
| 结论 | 能否由固定源码直接证明 |
|---|---|
| system_server 由主 Zygote 直接 fork | 能 |
| system_server 走了普通 Zygote socket 请求 | 不能,而且调用顺序反证 |
| init 是 system_server 的直接父进程 | 不能,而且正常进程树反证 |
| init 是这条进程链的上游创建与监督者 | 能 |
| system_server 与 Zygote 共享一个可互改的堆 | 不能 |
| system_server 一出现,所有系统服务都已 ready | 不能,出生只完成进程层里程碑 |
| 所有产品的附加 group/capability 完全不变 | 不能,基线与产品配置可能调整 |
init 通过 rc 配置、fork/exec
app_process64建立并监督主 Zygote;主 Zygote 在 preload 后、不经过普通 socket 请求,直接 fork 并 specialize 出 system_server;子进程进入SystemServer.main(),父进程则继续监听并孵化后续 App。
首读主线可以直接进入第七篇,看这个子进程怎样建立服务容器;想补齐运行期进程工厂,再阅读第六篇,区分"源码明确使用 socket"与"为什么没有选择 Binder"的架构解释。
源码定位
ZygoteInit.main():system_server fork 与 select loop 的先后。ZygoteInit.forkSystemServer():专用身份参数与 child 入口。Zygote.forkSystemServer():Java 到 Native 的 fork 包装。nativeForkSystemServer():Native fork、specialize 与 PID 跟踪。SigChldHandler():system_server 死亡后的 Zygote 退出路径。