Android 系统启动机制(七):进入 SystemServer.main() 以后,system_server 还是一个空进程吗?

前面追到 system_server 的出生点:Zygote fork 出子进程,子分支完成 specialize,最后进入 com.android.server.SystemServer.main()

这时容易出现两种相反的误解:

复制代码
"它刚出生,所以里面什么都没有";
"它继承了 Zygote,所以系统服务已经都在里面了"。

两种说法都把"运行环境"和"系统服务"混成了一层。

进入 SystemServer.main() 时,system_server 已是拥有 ART、Framework JNI、预加载页面和 Binder IPC 基础设施的独立进程;但 System Context、主 Looper 的长期循环、SystemServiceManager 以及 AMS/PMS/WMS 等服务仍要由 SystemServer.run() 组织建立。

本篇只回答"一个可运行的子进程怎样搭好服务容器骨架"。服务怎样从构造走到 ready,留给下一篇。

源码基线: Android 16 QPR2 android-16.0.0_r4frameworks/base commit 45034f0663f960d9ee5fb0a101a4732b71f6e2f4

一、进入 main 的那一刻,已经有什么?

到达 Java 入口前,子进程已经走过:

lua 复制代码
Zygote preload
  → fork
  → system_server specialize
  → 完成通用 child 初始化
  → 进入 SystemServer.main()

Binder 线程池的完整 child 调用链已在 第五篇给出;本篇只讨论它与主 Looper 的职责区别。

于是"出生清单"可以分成两列:

已经具备 仍未建立
独立 PID、system UID/GID/capability 与 SELinux 身份 System Context / System UI Context
ART、Framework JNI 与 fork 后运行时状态 system_server 主线程的长期 Looper 循环
Zygote 预加载的类、资源和库页面 SystemServiceManager
Binder IPC 线程池 AMS、PMS、WMS 等服务对象及其发布状态

因此,system_server 不是"空地址空间",却仍是一个尚未完成 Framework 服务装配的容器

二、SystemServer.main() 只是装配入口

SystemServer.main() 很短:

typescript 复制代码
public static void main(String[] args) {
    new SystemServer().run();
}

这里没有创建新进程。当前代码已经运行在 Zygote fork 出来的 system_server 中,只是创建一个 Java SystemServer 对象并调用 run()

四个名字必须分开:

名称 类型 角色
system_server Linux 进程 承载大量 Framework 核心系统服务
SystemServer Java 类/对象 组织这个进程的初始化与服务启动
SystemServiceManager Java 管理对象 启动并分发一部分 SystemService 生命周期
SystemService Java 抽象基类 一类具有统一生命周期回调的服务实现

SystemServer 不是 AMS,也不是发布给 ServiceManager 的 Binder Service。它更像一次性的装配总控:把进程规则、Context、管理对象和服务启动顺序接起来,最后让主线程进入长期消息循环。

三、SystemServer.run() 要补齐哪几类设施?

不要把 SystemServer.run() 看成一串互不相干的初始化。它做的工作可以按目的归为四层:

markdown 复制代码
1. 进程规则
   调整 runtime、Binder、SQLite、Parcel、调度与安全相关策略
​
2. 执行基础设施
   准备主 Looper,启动允许并行的初始化线程池
​
3. Framework 运行上下文
   加载 android_servers,建立 System Context / System UI Context
​
4. 服务容器
   创建 SystemServiceManager,随后开始分组启动系统服务

这个顺序有因果关系:服务构造需要 Context;统一生命周期需要 Manager;可能阻塞的远端调用和长期主线程则需要提前配置进程规则。

run() 末尾的 Looper.loop() 也不是"启动完成标志"。它表示主线程从一次性装配控制流进入长期事件循环,服务和用户级启动工作仍会继续发生。

四、system_server 中至少有三套执行路径

理解服务容器,不能只画对象,还要知道代码可能在哪条线程执行。

1. Java 主线程 / 主 Looper

SystemServer.run() 在当前启动线程调用:

ini 复制代码
Looper.prepareMainLooper();

服务启动的大顺序由这条主控制流组织;末尾进入 Looper.loop() 后,它继续处理投递到 system_server 主 Looper 的消息。下一篇会进一步区分两件事:SystemService 文档要求生命周期方法由主 Looper 调用,但一次回调在实机上究竟落到哪条线程,仍由 SystemServiceManager 的实际调用点以及是否显式切线程决定。

2. Binder 线程

进入 Java main 前,system_server 已具备 Binder IPC 线程池;SystemServer.run() 还会配置线程数量与调度策略。此处重要的不是重复启动调用链,而是线程职责:

Binder 线程负责接收远端 transaction。它们不是主线程,也不会天然服从主 Looper 的消息顺序。服务若要把 IPC 工作转到主线程或自己的 HandlerThread,必须显式投递。

3. 初始化线程池与服务自有线程

SystemServerInitThreadPool 允许少量明确可并行的初始化任务与主线重叠。各服务启动后还可能创建自己的 HandlerThread、executor 或 Native 工作线程。

所以准确模型是:

SystemServer 主线程控制总体装配顺序;明确提交的初始化任务可以并行,Binder transaction 与服务内部后台工作又属于其他执行路径。

这一区分很重要:一个 Binder 线程阻塞,不自动等于 SystemServer 主启动线程卡死;反过来,主线程卡在服务启动,也不能靠观察某个 Binder 线程活跃来证明启动仍在推进。

五、为什么先要 System Context,再要 SystemServiceManager?

1. System Context:让服务获得 Framework 运行环境

createSystemContext() 的核心是:

ini 复制代码
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();

这里没有启动普通 Activity。ActivityThread 也不只服务于三方 App;systemMain() 为 system_server 建立资源、包与 Context 运行环境,使后续服务能够获得系统资源、ContentResolver 等基础能力。

System Context 不是"所有服务都 ready"的证明。它是后续服务构造和运行所依赖的容器环境。

2. SystemServiceManager:让部分服务共享生命周期框架

System Context 建立后,run() 创建:

ini 复制代码
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

此时它只是 system_server 进程内的 Java 对象和 LocalServices 条目,不是独立进程,也不是面向 App 的 Binder 接口。

它出现是因为接下来需要统一完成几件事:

scss 复制代码
以 System Context 构造 SystemService;
记录由它启动的服务实例;
调用 onStart();
保存当前 Boot Phase;
向已纳管服务分发生命周期回调。

它不会读取全局依赖图自动拓扑排序,也不管理 system_server 中的每一种服务形态。显式顺序与 ready 机制是下一篇的主线。

六、什么时候才真正开始创建服务?

容器骨架建立以后,run() 才进入服务装配:

scss 复制代码
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);

这些名称首先是 SystemServer.java 的源码分组与大体顺序,不是四个 Boot Phase,也不对应 init rc 的 class_start core

服务的启动形态也并不统一:

scss 复制代码
mSystemServiceManager.startService(SomeLifecycle.class)
SomeLegacyService.main(...)
ServiceManager.addService(name, binder)
对象构造后再显式调用 systemReady()

因此,"开始调用 startBootstrapServices()"只能说明服务创建阶段已经开始,不能说明所有 Bootstrap 服务已完成,更不能说明 Framework 已 ready。

Watchdog 会在 bootstrap 早期启动,以便尽早发现启动死锁;system_server_dumper 也会较早发布,给调试构建提供内部状态入口。这些设施很重要,但在本篇只需知道它们位于容器基础设施与早期服务装配之间,不需要抢占主线。

容器已经搭好,为什么能力仍不能立即使用?

到这里,system_server 已经从"可运行的 Zygote 子进程"变成"能够开始承载 Framework 服务的容器":

sql 复制代码
有独立进程身份
  → 有 ART 与 Binder 基础设施
  → 有主 Looper 与初始化执行路径
  → 有 System Context
  → 有 SystemServiceManager
  → 开始创建服务

但"开始创建"与"服务可用"之间仍有一段关键距离:构造函数、onStart()、Binder/LocalService 发布、Boot Phase、服务专用 systemReady() 与异步初始化分别代表什么?下一篇专门拆开这些里程碑。

源码定位

相关推荐
王的宝库1 小时前
Linux 性能优化入门
linux·学习
好安静1 小时前
SurfaceFlinger 合成一帧的完整流程
android
alexhilton1 小时前
架构测试为何需要双视图
android·kotlin·android jetpack
事圆则缓1 小时前
Jetpack Compose 快速上手
android·kotlin
y小花1 小时前
安卓HAL接口技术之HIDL&AIDL
android
YF02112 小时前
Android 系统自带机制的卸载更新都哪些实现方案
android
事圆则缓2 小时前
MVC、MVP、MVVM、MVI 的区别与实现原理
android·kotlin·mvc
Ruiery2 小时前
Linux 6.6内核 PCIe 深度解析(九):复位机制 — 从 FLR 到 Secondary Bus Reset 的降级链
linux·运维·服务器
学烹饪的小胡桃2 小时前
WGCLOUD支持哪些告警方式
linux·运维·服务器·网络·安全