系统调试与排障
把系统现象翻译成可验证的调用链
先固定时间,再找最后成功节点
只说“页面没出来”无法定位问题。系统链路可能同时经过异步消息、Binder 和渲染线程,必须先 固定复现时间与对象身份,再确认请求经过哪些节点、最后在哪里留下了成功证据。
核心结论
高效排障不是先搜索异常字符串,而是先回答五个问题:何时发生、哪个进程、哪个服务、 哪个线程或 IPC、系统当时保存了什么状态。
第一步:固定复现窗口
记录设备版本、操作步骤、发生时间和预期结果。清日志只适合可稳定复现的问题;偶现问题应先 保存现场,避免把唯一证据清掉。
# 主机终端;普通 USB 调试权限即可
adb shell date
adb logcat -v threadtime -b all -d > incident-logcat.txt预期得到带线程与时间戳的日志。限制:零售版本可能裁剪日志,主机时间与设备时间也可能不同。
第二步:确认进程和服务
adb shell ps -A
adb shell service list
adb shell dumpsys activity processes进程 PID 反复变化通常表示崩溃重启;服务名存在只说明已注册,不说明业务状态正确。 先证明“人是否在岗”,再追“为什么没办成事”。
第三步:读取系统保存的事实
adb shell dumpsys activity activities
adb shell dumpsys window windows
adb shell dumpsys input
adb shell dumpsys SurfaceFlinger --listActivity dump 回答任务与生命周期,window dump 回答窗口与焦点,input dump 回答输入目标, SurfaceFlinger 回答图层是否存在。不同版本和厂商的字段会变化,先保存原始输出,再按当前 源码解释。
第四步:区分卡死、阻塞和状态错误
ANR、锁等待、Binder 阻塞和主线程忙看起来都可能是“点了没反应”。使用 bugreport 保存线程、 服务和日志快照;性能或时序问题再采 Perfetto。不要在没有时间范围的情况下直接录制超长 trace。
adb bugreport bugreport.zip
adb shell perfetto --helpbugreport 可能包含账号、路径和设备标识,分享前必须脱敏;Perfetto 可用数据源取决于构建、 权限和配置。
从证据回到源码
把日志 tag、Binder 接口、dump 字段或堆栈方法当作源码锚点,用 rg -n 找定义和调用者。 先确认 Android tag,再判断它是确定事实、设备观察还是暂未验证的推断。
三类证据各有用途:日志记录发生过什么,dump 保存采样时刻的状态,trace 说明时间花在哪段 执行或等待上。
源码入口
窗口创建、布局、Surface、焦点或输入异常可直接进入 WMS 排障,把通用证据顺序落到窗口状态上。
| 文件 | 关键位置 | 作用 |
|---|---|---|
ActivityManagerService.java | dump() | Activity/进程状态入口 |
WindowManagerService.java | dump() | 窗口状态入口 |
InputManagerService.java | dump() | 输入状态入口 |
dumpsys.cpp | main() | dumpsys 命令入口 |
行号随 tag 变化;在 Android 14 r75 源码树中用上述稳定符号取得真实位置。