Android获取崩溃日志
一、adb 命令(PC 调试,最常用)
1、单独抓崩溃缓冲区(推荐,等价提取 bugreport 里 crash 部分)
# 读取crash缓冲区,只拿崩溃日志
adb logcat -b crash
# 输出到文件
adb logcat -b crash -d > crash.txt
# 同时读main、system、crash,类似bugreport里日志段
adb logcat -b main -b system -b crash -d > all_log.txt
-d:dump 一次然后退出,不会持续监听-b crash:专门崩溃缓冲区,Java 崩溃、ANR 都在这里Android De...
2、dumpstate(bugreport 核心组成,输出大量诊断信息)
adb shell dumpstate > dumpstate.txt
bugreport 底层就是调用 dumpstate。
3、dumpsys 拿进程退出信息(Android12+)
adb shell dumpsys activity --processes
4、tombstone 原生崩溃(C/C++ sigsegv,native 崩溃)
文件路径 /data/tombstones/,需要 root 或者 adb shell:
adb shell su -c cat /data/tombstones/tombstone_00
非 root 普通 adb 无法直接读取 tombstone 文件Android Op...
二、App 内 Java 代码获取(重点,你业务埋点上报用)
⚠️ 限制:第三方普通 App只能读取自己 App 的崩溃信息,不能读别的 App / 系统崩溃,
READ_LOGS在 Android10 + 对第三方 App 基本废掉,不要依赖这个权限Android Op...
✅ Android12 (API31+) 官方 API:ApplicationExitInfo(谷歌推荐,可拿 Java 崩溃、ANR、native tombstone)
这个是系统开放给 App 读取自身历史退出原因,包含崩溃,替代以前读 logcat 方案Android De...
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.content.Context;
import java.io.InputStream;
import java.util.List;
public static void readExitInfo(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// 最多取最近10条,当前包名
List<ApplicationExitInfo> exitList = am.getHistoricalProcessExitReasons(context.getPackageName(), 0, 10);
for (ApplicationExitInfo info : exitList) {
int reason = info.getReason();
long time = info.getTimestamp();
if (reason == ApplicationExitInfo.REASON_CRASH) {
// Java异常崩溃
String trace = info.getTrace();
} else if (reason == ApplicationExitInfo.REASON_CRASH_NATIVE) {
// native崩溃,可以拿到tombstone流
try (InputStream is = info.getTraceInputStream()) {
// 解析protobuf tombstone
} catch (Exception e) {
e.printStackTrace();
}
} else if (reason == ApplicationExitInfo.REASON_ANR) {
// ANR
}
}
}
枚举说明:
REASON_CRASH:Java 未捕获异常崩溃REASON_CRASH_NATIVE:Native 信号崩溃REASON_ANR:ANRREASON_USER_REQUESTED:用户手动杀掉
缺点:Android12 以下无此 API;厂商部分 ROM 会裁剪这个接口返回内容。
✅ 兼容低版本方案:UncaughtExceptionHandler(Java 崩溃捕获,最稳)
只能捕获Java 崩溃,进程被杀、ANR、native 崩溃抓不到,必须搭配上面 ApplicationExitInfo
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
// 在这里保存堆栈到本地文件,下次启动读取上报
String stack = Log.getStackTraceString(throwable);
});
❌ 不推荐:App 内执行 logcat 命令
// Runtime.getRuntime().exec("logcat -b crash -d");
Android 10+ 第三方 App 执行这个拿不到任何数据,系统 selinux 限制,华为 / 小米 / 荣耀全部拦截,不要做。
三、对比表
表格
| 方式 | 是否类似 bugreport | 能否 App 内用 | 支持版本 | 能抓到什么 |
|---|---|---|---|---|
| adb bugreport | ✅ 完整版 | ❌ adb | 全部 | 全量日志、dumpsys、crash、tombstone |
| adb logcat -b crash | ✅ 只提取崩溃段 | ❌ adb | 全部 | Java 崩溃、ANR |
| adb shell dumpstate | ✅ bugreport 核心 | ❌ adb | 全部 | 系统诊断信息 |
| ApplicationExitInfo | ⚠️ 仅本 App 崩溃 | ✅ Java 代码 | Android12+ | Java Crash / Native Crash / ANR |
| UncaughtExceptionHandler | ❌ 仅实时 Java 异常 | ✅ Java 代码 | 全部 | Java 崩溃,native/ANR 抓不到 |
四、隐私 & 上架提醒
ApplicationExitInfo只能读取你自己包名的退出记录,不能读取其他 App 崩溃,隐私合规没问题;- 不要尝试反射、读
/data/tombstones、执行 logcat 全局抓日志,国内厂商 ROM 拦截、隐私审核高危; - 如果你要做一套崩溃收集上报:
UncaughtExceptionHandler + ApplicationExitInfo(Android12+)组合是行业标准方案(类似 Bugly、Firebase Crashlytics)。
五、补充:ANR 日志位置
ANR 日志在 /data/anr/traces.txt,同样普通第三方 App 无权限读取,adb 可以:
adb pull /data/anr/traces.txt
Android 9+ 普通 userdebug / 量产机,直接 adb pull /data/anr/traces.txt 绝大多数报 Permission denied,selinux 限制,拿不到。 高版本不再只有 traces.txt,文件名变成 anr_yyyy-MM-dd-HH-mm-ss-xxx 多个文件
方案 1(✅ 推荐,所有机型通用,不用 root,就是你前面问的 bugreport)
# 导出bugreport压缩包,解压后 FS/data/anr/ 下面包含全部anr traces文件
adb bugreport ./anr_report.zip
解压 zip → 路径:FS/data/anr/,里面就是 ANR 堆栈文件。
华为、小米、荣耀、鸿蒙全部能用,是官方标准获取 ANR 的方式
方案 2(模拟器 /root 手机 直接 pull)
# root/模拟器才生效
adb root
adb pull /data/anr/traces.txt ./
# 或者拉整个anr目录
adb pull /data/anr ./anr_folder
方案 3(老方案:shell 内复制到 sdcard 中转,新版很多 ROM 已经拦截 cat)
adb shell
# 复制到应用可读的临时目录
cat /data/anr/traces.txt > /sdcard/Download/traces.txt
exit
adb pull /sdcard/Download/traces.txt ./
很多新版鸿蒙 / HyperOS,shell 里 cat /data/anr/* 也会 Permission denied,此方案失效
方案 4(Android Studio 图形化)
View → Tool Windows → Device File Explorer 路径 /data/anr,高版本量产机同样无权限打开。
方案 5(App 代码内获取 ANR 堆栈,你业务埋点)
普通第三方 App不能直接读 /data/anr/ Android12+ 使用
ApplicationExitInfo,ANR reason =REASON_ANR,可以拿到 trace 文本流,这个是 App 内合法获取自己 ANR 的 API,前面给过代码。
补充小知识点
- traces.txt 是旧版单文件方案;新版系统每个 ANR 单独生成
anr_时间戳文件; - ANR 产生时机:主线程阻塞 > 5s,系统才会生成;没 ANR 的时候
/data/anr是空; - 区分:
- Java 崩溃:
logcat -b crash - ANR 堆栈:/data/anr 下的文件
- Native 崩溃:/data/tombstones
- Java 崩溃:
快速排查顺序
- 优先
adb bugreport(测试最稳) - 模拟器 → adb root + pull
- 业务上报 ANR → 依赖
ApplicationExitInfo
FS/data/anr/ 不是手机真实目录,它是 adb bugreport 生成的 zip 压缩包解压之后,压缩包内部的虚拟目录结构,手机上真实 ANR 目录仍然是 /data/anr。
完整导出步骤(电脑终端,Windows/Mac 通用)
- 手机打开开发者选项、USB 调试,adb 连接成功
# 生成bugreport压缩包,输出到电脑当前文件夹
adb bugreport anr_full.zip
执行会等待几十秒,系统打包日志
- 把
anr_full.zip拷贝到电脑,解压这个 zip 文件 - 打开解压后的文件夹,里面有一个名字叫
FS的文件夹 进入:FS/data/anr/✅ 这里面就是所有 ANR 堆栈文件(anr_时间戳文件,老机型会有 traces.txt) 直接复制这些文件到你的电脑其他目录即可。
补充说明
- 手机系统里不存在 FS 文件夹,FS = File System,是 bugreport 打包工具自己组织的目录视图,方便查阅。
- 量产普通手机(非 root):
- 不能直接
adb pull /data/anr,权限拒绝 - 👉 唯一稳定拿 ANR 堆栈的方式就是 bugreport(华为、鸿蒙、HyperOS 都生效)
- 不能直接
- 如果你只想快速定位 ANR,不想解压大包: 解压后还可以看
bugreport-xxx.txt,里面也包含 ANR 堆栈内容,可以直接搜索关键词ANR in
可选:快速检索 ANR(解压后在电脑上搜)
- 关键词:
ANR in 你的包名 - 关键词:
traces
对比
表格
| 路径 | 位置 | 是否可以直接 pull |
|---|---|---|
/data/anr | 手机真实路径 | 量产机 ❌ 无权限 |
FS/data/anr | bugreport 解压包内 | ✅ 解压后随便复制 |
Mac / Linux 一键脚本(adb + 自动解压)
adb bugreport anr_full.zip && unzip -o anr_full.zip -d ./bugreport_out
执行完:
- 在当前目录生成
anr_full.zip - 自动解压到文件夹
bugreport_out - ANR 文件路径:
./bugreport_out/FS/data/anr/
参数说明:
-o:覆盖旧文件,不弹窗询问
一键清理(用完删掉包和解压目录)
rm -rf anr_full.zip bugreport_out
Windows(PowerShell 版本)
adb bugreport anr_full.zip ; Expand-Archive -Force anr_full.zip -DestinationPath .\bugreport_out
解压后 ANR 路径:.\bugreport_out\FS\data\anr\
清理命令(PowerShell)
Remove-Item anr_full.zip; Remove-Item -Recurse -Force bugreport_out
注意:
- 执行前确认 adb 在环境变量、设备已经连上
- bugreport 打包耗时比较久(10~60 秒),耐心等待
- 如果手机里很久没有发生 ANR,
FS/data/anr目录是空的
附加:只检索 ANR 关键词,不用进文件夹翻
Mac/Linux,解压完成后直接搜索你的包名:
grep -r "ANR in com.xxx.xxx" ./bugreport_out
Windows PowerShell 搜索:
Select-String -Path .\bugreport_out\* -Pattern "ANR in com.xxx.xxx"
参数 “-o”:
unzip -o 里的 -o 是 overwrite,含义:直接覆盖已存在的文件,不弹出 y/n 确认提示。
unzip 常用参数(只挑高频)
-o overwrite,覆盖,不询问(重点你用到的)
-n never overwrite,绝不覆盖已有文件
-q quiet,安静模式,减少输出日志
-d xxx 指定解压目标目录(你脚本里的 -d ./bugreport_out)
对比
- 不加
-o:如果bugreport_out里面已经有同名文件,unzip 会在终端交互询问:replace xxx.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename:,脚本会卡在这里等输入,自动化流程就挂了。 - 加
-o:自动全部覆盖,无交互,适合一键脚本。
你的原命令
adb bugreport anr_full.zip && unzip -o anr_full.zip -d ./bugreport_out
执行逻辑:
- adb 生成报告成功后才执行后面
- unzip 解压,遇到重名直接覆盖,不等待人工确认
⚠️ 小风险:旧的 bugreport_out 里面你还没备份的内容会被覆盖丢失;如果你不想覆盖,可以改成
-n。
示例(不覆盖版本):
adb bugreport anr_full.zip && unzip -n anr_full.zip -d ./bugreport_out
更多推荐


所有评论(0)