第3章 ANR日志获取:四种核心手段
3.1 为什么日志是ANR分析的第一步?
你想想看,ANR发生了,你手上什么数据都没有,怎么定位问题?靠猜吗?
日志就是ANR现场的"黑匣子"。它记录了崩溃瞬间的线程堆栈、CPU负载、内存状态、Binder事务等信息。没有这些,你连主线程在干什么都不知道。
我个人习惯是:一旦复现ANR,第一件事就是拉日志。先别急着看代码,先把现场固定下来。我在项目中遇到过好几次,开发者先改代码再拉日志,结果问题复现不了,日志也拿不到,白白浪费了一整天。
所以,拿到完整、准确的日志,是ANR分析的基础。这一章我们就来聊聊四种获取日志的核心手段。
3.2 四种获取方式概览
下面这张图概括了四种方式的关系和定位。你收日志的时候,可以按需选择,也可以组合使用。
3.3 详解四种获取方式
方式一:adb bugreport
adb bugreport 可以说是最"重"的手段。它会打包系统的全量信息,包括CPU负载、内存状态、进程列表、Binder事务、内核日志等等。说白了,一份bugreport就是设备的"体检报告"。
命令很简单:
adb bugreport ./bugreport_$(date +%Y%m%d_%H%M%S)
但是要小心——生成时间很长。我在低端机上跑过,足足等了2分多钟。如果ANR现场比较脆弱,可能等你bugreport生成完,现场已经没了。
方式二:/data/anr/traces.txt
这是我最常用的方式,没有之一。它直接告诉你ANR发生时所有线程的堆栈。主线程卡在哪儿?Binder线程在等什么?一看便知。
拉取命令:
adb root
adb shell cat /data/anr/traces.txt > traces_$(date +%Y%m%d_%H%M%S).txt
或者如果设备没root,可以用:
adb bugreport # 然后从bugreport包里提取traces.txt
我曾经踩过这个坑:traces.txt会被覆盖。系统默认只保留最近一次ANR的traces。如果你连续复现了两次ANR,第一次的traces就被冲掉了。所以我建议:每次ANR发生后立即拉取,别等。
adb shell ls /data/anr/ 查看具体文件名。
方式三:logcat过滤
你想想看,如果每次都要等bugreport生成,黄花菜都凉了。logcat过滤是最快拿到ANR线索的方式。系统在发生ANR时,会输出带 "ANR in" 关键字的日志。
过滤命令:
adb logcat | grep "ANR in"
或者更精确一点,抓取ANR完整上下文:
adb logcat -v threadtime | grep -E "ANR|am_anr|Reason:"
我在项目中遇到过一个问题:logcat缓冲区太小,ANR日志被冲掉了。尤其是游戏类应用,日志量巨大。所以我通常会提前调大缓冲区:
adb logcat -G 16M
adb logcat -b events | grep am_anr 从events缓冲区抓ANR事件,这个缓冲区通常更稳定。
方式四:dropbox信息
dropbox这块容易被忽略。它记录的是系统级的关键事件,包括ANR、crash、watchdog等。dropbox里保存的数据比traces.txt更全面,有时候还会附带CPU使用率、内存快照等。
查看方式:
adb shell dumpsys dropbox --print | grep -A 50 "ANR"
或者直接拉取所有ANR相关的dropbox条目:
adb shell dumpsys dropbox --print | grep "process_crashed_meminfo\|anr"
说实话,dropbox是"救急"用的。当traces.txt被覆盖、logcat被冲掉时,dropbox往往还能找到线索。我遇到过好几次traces.txt为空,全靠dropbox里残留的堆栈信息定位问题。
3.4 四种方式对比
| 方式 | 数据范围 | 获取速度 | 核心用途 |
|---|---|---|---|
| adb bugreport | 系统全量信息 | 较慢(30s~2min) | 全局分析、跨进程依赖 |
| /data/anr/traces.txt | 线程堆栈快照 | 快(秒级) | 定位卡顿线程、锁竞争 |
| logcat过滤 | 日志流(实时) | 实时 | 快速筛选ANR现场 |
| dropbox信息 | 系统级事件记录 | 快(秒级) | 异常事件追溯、兜底 |
3.5 实战建议与避坑
我的标准操作流程(SOP):
- ANR发生 → 第一时间
adb logcat | grep "ANR in",截取现场日志。 - 马上
adb shell cat /data/anr/traces.txt拉取堆栈。 - 如果traces.txt被覆盖,立刻查
dumpsys dropbox找残留数据。 - 时间允许的话,后台跑一份
adb bugreport做全局补充。
避坑指南——我曾经吃过亏的几个点:
- 不要太依赖bugreport。现场越卡,bugreport生成越慢,甚至可能把系统拖死。
- traces.txt 不是一直存在的。系统在重启、存储空间不足时会清理它。
- logcat 缓冲区默认只有64KB(旧设备甚至更小)。提前
adb logcat -G 16M是保命操作。 - dropbox 条目有数量限制,老条目会被自动删除。所以ANR发生后尽快拉取。
一点小建议:把这四种方式的命令写成脚本,放到你的工具库里。我在团队里就是这么做的——一个 anr_capture.sh 脚本,一键跑完所有日志收集步骤。这样即使你不在现场,也能让测试同学帮忙跑,大大降低沟通成本。
好了,这一章的内容就到这里。日志拿到了,下一步就是分析。怎么从堆栈里快速定位问题?那是后面章节要聊的事。先把日志收好,这是所有分析的基础。