第3章 关键日志采集:logcat、traces.txt、dropbox、bugreport 的获取时机与保存
3.1 现象识别:判断 ANR 现场与日志采集决策树
并非所有 ANR 都需要采集全部四种日志。采集前必须根据现场状态快速决策:
- 正在 ANR(对话框未消失):优先采集
logcat -d与traces.txt,此时缓冲区最完整; - ANR 刚恢复(对话框已消失 < 5 分钟):
traces.txt与dropbox仍有保留,立即拉取; - 历史 ANR(已过数小时):
traces.txt可能被覆盖,依赖dropbox和bugreport的归档记录; - 复现测试阶段:提前开启
logcat -v threadtime -b all持续落盘,配合bugreport定点触发。
采集决策规则:
现场 ANR → 先拉 traces.txt 再拉 logcat,顺序不可颠倒。
历史 ANR → 优先查 dropbox,其次拉取 bugreport 做全量诊断。
现场 ANR → 先拉 traces.txt 再拉 logcat,顺序不可颠倒。
历史 ANR → 优先查 dropbox,其次拉取 bugreport 做全量诊断。
3.2 数据采集:四大日志源的获取时机与标准命令
四种日志源分别从不同维度记录 ANR 证据,采集时机直接影响证据完整性。下表列出每种日志的触发机制、保存路径与核心价值:
| 日志源 | 触发时机 | 保存路径(设备端) | 核心内容 | 采集优先级 |
|---|---|---|---|---|
| logcat | 实时流,循环缓冲区 | 内存缓冲区 → 可落盘 | 系统事件、GC、CPU 负载、堆栈日志 | ★★★★★ |
| traces.txt | ANR 发生时系统自动 dump | /data/anr/traces.txt | 所有线程堆栈、锁信息、CPU 时间片 | ★★★★★ |
| dropbox | ANR 发生后数秒内写入 | /data/system/dropbox/*anr* | 错误摘要、进程状态、系统快照 | ★★★★☆ |
| bugreport | 手动触发(adb / 开发者选项) | 生成 zip 包到 PC | 以上三者的聚合 + 系统配置 + 诊断报告 | ★★★☆☆ |
3.2.1 logcat 采集:黄金窗口 30 秒
ANR 对话框出现后,30 秒内执行以下命令可捕获最完整的现场日志:
# 捕获所有缓冲区日志并保存到文件(推荐)
adb logcat -b all -d -v threadtime > logcat_anr_$(date +%Y%m%d_%H%M%S).txt
# 按进程过滤(已知包名)
adb logcat -b all -d --pid=$(adb shell pidof com.example.app) > logcat_app.txt
# 持续落盘(复测场景)
adb logcat -b all -v threadtime -f /sdcard/logcat_capture.txt &
避坑:不要使用
logcat -c 清空缓冲区后再采集,这会丢失 ANR 发生前的关键日志。始终使用 -d(dump 并退出)而非 -s(过滤后持续输出)。
3.2.2 traces.txt 采集:系统 dump 的第一手证据
系统检测到 ANR 后,会由 system_server 向目标进程发送 SIGQUIT 信号,进程将所有线程堆栈写入 /data/anr/traces.txt。若设备有多个 ANR 历史,可能生成 traces_01.txt、traces_02.txt 等滚动文件。
# 查看 ANR 痕迹文件列表
adb shell ls -la /data/anr/
# 拉取最新 traces.txt
adb pull /data/anr/traces.txt ./traces_anr_$(date +%Y%m%d).txt
# 拉取历史滚动文件(如有)
adb pull /data/anr/traces_01.txt ./traces_01.txt
现场铁律:traces.txt 在 ANR 发生后 只保留一次 dump,下一次 ANR 会直接覆盖。遇到连续 ANR 时,每发生一次就立即 pull 一次,避免被覆盖。
3.2.3 dropbox 采集:系统级错误归档
dropbox 是 Android 系统内置的错误日志服务,ANR 发生后自动生成一条 ANR 类型的条目。dropbox 的优势在于 不会因缓冲区覆盖而丢失,适合排查历史 ANR。
# 打印所有 ANR 类型条目(按时间倒序)
adb shell dumpsys dropbox --print ANR --latest 10 > dropbox_anr.txt
# 查看条目元数据(时间戳、大小)
adb shell dumpsys dropbox --list ANR
# 按时间范围过滤(单位:毫秒)
adb shell dumpsys dropbox --print ANR --since 1696000000000
3.2.4 bugreport 采集:全量诊断聚合包
bugreport 将 logcat、traces.txt、dropbox、dumpsys 输出、系统配置文件等聚合为一个 zip 包。适用于 复现后全量归档 或 跨团队协作 场景。
# 生成 bugreport 并拉取到 PC(压缩包)
adb bugreport ./bugreport_anr_$(date +%Y%m%d_%H%M%S).zip
# 若只查看关键部分,可先输出到终端再重定向
adb bugreport > bugreport_full.txt
采集顺序建议:
1. 先 pull
2. 再 dump
3. 接着导出
4. 最后生成
1. 先 pull
traces.txt(最易被覆盖)2. 再 dump
logcat -d(缓冲区可保留数分钟)3. 接着导出
dropbox(持久保存,但需 adb shell)4. 最后生成
bugreport(耗时最长,适合离线分析)
3.3 原因定位:从日志时间线反推 ANR 链路
采集到日志后,通过建立 统一时间基线 将四种日志源关联起来,才能还原 ANR 发生的全貌。
- logcat 时间戳:
2025-01-15 10:23:45.123格式,记录 ANR 触发前后 CPU 负载、GC 停顿、广播超时等事件; - traces.txt 时间戳:文件头部的
----- pid 1234 at 2025-01-15 10:23:45 -----精确到秒; - dropbox 时间戳:
dumpsys dropbox --list显示ANR @ 1705289025000(毫秒级 Unix 时间戳); - bugreport 时间轴:内部已整合上述三种日志,按时间线排列。
| 时间线事件 | logcat 关键字 | traces.txt 标记 | dropbox 字段 |
|---|---|---|---|
| CPU 负载飙升 | Load: 12.5 / 8.3 / 5.1 | cpuLoad=85% | load |
| 主线程卡住 | dispatchMessage took 5005ms | "main" prio=5 tid=1 Blocked | blocked_main_thread |
| GC 停顿 | Background young concurrent copying GC freed | gcCount=12 | gc_stall |
| 系统发送 SIGQUIT | Sending signal. SIGQUIT | 文件生成标志 | anr_dump |
反推技巧:在 logcat 中搜索
ANR in 或 Input event dispatching timed out,定位到 ANR 触发时间点,再向前回溯 5~10 秒,观察 CPU 负载、GC 频率和主线程消息处理耗时,即可快速锁定可疑区间。
3.4 修复动作:日志持久化与采集策略配置
为防止 ANR 发生时日志被覆盖或丢失,需要在开发/测试阶段提前做好以下配置:
- 增大 logcat 缓冲区(build.prop 或开发者选项):
# 设置每个缓冲区大小为 8MB(默认 256KB) adb shell setprop persist.logd.size.main 8388608 adb shell setprop persist.logd.size.system 8388608 adb shell setprop persist.logd.size.events 8388608 - 保留多个 traces.txt 历史(Android 10+ 原生支持滚动):
# 启用 traces 滚动保留(最多 8 个文件) adb shell setprop persist.anr.traces.max_files 8 - dropbox 保留天数调整:
# 保留 7 天内的 ANR 条目(默认 3 天) adb shell setprop persist.dropbox.max_entries.ANR 50 - 自动化采集脚本:将采集命令封装为
collect_anr_logs.sh,ANR 发生后一键拉取全部日志。
3.5 复测:模拟 ANR 验证日志完整性
修改配置后,必须通过模拟 ANR 验证每种日志能否成功采集:
# 方法一:使用 adb 模拟主线程阻塞(需 root 或 eng 版本)
adb shell am start-foreground-service -a com.example.TEST_ANR
# 方法二:使用系统 ANR 测试工具(Android 10+)
adb shell cmd activity anr-test com.example.app 10000
# 方法三:通过开发者选项 → 立即执行 ANR(部分系统支持)
触发 ANR 后,按 3.2 节 的采集顺序逐一验证文件完整性:
traces.txt中是否包含目标进程的所有线程堆栈;logcat -d是否包含ANR in及前后 5 秒的 CPU 日志;dropbox --print ANR是否能检索到本次 ANR 条目;bugreport解压后anr/目录下是否存在对应的 traces 文件。
复测通过标准:四种日志源各自独立且时间戳偏差在 ±1 秒内,即视为采集链路完整可用。
3.6 预防:自动化日志兜底机制
在生产环境中,依赖人工采集往往滞后。建议在应用层和系统层建立自动化兜底:
| 层级 | 兜底方案 | 实现方式 |
|---|---|---|
| 应用层 | 注册 ANR 监听 + 本地日志回写 | Application.registerActivityLifecycleCallbacks + 自定义文件落盘 |
| 系统层 | logd 日志持久化到 /data/log | persist.logd.logpersistd 系统服务 |
| 云端层 | ANR 报告自动上传 | Firebase / 自建 Crash 上报 SDK |
| CI 层 | 自动化测试流水线集成日志采集 | UI 自动化框架 + 每用例执行前后采集 logcat |
重要提醒:应用层 ANR 监听存在局限性(无法监听系统级 ANR),只能作为辅助手段。系统层 traces.txt + dropbox 仍是 ANR 排查的黄金证据,必须确保 adb 调试权限或 bugreport 上传通道畅通。