4. 日志分析工具:adb logcat过滤、trace分析工具、dumpsys activity processes解析
4.1 现象识别:权限回调 ANR 的典型表现
权限回调导致 ANR 时,用户表现为点击“授权”或“拒绝”后界面无响应,几秒后弹出系统 ANR 对话框。从用户视角看:应用卡死 → 点击无反馈 → 系统提示“xxx 无响应”。从开发者视角看:Logcat 会输出 ANR in ... 与 Reason: Input dispatching timed out,且主线程堆栈最终停在 onRequestPermissionsResult 附近的耗时操作上。
排查前置条件:确保已开启开发者选项中的“显示所有 ANR”开关,并保持 USB 连接持续输出日志。
4.2 数据采集:三工具协同抓取现场
| 工具 | 命令/操作 | 采集目标 | 典型输出特征 |
|---|---|---|---|
| adb logcat | |
实时日志,捕获 ANR 触发点、权限请求时间戳、主线程阻塞线索 | 包含 ANR in com.example.app、Reason: Input dispatching timed out、权限回调方法名 |
| trace 文件 | |
主线程调用栈快照,精确找到阻塞点 | 主线程(main)堆栈停在 PermissionUtils.checkAndRequest → onRequestPermissionsResult → 耗时 I/O 或同步调用 |
| dumpsys activity processes | |
进程状态、等待锁信息、ANR 发生时的主线程状态 | waiting to lock、last ANR time、current state: WAIT |
采集顺序建议:先保持
adb logcat 持续输出,复现 ANR 后立刻执行 dumpsys activity processes 记录进程快照,再拉取 trace 文件(或直接通过 bugreport 获取完整 traces.txt)。避免时间错位导致关键信息丢失。
4.3 原因定位:从日志和堆栈逆向推导
定位遵循“主线程阻塞 → 定位阻塞方法 → 检查回调执行上下文”的故障树逻辑:
- Step 1 – 在 Logcat 中找到 ANR 时间戳,确认
PID和Reason是否包含 “permissions” 或 “callback”。 - Step 2 – 用 trace 分析工具(如
Chrome://tracing或直接文本搜索)打开 traces.txt,找到 PID 对应的主线程堆栈。判断堆栈中是否存在android.app.Activity.onRequestPermissionsResult→ 你自定义的权限处理逻辑。 - Step 3 – 结合
dumpsys activity processes输出,检查该进程是否持有锁或处于长时间等待状态。若发现held by thread 2等异常锁链,则可能是死锁或锁竞争加剧了回调阻塞。
常见误判:不要仅凭 Logcat 中权限相关日志就认定是回调本身慢。有时 ANR 是因为主线程在其他地方就已经阻塞,权限回调只是“最后一根稻草”。必须用 trace 确认调用栈的精确停留点。
4.4 修复动作:让权限回调不再阻塞主线程
根据定位结论(主线程在回调中执行了 网络请求、数据库写入、文件 I/O 或锁等待),修复原则是:将耗时代码移出回调,或用异步机制延迟执行。
- 方案 A – 回调内仅做状态标记,通过 Handler 或协程在主线程空闲时处理。
- 方案 B – 使用
ActivityResultLauncher替代旧式 permission API,其回调自带生命周期感知且不易阻塞。 - 方案 C – 若必须同步等待权限结果,设置超时保护(如
CountDownLatch配合await(timeout, unit)),避免无限阻塞。
// 修复示例:改用 ActivityResultLauncher
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
// 此处仅记录状态,不执行耗时操作
isPermissionGranted = granted
// 实际耗时操作通过 ViewModel 或 WorkManager 调度
viewModel.loadDataAfterPermission(granted)
}
4.5 复测:用工具验证修复效果
复测时保持数据采集工具开启,重复触发权限请求。检查点:
| 检查项 | 预期结果 |
|---|---|
| Logcat 中不再出现 ANR 相关输出 | 无 ANR in 日志 |
| trace 文件中主线程堆栈不再停留在权限回调 | 回调方法调用链短且非阻塞 |
| dumpsys activity processes 输出中进程状态正常 | current state: RESUMED 或 IDLE |
4.6 预防:建立监控与自动分析机制
- 日志预检 – 在 CI 构建后自动运行
adb logcat -d | grep "ANR",若包含本应用包名则告警。 - Trace 存档 – 每次 ANR 自动上传 trace 文件到后端,按
permission关键词分类统计高频阻塞点。 - 代码审查规则 – 禁止在
onRequestPermissionsResult中直接调用同步网络、数据库、文件操作;使用 Lint 规则或自定义 checkstyle 拦截。
工具链整合建议:将 adb logcat 过滤、trace 解析、dumpsys 解析封装为一个自动化脚本,复现 ANR 后一键输出定位报告,减少手动排查时间。