SystemServer 如何启动系统服务并进入桌面
SystemServer 如何启动服务并进入桌面
问题场景
system_server 进程出现后,桌面仍不会立刻可用。AMS、PMS、WMS 等服务有依赖关系,用户和 Home 也要在正确时机启动。最后一段启动链需要回答:服务如何被编排,systemReady() 做了什么,桌面可见与 BOOT_COMPLETED 又是什么关系?
下面基于 AOSP Android 14 android-14.0.0_r75,从 SystemServer.main() 追踪到系统服务、 Home 和用户开机广播。不同设备新增的厂商服务不在通用顺序中,不能拿服务数量或单个厂商 阶段替代 AOSP 的启动边界。
核心结论
- SystemServer 在主线程创建 Looper 和 SystemServiceManager,随后按 bootstrap/core/other 三组启动服务。
- 三个
start*Services()是代码组织分组;SystemService.PHASE_*是跨服务生命周期通知,两者不是同一套阶段。 ActivityManagerService.systemReady()是允许系统进入应用世界的关键转折,回调中继续完成依赖就绪与 Home 启动准备。- Home 首帧、用户解锁、
sys.boot_completed=1与ACTION_BOOT_COMPLETED送达不保证同时发生。
图中最后几步存在用户、解锁和广播队列条件,不应理解为一条严格同步直线。
主流程
阶段一:SystemServer 建立服务容器
- 执行者:system_server 主线程;输入:Zygote 子进程运行环境。
- 动作:准备 Looper、上下文、SystemServiceManager 和启动线程池。
- 下一跳:
startBootstrapServices();边界:同进程,部分初始化任务并行。
阶段二:按依赖启动系统服务
- 执行者:SystemServer 与各服务;输入:已启动的基础依赖。
- 动作:依次执行 bootstrap/core/other 分组,向 ServiceManager 注册 Binder 服务,并推进 boot phase。
- 下一跳:WMS/PMS 等
systemReady(),最终 AMSsystemReady()。
阶段三:启动 Home 与用户完成事件
- 执行者:AMS、ATMS、UserController、Launcher 与广播队列。
- 动作:允许进程和 Activity 启动,解析并启动 Home;随用户状态发送 locked/unlocked boot 广播。
- 下一跳:桌面可交互、应用接收广播;边界:多次 Binder、异步消息和进程切换。
关键源码
源码节点:SystemServer 服务分组
- 类/方法:
SystemServer.run();路径:frameworks/base/services/java/com/android/server/SystemServer.java。
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);结论:源码以依赖和职责拆分启动方法;不能仅凭服务属于哪一组推断它何时完全可用。
源码节点:boot phase
- 类/方法:
SystemServiceManager.startBootPhase();路径:frameworks/base/services/core/java/com/android/server/SystemServiceManager.java。
SystemServiceManager 按递增 phase 通知已启动服务,并在 PHASE_BOOT_COMPLETED 后标记启动完成。服务可以早已构造和注册,但要等特定 phase 才开放完整能力。
源码节点:ActivityManager 进入 systemReady
- 调用点:
mActivityManagerService.systemReady(...);路径:frameworks/base/services/java/com/android/server/SystemServer.java。 - 作用:把前面启动的服务依赖汇合,并进入应用、Home 和用户生命周期相关工作。
源码节点:用户开机广播
- 类:
UserController;路径:frameworks/base/services/core/java/com/android/server/am/UserController.java。
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);结论:BOOT_COMPLETED 面向具体用户构造并经广播系统发送;多用户、直接启动模式和解锁状态会影响时机。
验证与排障
环境:adb shell;普通设备可读取多数属性和 dumpsys,完整 system_server 堆栈可能需要 bugreport 或更高权限。
adb shell getprop sys.boot_completed
adb shell service list | head
adb shell dumpsys activity activities | grep -E 'mResumedActivity|mCurrentFocus'
adb shell dumpsys activity broadcasts | grep -E 'BOOT_COMPLETED|LOCKED_BOOT_COMPLETED'
adb logcat -b system -d -s SystemServer ActivityManager ActivityTaskManager服务列表缺少关键项时先看对应服务构造/注册异常;SystemServer PID 变化说明进程级重启;服务稳定但没有 Home,检查 Launcher 包解析、默认 Home、ATMS 与显示状态;sys.boot_completed=1 但某应用未收到广播,还要检查用户是否解锁、包是否被停止、后台执行限制和广播是否延迟。dumpsys activity broadcasts 的输出随版本和构建变化,不能把某个字段名当永久接口。
常见误区
- bootstrap/core/other 不等于完整的时间阶段;boot phase 才是显式生命周期通知。
system_server存活不等于所有服务 ready,服务可能在注册后继续初始化。- 桌面出现不等于每个用户都已收到
BOOT_COMPLETED。
源码入口
Home 启动后还要经过窗口与合成链才能出现桌面首帧,图形侧入口见 SurfaceFlinger 为什么不画 View。
| 文件 | 关键位置 | 作用 |
|---|---|---|
| 见本章“关键源码”各节点 | 类名 / 方法名 | 证明主流程的关键动作 |
| Android 14 r75 对应源码文件 | 使用 rg -n 核对 | 发布前记录真实行号,避免跨 tag 漂移 |