4、Android SystemUI启动流程:init、SystemServer、SystemUI进程启动
咱们直接切入正题。SystemUI 的启动,不是单打独斗,而是一条完整的链路。
说白了,它依赖 Android 系统从 kernel 启动后的一系列“传帮带”。
我刚开始研究这部分时,也绕晕过几次。后来发现,只要抓住 init → Zygote → SystemServer → SystemUI 这条主线,就不容易迷路。
4.1 启动链条:三阶段的接力赛
Android 系统启动,大体可以拆成三个阶段:
- 第一阶段:init 进程 —— 内核启动后的第一个用户空间进程。它负责解析 init.rc 脚本,启动关键守护进程,比如
servicemanager、surfaceflinger,以及最重要的 Zygote。 - 第二阶段:Zygote 进程 —— Android 的“孵化器”。它预加载了 Java 虚拟机、核心类库和系统资源。之后,Zygote 会 fork 出 SystemServer 进程。
- 第三阶段:SystemServer 进程 —— 系统服务的“大脑”。它创建了几乎所有核心服务(AMS、WMS、PMS 等),并在服务就绪后,主动启动 SystemUI。
你想想看,SystemUI 就像是个“太子爷”,它必须等父辈们(系统服务)全部到位,才能出生。嗯,这里要注意的是,SystemUI 本身也是一个独立的进程,由 SystemServer 通过 AMS 启动。
4.2 init 进程:从这里开始
内核启动后,第一条用户空间进程是 /init。它的任务很明确:读取 /init.rc 和一系列 /init.${ro.hardware}.rc 脚本。
在这堆脚本中,我们能找到 Zygote 的启动命令:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
socket zygote stream 660 root system
onrestart restart SurfaceFlinger
onrestart restart audioserver
我个人习惯把 class main 看作一个关键标志——启动时属于 main 类别的服务,会在 on boot 阶段被统一拉起。
那时候我踩过一个坑:自己调试时改了脚本,不小心把 Zygote 移出了 class main,结果机器一直卡在动画循环里……后来用 logcat 追了好久才发现是服务没启动。
4.3 SystemServer 进程:服务的大本营
Zygote 启动后,会主动 fork 出 com.android.server.SystemServer。这一段是 Java 世界的入口,入口函数就叫 main()。
public static void main(String[] args) {
new SystemServer().run();
}
在 run() 方法里,SystemServer 依次做了几件事:
- 加载 native 库(如
system_server、servicemanager) - 创建 SystemServiceManager —— 它负责管理所有服务的生命周期
- 启动引导服务(Installer、DeviceIdentifiersPolicyService 等)
- 启动核心服务(AMS、WMS、PMS、InputManagerService 等)
- 启动其他服务(Telephony、Bluetooth、Wifi 等)
- 最后,在
startOtherServices()中调用 startSystemUi()
你看看,顺序是固定的。一旦某个服务启动失败,后面的步骤就可能崩掉。我曾经遇到过一个 case:因为某个厂商的 sensor 服务异常,导致 InputManagerService 初始化卡住,结果整个 SystemServer 卡死,连 SystemUI 都进不去。排查了两天才定位到是 HAL 层的问题。
4.4 SystemUI 进程启动:AMS 的助攻
好了,轮到重头戏——SystemUI 的进程是如何被创建的?
代码入口在 SystemServer.java 的 startOtherServices() 里,有一行:
mActivityManagerService.systemReady(() -> {
...
startSystemUi(context, windowManagerF);
...
});
实际上,startSystemUi() 是个静态方法:
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
}
说白了,就是通过 startServiceAsUser() 调用 AMS 去启动 com.android.systemui 进程里的 SystemUIService。
这里有一个关键点:SystemUI 的进程名就是 com.android.systemui,它是独立于 SystemServer 的。
如果你用 ps -A | grep systemui 查看,会看到类似:
u0_a28 1234 ... com.android.systemui
它的 UID 是 u0_a28,属于普通应用级进程,但拥有系统级权限(因为签名为平台签名)。
那么 AMS 在启动这个 Service 时,做了什么呢?
- 检查
AndroidManifest.xml中SystemUIService的进程属性(默认就是主进程) - 如果该进程不存在,AMS 会 fork 新进程,并加载
com.android.systemui的 APK - 初始化 Application 的
onCreate(),然后启动 Service 的onCreate()
嗯,这里有个小技巧:SystemUI 的 Application 类(SystemUIApplication)在 onCreate() 里会做两件事:
- 创建所有核心依赖对象的实例(比如
Dependency框架) - 初始化各个 UI 模块(状态栏、导航栏、通知面板等)
但注意,不是所有模块都在 Application.onCreate() 里初始化,有些懒加载模块会在用到时才创建。这块我留个坑,后面讲依赖图时会展开。
4.5 关键依赖与常见避坑
根据上面的分析,我梳理了一个启动时序表,供你参考:
| 启动阶段 | 进程/组件 | 关键动作 | 前置依赖 |
|---|---|---|---|
| 1 | init | 启动 Zygote | 内核、驱动 |
| 2 | Zygote | fork SystemServer | 虚拟机、核心类库 |
| 3 | SystemServer | 启动 AMS、WMS 等 | Binder、SurfaceFlinger |
| 4 | AMS | 启动 SystemUIService | SystemServer 服务齐全 |
| 5 | SystemUI | 初始化 UI 组件 | WMS 可用、DisplayManager 可用 |
我曾经在定制低端设备时,发现 SystemUI 在开机后首次显示搜索栏时卡顿严重。查了好几天,才发现是因为 DisplayManager 服务还没完全就绪,WMS 的窗口策略初始化时序没对齐。解决方法是把 SystemUI 的某些显示初始化拆分到
onBootCompleted() 回调中,而不是所有东西都集中在 Service.onCreate() 里。
如果你想看 SystemUI 到底何时被启动,可以在
startSystemUi()Slog.i(TAG, "Start SystemUI"),然后抓取 logcat 过滤 SystemServer 和 SystemUIService,就可以清晰看到时间线。我曾经用这个方法对比过不同 ROM 的启动耗时差异,非常直观。
4.6 整体流程图(SVG)
下面这张图,我把从 init 到 SystemUI 进程启动的完整链路画出来了。你顺着箭头看,就是一场接力赛:
我个人觉得这张图最妙的地方在于,你可以一眼看到几个关键的时间点:
- SystemServer 启动后,必须先拉起 AMS 和 WMS,才能叫醒 SystemUI
- SystemUI 进程,是 AMS 通过
startServiceAsUser创建的,而不是从 SystemServer 里派生
嗯,到这里,咱们把 SystemUI 的“身世”说清楚了。
下一层,我们就要深入到 SystemUI 自身内部,看看它启动后,那些依赖对象是如何被创建和串联起来的。不过今天先到这,你如果有时间,可以去 Android 源码里翻一翻 SystemServer.java 的 startOtherServices(),自己验证一下流程。