ANR 全类型:输入、广播、服务与 Provider 的超时
2026/8/9大约 4 分钟性能与稳定性Android 14ANR超时稳定性
ANR 全类型:输入、广播、服务与 Provider 的超时
上一章有了时间线工具。这一章回答:ANR 有哪些类型,各自的超时语义是什么,弹窗背后的 等待链怎么读?
输入、前台服务、广播和 Provider ANR 的计时起点与等待对象不同。拿到 traces 后应先从 系统日志确认 ANR 类型和触发时间,再判断主线程栈是根因、等待者还是采样时的后续状态。
先识别是哪一种超时
| 常见误解 | 正确理解 |
|---|---|
| ANR 只有一个原因:主线程卡死 | 主线程卡是表象,根因可能是锁、Binder、GC、I/O 或调度 |
| ANR 弹窗只发生在输入超时 | 广播、服务、Provider 超时同样弹 ANR |
| 看 ANR 文件只看主线程 | 要先看超时类型,再看主线程栈与其他线程的持锁关系 |
核心结论
- 输入 ANR:事件投递后应用未按时消费(约 5 秒量级)。
- 广播 ANR:前台广播约 10 秒、后台约 60 秒(以源码常量为准)。
- 服务 ANR:前台服务约 20 秒、后台约 200 秒(以源码常量为准)。
- Provider ANR:ContentProvider 初始化超时(约 10 秒量级)。
- 定位方法统一:读 ANR 文件里的超时类型与主线程栈,再用 Perfetto 还原时间线。
超时类型与等待链
逐步解释:
- 输入:dispatcher 投递后,主线程未在阈值内消费/完成。
- 广播:主线程的 onReceive 未按时返回。
- 服务:主线程的 onCreate/onStartCommand 未按时完成。
- Provider:应用启动时 Provider 初始化阻塞了等待方。
- 统一收口:都表现为主线程卡点,用 ANR 文件 + trace 定位。
为什么“主线程卡”不是根因
ANR 文件会给出主线程栈,但它只回答“卡在哪一行”,不回答“为什么卡”。要回答后者, 需要看其他线程:是否持有锁(同步块)、Binder 线程是否占满、GC 是否频繁、I/O 是否 阻塞。所以定位流程永远是“栈 + 锁 + 时间线”三件套。
源码证据
阅读目标:确认超时来源与 ANR 入口。
正文指针:ActivityManagerService.java 的 appNotResponding 与超时常量; InputDispatcher.cpp 的输入超时。
// ActivityManagerService.java(伪代码,行号以 r75 为准)
void appNotResponding(ProcessRecord app, ...) {
// 写 /data/anr,生成 ANR 文件与弹窗
}这段代码证明: 各类超时最终汇入同一个 appNotResponding 入口;ANR 文件包含超时 原因、主线程栈与 CPU 使用信息,是定位的第一证据。
验证与排障
环境:开发设备或模拟器;读取 ANR 文件通常需要 root 或开发者权限。
adb shell ls /data/anr/
adb shell cat /data/anr/anr_* | head -200
adb shell dumpsys activity processes | grep -i anr先看 ANR 文件头部确认超时类型,再看主线程栈;结合同一时间段的 Perfetto trace 还原 等待链。不要只看栈顶,要看“谁持有锁、谁在等锁”。
常见误区
- “ANR 就是主线程慢”:主线程慢是表象,根因在锁/Binder/GC/I/O。
- “超时数值到处一样”:输入、广播、服务各有阈值。
- “看 ANR 文件就够”:还要 trace 还原同时性。
- “后台不会 ANR”:后台广播/服务超时会以不同阈值触发。
延伸问题
- 为什么后台广播超时阈值比前台长?
- 锁等待在 ANR 文件里如何体现?
- 如何用 Perfetto 还原 ANR 前的 5 秒?
- 多用户或低内存场景下 ANR 触发有何差异?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
ActivityManagerService.java | appNotResponding() | ANR 入口 |
ActivityManagerConstants.java | 超时常量 | 阈值定义 |
InputDispatcher.cpp | 输入超时 | 输入 ANR |
/data/anr/ | ANR 文件 | 定位证据 |
公共路径:frameworks/base/services/core/java/com/android/server/am/ 与 frameworks/base/services/inputflinger/dispatcher/。行号以 r75 检索为准。
界面仍响应但呈现不连续时,转到 卡顿与帧时间线。