4、日志获取:adb logcat抓取日志、获取tombstone文件、获取traces.txt文件
好,咱们进入实战环节的第一个硬核技能——日志获取。
说实话,很多同学遇到Native Crash或者ANR,第一反应就是“看日志”。但日志在哪儿?怎么抓?抓完怎么看?这三个问题能卡住一大半人。我当年刚入行时,就因为在客户现场拿不到完整的tombstone文件,被老大骂了一顿。从那以后,我养成了一个习惯:先搞清楚日志的“家”在哪儿,再动手抓。
4.1 adb logcat:你的第一把瑞士军刀
adb logcat是Android调试的标配。但很多人只会用adb logcat裸跑,结果刷出一堆没用的信息。我个人习惯,先加几个关键参数。
核心命令模板:
# 清空旧日志,只抓新日志
adb logcat -c
adb logcat -v threadtime *:V > crash.log
# 如果只想看Native层崩溃
adb logcat -v threadtime -s "DEBUG" > native_crash.log
# 抓ANR相关日志(重点关注ActivityManager)
adb logcat -v threadtime -s "ActivityManager" "SystemServer" "ANR" > anr.log
这里有个坑,我踩过好几次:日志级别。如果你只设*:E,很多关键的前置信息会被过滤掉。比如Native Crash前的堆栈准备、信号处理过程,这些往往是D或I级别的。所以我建议,抓崩溃日志时用*:V,回头再慢慢筛。
我的小技巧: 抓日志时,顺手把dmesg也抓一份。很多底层的内存越界、内核OOM killer信息,logcat里看不到,但dmesg里一清二楚。
adb shell dmesg > kernel.log
4.2 获取tombstone文件:Native Crash的“尸检报告”
tombstone文件,说白了就是Native层崩溃时的快照。它记录了崩溃时的寄存器状态、调用栈、内存映射等信息。没有它,你分析Native Crash就像盲人摸象。
tombstone文件默认存放在:
/data/tombstones/
# 文件名通常是 tombstone_00, tombstone_01 ... 最多到 tombstone_09
获取命令很简单:
# 先确认有没有权限(需要root或system权限)
adb shell ls -l /data/tombstones/
# 拉取所有tombstone文件到本地
adb pull /data/tombstones/ ./tombstones_backup/
# 如果权限不够,试试用run-as(针对debuggable应用)
adb shell run-as com.your.package cat /data/tombstones/tombstone_00 > tombstone_00.txt
注意: tombstone文件是循环覆盖的。最多保留10个,新的会覆盖旧的。所以一旦发生崩溃,第一时间拉取tombstone。我曾经因为多测了几次,结果最早的tombstone被覆盖了,关键信息全丢了。
拿到tombstone后,怎么看?我一般先看这几个关键字段:
| 字段 | 含义 | 我的关注点 |
|---|---|---|
Build fingerprint |
系统版本信息 | 确认是不是特定ROM的问题 |
pid: xxx, tid: xxx |
进程ID和线程ID | 看是不是主线程崩溃 |
signal xx (SIGSEGV) |
崩溃信号类型 | SIGSEGV一般是空指针或野指针 |
backtrace |
调用栈 | 最核心,直接定位到代码行 |
memory map |
内存映射 | 看so库加载地址,辅助解析 |
4.3 获取traces.txt文件:ANR的“现场笔录”
ANR发生时,系统会生成一份traces.txt文件。它记录了ANR那一刻,所有线程的堆栈信息。说白了,就是系统帮你“拍了一张快照”,告诉你每个线程在干什么。
traces.txt的路径比较特殊:
# 传统路径(Android 10及以下)
/data/anr/traces.txt
# 新版本路径(Android 11+)
/data/anr/traces_xxx.txt # 文件名带时间戳
# 或者
/data/system/dropbox/ANR_xxx.txt # dropbox里也有一份
获取命令:
# 直接拉取
adb pull /data/anr/traces.txt ./
# 如果权限不够,试试
adb shell cat /data/anr/traces.txt > traces.txt
# 对于Android 11+,先看看有哪些文件
adb shell ls /data/anr/
adb pull /data/anr/traces_最新时间戳.txt ./
重点看什么?
- 主线程(main):如果主线程卡在某个方法上,比如
InputMethodManager或Binder调用,那基本就是ANR的元凶。 - 锁等待(waiting for lock):看到
waiting to lock <xxx>,说明有死锁或锁竞争。 - CPU占用:traces.txt顶部会显示CPU使用率,如果CPU跑满,可能是线程太多或死循环。
举个例子,我曾经遇到一个ANR,traces.txt里主线程卡在android.os.BinderProxy.transactNative。一看就是Binder调用超时。再往下翻,发现一个后台线程在doSomeHeavyWork里持有了锁,主线程等不到锁释放。嗯,典型的锁竞争问题。
4.4 实战中的“组合拳”
光拿一个文件往往不够。我个人的标准流程是:
- 先抓logcat:用
-v threadtime格式,保存到文件。 - 再拉tombstone:如果logcat里看到
DEBUG进程输出,说明有Native Crash,立刻拉tombstone。 - 最后拉traces.txt:如果logcat里看到
ANR in xxx,立刻拉traces.txt。 - 别忘了dmesg:很多底层问题,logcat里没有,但dmesg里有。
避坑指南: 我曾经在抓日志时,忘了先执行adb logcat -c,结果抓了10分钟的旧日志,关键崩溃信息被冲走了。所以,抓日志前一定先清空,除非你想看历史记录。
好了,日志获取这块就讲到这里。下一章,咱们聊聊怎么用这些日志,一步步定位到具体的代码行。说白了,拿到日志只是第一步,会看才是真本事。