4. 采集 ANR 日志:adb logcat 抓取 ANR 堆栈与前后缓冲区

4.1 本章在排查主线中的位置

在“现象识别”阶段确认 ANR 发生后,数据采集是锁定根因的关键步骤。adb logcat 能够捕获 App 进程在 ANR 时刻的堆栈快照、系统日志以及内核 buffer 状态,为后续分析 I/O 阻塞、Binder 死锁、主线程耗时等提供原始证据。

核心目标:在 ANR 发生后的数秒内,通过 adb logcat 获取包含 ANR in 标签的完整日志,尤其是主线程堆栈和前后缓冲区(main buffer 与 system buffer),避免因日志循环覆盖丢失关键帧。

4.2 前置条件与工具清单

需求项说明
USB 调试Android 设备已开启开发者选项中的 USB 调试
adb 工具版本 ≥ 1.0.36(支持 -b 参数指定 buffer)
系统权限抓取 system buffer 可能需要 root 或为 system 应用
时间同步设备时间与 PC 时间尽量一致,便于关联 logcat 时间戳与 ANR 发生时刻

4.3 抓取命令与参数详解

当 App 发生 ANR 时,Android 系统会在 /data/anr/traces.txt 中写入堆栈 dump,同时 logcat 会输出 ANR in 标记。对于 I/O 瓶颈类 ANR,必须同时捕获 main(主日志)和 system(系统事件)两个 buffer 的内容。

# 实时抓取并保存到文件(推荐)
adb logcat -b main -b system -v threadtime -d > anr_full.log

# 仅抓取 ANR 相关行(适合快速定位)
adb logcat -b main -b system -v threadtime -d | grep -E "(ANR in|DALVIK THREADS|----- pid )"

# 持续抓取直到手动停止(用于复现)
adb logcat -b main -b system -v threadtime > anr_live.log
参数说明:-b main 抓取应用日志,-b system 抓取系统级消息(如 Watchdog、IOWait),-v threadtime 输出含线程 ID 和精确时间戳,-d 表示 dump 当前缓冲区后退出。

4.4 前后缓冲区策略与循环覆盖

Android logcat 使用环形缓冲区,默认大小因设备而异(通常 main 256KB,system 256KB)。ANR 发生后,若继续产生大量日志,关键堆栈可能被后续日志覆盖。因此建议:

  • 立即执行:检测到 ANR 弹窗后,3 秒内执行 adb logcat -b main -b system -d dump 操作。
  • 增大缓冲区:若环境允许,预先调整 buffer 大小(需要 root):logcat -b main -G 1M。
  • 多 buffer 备份:同时抓取 events buffer(系统事件)辅助分析 I/O 等待原因:
    adb logcat -b events -v threadtime -d > events_anr.log

4.5 堆栈定位与 I/O 标记识别

抓取后的 anr_full.log 中,重点关注以下模式:

日志特征指示含义
ANR in ... (com.example.app)ANR 进程包名与时间戳
----- pid 12345 at 2025-03-20 14:30:00 -----堆栈 dump 起始标记
main (native): #00 pc ... /system/lib/libc.so (__ioctl+4)主线程阻塞在 I/O 系统调用(如 ioctl、read、write)
"main" prio=5 tid=1 Blocked主线程处于 Blocked 状态
java.io.FileInputStream.readBytes / android.database.sqlite.SQLiteSession.acquireConnection上层 I/O 或数据库竞争
排查技巧:在日志中搜索 ioctl、futex、epoll_wait 等内核符号,结合 system buffer 中的 Watchdog 信息,可快速判断是否因磁盘 I/O 高负载导致主线程无法获得 CPU 或文件锁。

4.6 常见采集误区与避坑

  • 只用 -b main:遗漏 system buffer 中的系统级提示(如 I/O wait 百分比、磁盘排队深度)。
  • 未使用 -d:持续监听会覆盖旧日志,丢失 ANR 现场。
  • 时间戳不一致:设备与 PC 时间差导致无法匹配 ANR 报告时间。
  • 忽略 /data/anr/traces.txt:该文件包含更详细的 native 堆栈,与 logcat 互为补充。

4.7 本章故障树:adb logcat 采集执行流程

下图展示了从检测 ANR 到获取有效堆栈的决策与操作路径:

adb logcat 采集 ANR 日志流程 adb logcat 采集 ANR 日志故障树 检测到 ANR 弹窗 时间戳: T0 有 root 权限? 增大 buffer logcat -G 1M 使用默认 buffer 快速 dump 执行 dump 命令 -b main -b system -d 检查 ANR 堆栈 grep "ANR in" 得到 anr_full.log 提示:同时抓取 /data/anr/traces.txt 获取更完整堆栈

4.8 本章小结检查表

检查项是否完成
已连接 USB 调试并确认 adb 可用☐
ANR 发生后 3 秒内执行 dump 命令☐
同时使用了 -b main 和 -b system☐
日志中可找到 “ANR in” 及主线程堆栈☐
已检查 /data/anr/traces.txt 是否存在☐
注意:如果日志中未找到堆栈,可能是 buffer 已被覆盖。建议下次复现时使用 logcat -b main -G 2M 预先扩大缓冲区,或编写自动 dump 脚本(如监听 ActivityManager: ANR in 关键词实时触发)。