第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 做全量诊断。

3.2 数据采集:四大日志源的获取时机与标准命令

四种日志源分别从不同维度记录 ANR 证据,采集时机直接影响证据完整性。下表列出每种日志的触发机制、保存路径与核心价值:

日志源触发时机保存路径(设备端)核心内容采集优先级
logcat实时流,循环缓冲区内存缓冲区 → 可落盘系统事件、GC、CPU 负载、堆栈日志★★★★★
traces.txtANR 发生时系统自动 dump/data/anr/traces.txt所有线程堆栈、锁信息、CPU 时间片★★★★★
dropboxANR 发生后数秒内写入/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 traces.txt(最易被覆盖)
2. 再 dump logcat -d(缓冲区可保留数分钟)
3. 接着导出 dropbox(持久保存,但需 adb shell)
4. 最后生成 bugreport(耗时最长,适合离线分析)
ANR 日志采集时间线与决策流 ANR 触发 T₀ logcat 实时流 T₀+0ms traces.txt dump T₀+200ms dropbox 归档 T₀+1s bugreport 综合聚合(手动触发) 日志关联分析 → 原因定位 ⏱ 黄金采集窗口:ANR 发生后 30 秒内完成 logcat -d 和 traces.txt pull,避免缓冲区覆盖 采集顺序:traces.txt → logcat -d → dropbox → 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.1cpuLoad=85%load
主线程卡住dispatchMessage took 5005ms"main" prio=5 tid=1 Blockedblocked_main_thread
GC 停顿Background young concurrent copying GC freedgcCount=12gc_stall
系统发送 SIGQUITSending signal. SIGQUIT文件生成标志anr_dump
反推技巧:在 logcat 中搜索 ANR in 或 Input event dispatching timed out,定位到 ANR 触发时间点,再向前回溯 5~10 秒,观察 CPU 负载、GC 频率和主线程消息处理耗时,即可快速锁定可疑区间。

3.4 修复动作:日志持久化与采集策略配置

为防止 ANR 发生时日志被覆盖或丢失,需要在开发/测试阶段提前做好以下配置:

  1. 增大 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
  2. 保留多个 traces.txt 历史(Android 10+ 原生支持滚动):
    # 启用 traces 滚动保留(最多 8 个文件)
    adb shell setprop persist.anr.traces.max_files 8
  3. dropbox 保留天数调整:
    # 保留 7 天内的 ANR 条目(默认 3 天)
    adb shell setprop persist.dropbox.max_entries.ANR 50
  4. 自动化采集脚本:将采集命令封装为 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/logpersist.logd.logpersistd 系统服务
云端层ANR 报告自动上传Firebase / 自建 Crash 上报 SDK
CI 层自动化测试流水线集成日志采集UI 自动化框架 + 每用例执行前后采集 logcat
重要提醒:应用层 ANR 监听存在局限性(无法监听系统级 ANR),只能作为辅助手段。系统层 traces.txt + dropbox 仍是 ANR 排查的黄金证据,必须确保 adb 调试权限或 bugreport 上传通道畅通。