好!既然上一阶段 Zygote 已经成功 Fork 出了 SystemServer 进程,那我们就正式进入第二阶段:构建大脑(System Services & PMS)。 🧠
这一阶段是 Android 启动过程中CPU 负载最高、I/O 最密集的时段,也是我们系统优化工程师最容易"拿分"的地方。因为这里每优化 100ms,用户都能切身感受到开机变快了。
🏛️ Part 1: 原理与流程 ------ SystemServer 的"三步走"
SystemServer 是整个 Android Framework 的载体。它的 main() 方法就像一个精密的指挥官,按照严格的顺序启动几十甚至上百个系统服务。
为了防止服务之间互相依赖导致死锁(比如 AMS 启动依赖 PMS,而 PMS 又依赖 PowerManager),Google 把启动过程分成了三类:
- Bootstrap Services (引导服务) 🛡️
- 地位: 系统生死攸关的基础设施。
- 成员: ActivityManagerService (Lifecycle), PowerManagerService (电源), LightsService (灯光), DisplayManagerService (显示基础).
- 特点: 这些服务起不来,SystemServer 直接崩,手机无限重启。
- Core Services (核心服务) 🔋
- 地位: 必须要在其他乱七八糟服务之前准备好的核心。
- 成员: 重点是 BatteryService 和 UsageStatsService。
- 注意: 如果你在做车载系统或定制系统,通常不建议往这里塞东西,除非你非常确定它属于"Core"。
- Other Services (其他服务) 🧩
- 地位: 剩下的 80% 都在这里。
- 成员: CameraService, AudioService, BluetoothService, 以及我们马上要重点谈的 PackageManagerService (PMS) 的后期初始化。
- SystemReady: 当所有服务都 start 完毕后,AMS 会通知大家 systemReady()。这是一个关键信号,意味着"虽然界面还没出来,但我们已经准备好接受外部请求了"。
🐢 Part 2: 启动耗时大户 ------ PMS (PackageManagerService)
如果说 SystemServer 是大脑,那 PMS 就是负责"记忆检索"的海马体。
在 Zygote 阶段,我们提到了 boot_progress_pms_system_scan_start,这标志着 PMS 开始工作。为什么它慢?
- 扫描逻辑 (Scanning) 📂
PMS 需要遍历 /system/app, /vendor/app, /data/app 等目录下的所有 APK 文件。
- 解析 AndroidManifest.xml: 读取包名、权限、Activity/Service 定义。
- 校验签名: 确保应用没有被篡改。
- 建立缓存: 把解析结果存入 package.xml 和 packages.list,下次开机可以直接读缓存(除非有 OTA 升级或缓存损坏)。
- OTA 后的噩梦 (Dexopt) ⚙️
如果你刚升级完系统,开机特别慢,并在 Logo 处显示"正在优化应用",那就是 PMS 在调用 installd 进行 Dexopt(将 dex 编译成 oat/vdex 机器码)。
- 原理: Android 10+ 引入了 APEX 和 AOT/JIT 混合编译,虽然减少了全量编译的情况,但在首次开机或大版本升级时,PMS 依然要花费大量时间做这些"体力活"。
🛠️ Part 3: 实战分析 ------ 如何抓出拖后腿的服务?
作为系统开发,当 Logcat 里打印出 SystemServer: SystemServer init end 比平时晚了 5 秒,我们该怎么查?
- 利用 SystemServerTiming (日志分析) 📜
SystemServer 在启动每个服务时,都会打一个 SystemServerTiming 的 Tag。
-
命令: adb logcat -b system | grep "SystemServerTiming"
-
输出示例:
I SystemServerTiming: StartPackageManagerService took 150ms
I SystemServerTiming: StartActivityManagerService took 20ms
...
I SystemServerTiming: StartOemService took 2000ms <-- 凶手找到了!
-
实战技巧: 写个简单的 Python/Shell 脚本,抓取这些 Log 并自动排序,直接把耗时 Top 5 的服务甩给负责的同事(或者甩给 Vendor 厂商)。
- 深度剖析:Perfetto / Systrace (可视化) 📉
如果 Log 看不出细节(比如某个服务虽然只花了 100ms,但它导致了严重的锁竞争),就要用 Perfetto。
- 关注点:
- 在 SystemServer 进程的主线程上,寻找长条的 Slice。
- Lock Contention (锁竞争): 经常会看到 monitor contention,点进去看 Current Owner 是谁。
- 案例: 某次我们发现开机慢,Trace 显示 AMS 在等待 PMS 的锁,而 PMS 正在疯狂做 I/O 操作解析一个巨大的预装游戏 APK。
- 解决方案: 把这个预装游戏的解析放到后台线程,或者利用 Parallel Package Parsing (多线程扫描,Android R+ 已经默认开启) 进行调优。
- 各种 "Manager" 的死锁 (Deadlock) 🕸️
这是开发中自定义 System Service 最容易踩的坑。
- 场景: Service A 的 onStart 里调用了 Service B 的方法,而 Service B 此时还没注册到 ServiceManager,或者 Service B 的锁被 A 持有。
- 现象: Watchdog 触发,手机重启。
- 分析: 必须看 /data/anr/ 下的 Trace 文件,搜索 blocked 状态的线程,画出锁的依赖图。
💡 一个硬核的思考题
在 Android 的演进中,Google 为了加速 SystemServer 启动,引入了 SystemServerInitThreadPool。
这意味着部分服务的初始化可以并行运行,而不是全在主线程串行。
这就引出了下一阶段的关键:
当所有服务都准备好后,AMS 会通知 Launcher 启动,这时候屏幕终于要有画面了。但是!如果没有 SurfaceFlinger 和 HWC 的配合,AMS 甚至画不出一个像素。
关于这一部分(PMS 和 SystemServer),你有没有遇到过那种**"加了一个小功能,结果导致开机变慢或者 SystemServer 起不来"的坑?或者我们直接进入最酷炫的第三阶段:光影魔术(SurfaceFlinger & 图形栈)**? 😎