3. bugreport 工具介绍
说实话,bugreport 是我日常排查问题用到最频繁的命令之一。你想想看,当测试同学扔过来一个「App 闪退了」或者「系统卡死了」,你第一反应是什么?我反正会先要一份 bugreport。它能把我当时不在现场的设备状态,原封不动地拉到我面前。
这一章咱们就掰开揉碎了聊聊:怎么生成 bugreport、怎么导出、以及拿到手之后那一大坨文件到底怎么看。
核心概念:bugreport = 系统状态快照 + 日志归档 + 诊断数据包。它不是某个单一日志文件,而是一个结构化的数据集合。
3.1 什么是 bugreport?
bugreport 是 Android 系统内置的诊断数据收集工具。说白了,它就是把设备当前的内存状态、进程列表、日志缓冲区、系统服务信息、网络状态、电池数据、文件系统关键节点……一股脑打包出来。
我个人习惯把 bugreport 理解成「设备的飞行黑匣子」。你不需要复现问题,只要在问题发生后的第一时间抓取,里面大概率已经记录了关键线索。
| 维度 | 说明 | 典型数据量 |
|---|---|---|
| 系统信息 | 构建版本、内核版本、启动时间、运行时长 | 约 20-50 KB |
| 进程状态 | 所有进程的 CPU/内存占用、线程信息 | 约 200-500 KB |
| 系统服务 | ActivityManager、WindowManager、PackageManager 等状态 | 约 1-3 MB |
| 日志缓冲区 | main、system、events、crash、kernel 等 log | 约 2-8 MB |
| 异常信息 | ANR traces、Java 堆栈、Native 堆栈 | 约 100-500 KB |
我的经验:曾经遇到一个「Wi-Fi 连不上」的问题,测试同学复现了 3 天都没抓到规律。我让他每次连不上就立刻抓一份 bugreport,第 2 份就发现是 wpa_supplicant 进程在某个特定场景下 crash 了。没有 bugreport,这种偶发问题真的很难定位。
3.2 生成 bugreport:三种常用方式
生成 bugreport 的方式就那么几种,我按推荐度排个序:
方式一:adb 命令(最推荐)
# 生成完整 bugreport(zip 包)
adb bugreport
# 指定输出路径
adb bugreport ./my_bugreport.zip
执行后设备会开始收集数据,大概等 30 秒到 2 分钟(取决于系统负载),然后在当前目录生成一个类似 bugreport-2025-01-15-14-30-00.zip 的文件。
注意:adb bugreport 在 Android 7.0+ 上默认输出 zip 包,包含完整结构。如果你在用 Android 6.0 及以下的设备,输出的是纯文本文件,内容是一样的,只是没有目录结构。
方式二:设备端手动生成
进入「开发者选项」→ 「Bug 报告」→ 「生成报告」。系统会弹出分享菜单,你可以通过邮件、网盘等方式把文件发出来。嗯,适合没有 adb 环境的测试同学。
方式三:组合键(极少用)
同时按住「音量上 + 音量下 + 电源键」约 3 秒,设备震动后开始生成。说实话,这个方式容易误触,我一般不推荐。
对比总结:adb 方式最可控,可以指定输出路径和文件名;设备端生成适合外场测试;组合键只适合紧急场景。
3.3 导出 bugreport:两种常见场景
生成之后怎么把文件弄到电脑上?分两种情况:
场景 A:adb bugreport 直接生成在电脑上
这种情况你已经在电脑上了,文件就在当前目录,直接解压就行。
场景 B:设备端生成,需要拉取到电脑
# 查看设备上的 bugreport 文件
adb shell ls /data/bugreports/
# 拉取到电脑
adb pull /data/bugreports/bugreport-xxx.zip ./
有些厂商会把 bugreport 存在 /sdcard/bugreports/ 或者 /data/data/com.android.shell/files/bugreports/,路径稍有不同。我建议先用 adb shell find / -name "bugreport*" 2>/dev/null 扫一遍,省得一个个目录翻。
小技巧:如果你有多台设备,可以用 adb -s <serial> bugreport 指定单台设备,避免串号。
3.4 结构解析:zip 包里面到底有什么?
拿到 zip 包之后先解压,目录结构大概长这样:
bugreport-设备名-日期/
├── bugreport.txt # 主报告文件(纯文本,超大型)
├── bugreport_info.txt # 报告元信息(版本、时间、命令)
├── dumpstate_log.txt # dumpstate 执行日志
├── logs/ # 各种日志子目录
│ ├── logcat.txt # 主 logcat 输出
│ ├── logcat.txt.gz # 压缩版
│ ├── events.txt # events 日志
│ ├── kernel.log # 内核日志
│ └── radio/ # 无线通信日志(如果设备支持)
├── FS/ # 文件系统快照
│ ├── proc/ # /proc 下的关键节点
│ ├── sys/ # /sys 下的设备状态
│ └── data/ # /data 部分关键文件
└── dumpstate/ # 详细 dump 数据
├── anr/ # ANR traces
├── hprof/ # Java heap dump(如果触发)
└── tombstone/ # Native crash tombstone
我拿到 bugreport 后的「三板斧」是这样的:
- 先看 bugreport.txt 的前 200 行——确认设备基本信息、运行时长、构建版本,先判断是不是已知问题。
- 搜 "CRASH" 和 "ANR"——用
grep -in "crash\|anr" bugreport.txt快速定位异常。 - 看 logcat.txt 里目标进程的最后 500 行——确认崩溃前的操作序列。
核心思路:bugreport 数据量大,不要从头到尾读。带着问题去找线索,效率最高。
为什么会强调这个顺序?我之前有个同事,拿到 bugreport 直接双击打开,从第 1 行开始往下翻,翻了半小时还在看 CPU 频率表……你想想看,那里面光 dumpsys 的输出就几千行,这么看法太低效了。
说到 dumpsys,我再提一嘴:bugreport 里的 dumpsys 输出跟单独执行 adb shell dumpsys 是一样的,但它是一个「时间点快照」。我记得有个案例,某 App 在后台被频繁 kill,我从 bugreport 里的 dumpsys procstats 和 dumpsys meminfo 直接看到系统在持续低压杀进程,定位到是某个三方服务的内存泄漏。没有 bugreport 的全局视角,这种跨进程的问题很难串联起来。
3.5 快速使用 checklist
| 步骤 | 操作 | 预期产出 |
|---|---|---|
| 1 | 连设备,执行 adb bugreport |
zip 包(30秒-2分钟) |
| 2 | 解压 zip,确认目录结构完整 | bugreport.txt + logs/ + FS/ |
| 3 | 用文本编辑器打开 bugreport.txt | 查看设备基本信息 |
| 4 | 搜索 "CRASH" / "ANR" / "FATAL" | 定位异常入口 |
| 5 | 查看 logs/logcat.txt 中对应进程的日志 | 获取详细异常上下文 |
避坑指南:我曾经在一个项目里连续抓了 5 份 bugreport 都发现 logcat 是空的,查了半天才发现是测试机开启了「日志大小限制 = 关闭」,导致 logd 没启动。生成 bugreport 之前,最好先确认 adb shell logcat -c 之后能正常输出日志。否则你抓回来的报告,logcat 部分就是一片空白。