1. 课程导入

Android 系统服务是整机运行的中枢:ActivityManagerService、WindowManagerService、PackageManagerService、InputManagerService、SurfaceFlinger、SystemServer 中的各类 Binder 服务,共同支撑应用启动、窗口绘制、输入分发、权限校验与进程调度。一旦某个系统服务出现阻塞、崩溃、死锁或资源泄漏,表现往往不是"某个应用报错",而是整机卡顿、黑屏、重启、ANR 甚至无法开机。因此,系统服务稳定性调试的核心,不是"改一行代码让日志消失",而是建立一套从现象到根因的可复现、可度量、可验证的排查能力。

一、学习目标:从"看日志"到"建模型"

本课程面向已经具备 Android 应用开发或系统开发基础、希望深入系统稳定性领域的工程师。完成学习后,应达到以下目标:

  • 能区分系统服务稳定性问题的四类典型现象:崩溃(Crash)、无响应(ANR/Block)、异常重启(Reboot/Watchdog)、性能劣化(卡顿、掉帧、内存增长)。
  • 能读懂 SystemServer 启动流程、Binder 通信模型、Watchdog 检测机制与 AMS/WMS 关键锁结构。
  • 能独立完成一次系统服务卡死的现场抓取:logcat、dumpsys、traces、tombstone、dropbox、/data/anr 等。
  • 能使用 Systrace/Perfetto、simpleperf、GDB、Binder 调试节点等工具定位到具体线程与调用栈。
  • 能针对死锁、锁竞争、Binder 超时、内存泄漏等典型根因给出修复方案并设计回归验证。

二、核心概念:先建立系统服务的"运行模型"

系统服务稳定性问题之所以难,是因为它跨越了 Java 层、Native 层与内核层。理解下面几个概念,是后续所有调试工作的前提。

SystemServer 与系统服务生命周期。SystemServer 由 Zygote fork 而来,依次启动引导服务、核心服务和其他服务。服务启动顺序决定了依赖关系,也决定了"谁先卡住会拖垮谁"。

Binder 通信与线程池。应用通过 Binder 调用系统服务,服务端由 Binder 线程池处理请求。当服务端持锁时间过长,Binder 线程被占满,调用方就会阻塞,最终触发 ANR 或 Binder 超时。

Watchdog 与系统重启。Watchdog 周期性检查关键服务与监控线程是否按时"喂狗"。一旦超时,会抓取 traces 并触发系统重启,这是系统服务卡死最典型的兜底机制。

锁与并发。AMS、WMS、PMS 内部大量使用 synchronized 与各类 Lock。锁顺序不一致会死锁,锁粒度过大会造成竞争,这是系统服务稳定性问题的头号根因。

系统服务稳定性调试的本质公式:
现象(卡顿/ANR/重启) → 现场(日志/traces/dumpsys) → 线程与锁(调用栈/锁持有) → 根因(死锁/竞争/泄漏/超时) → 修复 → 回归验证

三、整体知识框架与实战路线图

下图给出本课程的整体知识框架:左侧是问题现象入口,中间是调试工具与数据来源,右侧是根因分类与修复方向,底部是贯穿全程的实战路线。

Android 系统服务稳定性调试 · 知识框架与实战路线 问题现象入口 系统卡顿 / 掉帧 ANR / Binder 超时 SystemServer 崩溃 Watchdog 重启 内存增长 / 泄漏 调试工具与数据来源 logcat / dmesg / dropbox dumpsys / /data/anr/traces Systrace / Perfetto simpleperf / GDB / tombstone Binder 调试节点 / ftrace Watchdog 超时报告 根因分类 死锁 / 锁顺序 锁竞争 / 长持锁 Binder 线程耗尽 内存 / 句柄泄漏 异常未捕获 / 空指针 修复与验证 调整锁粒度 统一锁顺序 异步化 / 超时 降级与兜底 压力回归 Monkey / 长稳 指标对比 确认不复发 实战路线图:复现 → 抓现场 → 读栈 → 定根因 → 修复 → 回归 1. 稳定复现 构造最小场景 2. 抓取现场 日志/traces 3. 分析线程 调用栈与锁 4. 定位根因 死锁/竞争 5. 实施修复 改锁/异步 6. 回归验证 长稳与指标

四、典型场景与误区复盘

以一个真实场景为例:某设备在连续使用 2 小时后出现整机卡顿,随后 Watchdog 触发重启。初步 logcat 只能看到"Watchdog: Blocked in handler on ActivityManager",但看不到根因。正确做法是:先取 /data/anr/traces.txt 与 dropbox 中的 watchdog 记录,确认被阻塞的线程;再用 dumpsys activity 与 Binder 调试节点确认是否有服务端长持锁;最后结合 Systrace 观察锁竞争窗口。常见误区如下:

误区 表现 正确做法
只看 logcat 就下结论 日志只显示"Blocked",误判为应用问题 结合 traces、dumpsys、dropbox 交叉验证
把 ANR 当成应用单方问题 忽略服务端 Binder 线程被占满 同时检查调用方与服务端线程栈
用加大超时"掩盖"问题 卡顿依旧,只是不报错 定位长持锁点,缩短临界区
修复后不做长稳回归 问题在特定压力下复现 Monkey + 长稳 + 指标对比
建议在调试前先固定环境:同一版本、同一硬件、同一压力脚本。系统服务问题对时序极其敏感,环境不一致会让复现率大幅下降。
不要在生产或未授权设备上随意触发 Watchdog 重启或修改系统服务代码。调试应在可控的工程机或模拟环境中进行,并保留原始日志与 traces 作为证据链。

五、常用命令速查

# 抓取系统服务与线程状态
adb shell dumpsys activity services
adb shell dumpsys window
adb shell dumpsys package

# 抓取 ANR / Watchdog traces
adb pull /data/anr/traces.txt
adb shell dumpsys dropbox --print system_app_anr

# 抓取 Binder 与锁信息
adb shell cat /sys/kernel/debug/binder/state
adb shell cat /proc/<pid>/task/<tid>/stack

# 性能与调度分析
adb shell atrace -t 10 -b 8000 gfx view binder_driver
adb shell simpleperf record -p <pid> --duration 10