2. 崩溃日志采集与解读:Logcat定位、native堆栈、ANR trace分析
当 CameraX 出现崩溃或 ANR 时,快速采集正确的日志是修复的第一步。本章将拆解三种崩溃类型(Java Crash、Native Crash、ANR)的现象、日志特征与定位方法,并通过故障树和排查表帮助你系统化定位根因。
2.1 现象识别
崩溃发生时,首先需要判断其类型。下表总结了三种崩溃的典型表象:
| 崩溃类型 | 现象 | 关键日志关键字 | 系统表现 |
|---|---|---|---|
| Java Crash | 应用直接闪退,弹窗“xxx已停止运行” | FATAL EXCEPTION、java.lang.* | 进程终止,返回桌面 |
| Native Crash | 闪退无弹窗,或出现SIGSEGV等信号 | signal 11、tombstone_* | 进程被系统杀掉,可抓取tombstone |
| ANR | 应用卡死后弹窗“xxx无响应” | ANR in xxx、cpu=、waiting on | 应用未退出但无响应 |
快速判断规则: Logcat 中搜索
FATAL EXCEPTION 为 Java Crash;搜索 signal 后跟数字且不含 java 堆栈为 Native Crash;搜索 ANR in 为 ANR。2.2 数据采集方法与命令
在问题复现时,应立即采集以下三类日志:
2.2.1 Logcat 实时日志
使用 adb 命令捕获全量日志,建议加上时间戳和进程过滤:
# 清空旧日志后启动实时捕获(按Ctrl+C停止)
adb logcat -c && adb logcat -v threadtime -s "CameraX:*" "ActivityManager:*" "*:E" > crash_log.txt
# 过滤指定 pid(如果知道进程号)
adb logcat -v threadtime --pid=1234 > pid_1234_log.txt
2.2.2 Native 崩溃 tombstone 文件
Native Crash 发生后,系统在 /data/tombstones/ 目录生成 tombstone_xx 文件,包含寄存器、调用栈和内存映射。使用以下命令提取:
# 查看所有tombstone
adb shell ls -l /data/tombstones/
# 拉取最新tombstone
adb pull /data/tombstones/tombstone_00 ./tombstone_00.txt
2.2.3 ANR Trace 文件
ANR 发生时,系统在 /data/anr/traces.txt 记录所有线程状态。使用如下方法:
# 普通权限设备(需要 root 或 debuggable)
adb pull /data/anr/traces.txt ./anr_traces.txt
# 无 root 的非 debuggable 设备,可通过以下方式触发生成(部分系统支持)
adb shell am force-stop com.example.app
# 等待 ANR 后使用 bugreport
adb bugreport
# 解压后在 FS/data/anr/traces.txt 中找到
注意事项:ANR trace 文件在非 root 设备上可能无法直接 pull,优先使用 bugreport 方式获取完整报告。
2.3 原因定位:故障树与排查表
使用故障树可以结构化地分析崩溃根因。下图以 CameraX 崩溃场景为例:
2.3.1 排查表
以下排查表帮助根据日志特征快速定位根因类型:
| 日志特征 | 可能的根因 | 推荐动作 |
|---|---|---|
java.lang.NullPointerException + CameraX API 调用 | 未检查 CameraX 生命周期绑定状态 | 添加空值检查,使用 ProcessCameraProvider.getInstance() 回调 |
signal 11 (SIGSEGV) 且 pc 落在 libcamera_client.so | Camera HAL 内部指针错误 | 检查设备兼容性,降级 CameraX 版本或使用 Camera2 备用 |
ANR + 主线程在 ImageCapture.takePicture 上阻塞 | 拍照回调中执行耗时操作 | 将回调切换到后台线程,使用 Executor 或 ListenableFuture |
FATAL EXCEPTION: main + CameraXConfig 相关 | 配置初始化时线程问题 | 确保 CameraXConfig 在主线程调用前完成 |
关键原理: CameraX 内部使用
ListenableFuture 和 HandlerThread 管理异步操作。如果主线程直接等待 Future 结果会导致 ANR;如果 Native 层访问已释放的内存则导致 SIGSEGV。理解这些设计模式有助于快速定位日志。2.4 修复动作
基于日志定位后,针对常见根因的修复示例:
- Java Crash - 空指针: 在
ProcessCameraProvider.unbindAll()后立即调用bindToLifecycle()前,检查 provider 是否已关闭。 - Native Crash - Camera HAL 崩溃: 尝试使用
CameraSelector的DEFAULT_BACK_CAMERA替换为CAMERA_FACING_FRONT测试,排除硬件问题。若为特定设备,添加黑名单。 - ANR - 主线程阻塞: 将
takePicture或setAnalyzer的回调通过Executors.newSingleThreadExecutor()执行。
// 修复ANR示例:使用后台线程处理拍照结果
ImageCapture capture = new ImageCapture.Builder().build();
capture.takePicture(context,
Executors.newSingleThreadExecutor(),
new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy image) {
// 处理图像(不在主线程)
}
});
2.5 复测
- 在已知崩溃的设备/系统上复现场景,确保不再出现相同日志。
- 执行压力测试:连续点击拍照、切换摄像头、旋转屏幕、按Home键再返回,每个动作间隔200ms,循环100次。
- 检查 Logcat 中无
FATAL EXCEPTION、无signal相关 warning、无ANR。 - 若原因为 Native,验证 tombstone 不再生成。
2.6 预防措施
- 在应用发布版本中开启
android:debuggable="false"并集成崩溃日志自动上传(如 Firebase Crashlytics)。 - 对 CameraX 关键调用加
try-catch (RuntimeException),将堆栈写入自有日志文件。 - 在 CI/CD 流程中集成 Monkey 测试和 ANR 预检测脚本。
# 自动化ANR检测脚本片段(bash)
adb shell dumpsys activity processes | grep "anr" > anr_check.txt
if [ -s anr_check.txt ]; then
echo "ANR detected"
adb pull /data/anr/traces.txt ./ci_anr_$(date +%s).txt
fi
最佳实践: 在测试阶段就开启
adb logcat -v threadtime -b all 记录全量日志,配合 strace 可进一步追踪native调用。对于 CameraX,推荐在 CameraXConfig 中设置 setCameraExecutor 和 setSchedulerHandler 来避免线程饥饿。