一、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:ANR
  • REASON_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 抓不到

四、隐私 & 上架提醒

  1. ApplicationExitInfo 只能读取你自己包名的退出记录,不能读取其他 App 崩溃,隐私合规没问题;
  2. 不要尝试反射、读 /data/tombstones、执行 logcat 全局抓日志,国内厂商 ROM 拦截、隐私审核高危;
  3. 如果你要做一套崩溃收集上报: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,前面给过代码。

补充小知识点

  1. traces.txt 是旧版单文件方案;新版系统每个 ANR 单独生成 anr_时间戳 文件;
  2. ANR 产生时机:主线程阻塞 > 5s,系统才会生成;没 ANR 的时候 /data/anr 是空;
  3. 区分:
    • Java 崩溃:logcat -b crash
    • ANR 堆栈:/data/anr 下的文件
    • Native 崩溃:/data/tombstones

快速排查顺序

  1. 优先 adb bugreport(测试最稳)
  2. 模拟器 → adb root + pull
  3. 业务上报 ANR → 依赖 ApplicationExitInfo

FS/data/anr/ 不是手机真实目录,它是 adb bugreport 生成的 zip 压缩包解压之后,压缩包内部的虚拟目录结构,手机上真实 ANR 目录仍然是 /data/anr。


完整导出步骤(电脑终端,Windows/Mac 通用)

  1. 手机打开开发者选项、USB 调试,adb 连接成功
# 生成bugreport压缩包,输出到电脑当前文件夹
adb bugreport anr_full.zip

执行会等待几十秒,系统打包日志

  1. 把 anr_full.zip 拷贝到电脑,解压这个 zip 文件
  2. 打开解压后的文件夹,里面有一个名字叫 FS 的文件夹 进入:FS/data/anr/ ✅ 这里面就是所有 ANR 堆栈文件(anr_时间戳文件,老机型会有 traces.txt) 直接复制这些文件到你的电脑其他目录即可。

补充说明

  1. 手机系统里不存在 FS 文件夹,FS = File System,是 bugreport 打包工具自己组织的目录视图,方便查阅。
  2. 量产普通手机(非 root):
    • 不能直接 adb pull /data/anr,权限拒绝
    • 👉 唯一稳定拿 ANR 堆栈的方式就是 bugreport(华为、鸿蒙、HyperOS 都生效)
  3. 如果你只想快速定位 ANR,不想解压大包: 解压后还可以看 bugreport-xxx.txt,里面也包含 ANR 堆栈内容,可以直接搜索关键词 ANR in

可选:快速检索 ANR(解压后在电脑上搜)

  • 关键词:ANR in 你的包名
  • 关键词:traces

对比

表格

路径位置是否可以直接 pull
/data/anr手机真实路径量产机 ❌ 无权限
FS/data/anrbugreport 解压包内✅ 解压后随便复制

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

注意:

  1. 执行前确认 adb 在环境变量、设备已经连上
  2. bugreport 打包耗时比较久(10~60 秒),耐心等待
  3. 如果手机里很久没有发生 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

执行逻辑:

  1. adb 生成报告成功后才执行后面
  2. unzip 解压,遇到重名直接覆盖,不等待人工确认

⚠️ 小风险:旧的 bugreport_out 里面你还没备份的内容会被覆盖丢失;如果你不想覆盖,可以改成 -n。

示例(不覆盖版本):

adb bugreport anr_full.zip && unzip -n anr_full.zip -d ./bugreport_out
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐