第4章:日志采集工具链——adb logcat、dumpsys、traces.txt、bugreport 抓取

本章价值:ANR 发生后,日志是唯一能还原主线程阻塞现场的证据。掌握四类日志工具的采集时机、命令参数和关键字段含义,是从“看见 ANR”到“看懂 ANR”的第一步。

4.1 现象识别:什么时候必须抓日志?

并非所有卡顿都需要完整日志链。以下 3 类现象 必须立即启动日志采集,否则现场容易丢失:

  • 连续 ANR:同一页面在 3 分钟内出现 ≥2 次 "应用无响应" 弹窗。
  • 关键路径 ANR:启动、跳转、支付、消息发送等核心流程发生 ANR。
  • 偶发 ANR:无法稳定复现,但线上监控上报率 > 0.1%。
经验法则:如果测试同学说“刚才卡了一下但没弹窗”,同样建议抓取 traces.txt + logcat,因为 无弹窗的主线程阻塞 往往比显式 ANR 更难排查。

4.2 数据采集:四类日志工具详解

下面按 采集顺序 和 信息密度 排列四类工具。实际排查时建议 一次性全部抓取。

工具 核心用途 采集耗时 是否 root 关键文件/命令
adb logcat 实时日志流,含 ANR 触发前后所有系统/App 消息 持续采集 否 adb logcat -v threadtime *:V
dumpsys 进程状态快照,查看 CPU、内存、线程状态 < 5 秒 否 adb shell dumpsys cpuinfo
traces.txt ANR 发生时系统自动 dump 的线程堆栈 被动生成 否 /data/anr/traces.txt
bugreport 全量系统诊断报告,包含以上所有信息 + 系统配置 < 60 秒 否 adb bugreport

4.2.1 adb logcat —— 实时流水,锁定时间窗口

在 ANR 弹窗出现后 立即 执行,注意加上 -v threadtime 以显示线程 ID 和时间戳:

# 清空旧缓存,只保留后续日志
adb logcat -c
# 开始采集(建议同时输出到文件)
adb logcat -v threadtime *:V > anr_logcat.txt

关键检索字段:

  • ANR in —— ANR 发生入口
  • Input dispatching timed out —— 输入事件超时
  • Reason: —— 系统给出的 ANR 原因描述
  • CPU usage —— ANR 时刻 CPU 负载分布

4.2.2 dumpsys —— 进程快照,查负载与线程

ANR 发生后 尽快 执行下面两条,用于分析 CPU 竞争和线程状态:

# CPU 使用率快照
adb shell dumpsys cpuinfo

# 目标进程的线程信息(以 com.example.app 为例)
adb shell dumpsys meminfo com.example.app
adb shell dumpsys activity processes | grep "com.example.app"

核心判断规则:

  • CPU 总体 > 90% 且 主线程占比 > 30% → 主线程自身 CPU 密集型阻塞
  • CPU 总体 > 90% 但 主线程占比 < 10% → 主线程被其他线程/进程争抢 CPU
  • CPU 总体 < 50% → 主线程在等待锁、I/O 或 Binder 调用

4.2.3 traces.txt —— ANR 堆栈铁证

系统在 ANR 发生时自动生成,位于 /data/anr/traces.txt。每个进程会 dump 出 所有线程的堆栈,主线程栈顶就是卡住的那一行代码。

# 拉取 traces.txt(需要 root 或 非生产环境)
adb root
adb remount
adb pull /data/anr/traces.txt .

主线程堆栈解读范例:

----- pid 12345 at 2025-01-15 10:30:00 -----
Cmd line: com.example.app
"main" prio=5 tid=1 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x...
  | sysTid=12345 nice=0 cgrp=default sched=0/0 handle=0x...
  at java.lang.Object.wait(Native Method)
  - waiting on <0x03a4c1e0> (a java.lang.Object)
  at com.example.data.local.DatabaseHelper.query(DatabaseHelper.java:45)
  - locked <0x03a4c1e0> (a java.lang.Object)
  at com.example.ui.MainActivity.loadData(MainActivity.java:78)
  at com.example.ui.MainActivity.onCreate(MainActivity.java:35)

线程状态速查表:

状态 含义 优先级
Blocked 等待锁释放 🔴 最高
Waiting 调用 wait()/join()/park() 🟠 高
Sleeping Thread.sleep() 🟡 中
Runnable 正在执行或等待 CPU 🟢 低
Native 执行 JNI 调用 🟠 高

4.2.4 bugreport —— 全量诊断,一次搞定

如果时间允许,优先执行 bugreport,它会打包 logcat、dumpsys、traces.txt、系统配置等全部信息:

# 生成 bugreport 压缩包(耗时约 30~60 秒)
adb bugreport bugreport_anr_$(date +%Y%m%d_%H%M%S).zip

解压后的目录结构:

  • bugreport-*.txt —— 汇总报告,包含所有 dump 信息
  • logs/ —— 包含 logcat、dumpsys 等原始文件
  • FS/data/anr/traces.txt —— ANR 堆栈文件
重要:bugreport 生成期间系统负载会短暂升高,不要在用户核心操作路径上 执行。建议在 ANR 弹窗出现后,先快速执行 adb logcat -c + adb shell dumpsys cpuinfo,再执行 bugreport。

4.3 原因定位:日志交叉分析三步法

单一日志往往只能看到表象,交叉分析 才能定位根因。下面以故障树形式给出排查流程:

日志交叉分析故障树 —— 三步定位 ANR 根因 ANR 日志已采集 ① logcat 流水 ② traces.txt 堆栈 ③ dumpsys 快照 查看 ANR Reason Input / Broadcast / Service CPU usage 段 总负载 / 进程占比 主线程栈顶状态 Blocked / Waiting / Runnable 线程数 / 锁信息 死锁检测 / 等待链 交叉比对 → 锁定根因类型 🔴 锁竞争 / 死锁 traces 中 Blocked + 锁地址 🟠 CPU 资源争抢 dumpsys 高负载 + logcat CPU 🟢 I/O / Binder 等待 traces 中 Native/Waiting 💡 三个分支的信息必须相互印证:单一日志只能给出假设,交叉比对才能给出结论

4.4 修复动作:基于日志类型的精准施策

交叉分析锁定根因类型后,对应修复动作如下:

根因类型 日志特征 修复方向
锁竞争 / 死锁 traces.txt 主线程为 Blocked,且存在 waiting on <0x...> + locked <0x...> 减少锁粒度、使用 synchronized 替代 Lock、避免跨进程锁嵌套
CPU 资源争抢 logcat 中 CPU usage 总负载 > 90%,且主线程占比低;dumpsys 显示大量线程 线程池限流、减少后台线程、关键路径提升优先级
I/O / Binder 等待 traces.txt 主线程为 Native 或 Waiting,栈顶在 FileInputStream.read() 或 BinderProxy.transact() I/O 操作切子线程、使用 StrictMode 拦截、Binder 调用加超时
修复优先级建议:锁竞争 > CPU 争抢 > I/O 等待。因为锁问题往往导致 系统级联阻塞,修复后收益最明显。

4.5 复测:验证修复是否有效

修复后使用同样的工具链做 前后对比:

  1. 复现验证:按原步骤触发场景,确认 ANR 不再出现。
  2. logcat 对比:检查 ANR in 字段是否消失,CPU usage 中主线程占比是否下降。
  3. traces.txt 对比:修复前的主线程栈顶状态为 Blocked/Waiting,修复后应为 Runnable 且耗时合理。
  4. dumpsys 对比:线程总数是否减少,锁等待时间是否归零。

4.6 预防:日志采集自动化规范

避免每次 ANR 都靠人工手动抓取,建立以下机制:

  • 自动化触发:在 Application 中注册 ANRWatchDog 或系统 ANRRecoveryHandler,当检测到 ANR 时自动执行 adb bugreport 并上传。
  • 日志保留策略:本地保留最近 3 次 ANR 的 traces.txt + logcat 片段,循环覆盖。
  • 关键字段告警:监控 logcat 中 Input dispatching timed out、ANR in、Reason: 等关键字,触发即时通知。
团队规范建议:在 CI/CD 流程中添加 ANR 日志采集测试用例,每次发布前用 Monkey 随机压测 30 分钟,自动抓取所有 ANR 日志并归档。做到 发布即排查,不复现不上线。