系统如何检测ANR
讲ANR调试,先得弄明白系统是怎么知道你卡了的。说白了,Android系统内部有一套监控机制,就像个后台小哨兵,盯着每个关键任务有没有在规定时间内完成。我刚开始接触ANR时,总以为是代码报错崩了,后来才发现——错了,ANR是超时,不是崩溃。
三种核心超时场景
Android系统主要监控三类场景:
- 输入事件超时:用户点了屏幕,5秒内没响应,系统就会触发ANR。
- 广播超时:前台广播10秒,后台广播60秒。嗯,广播处理不当,这是我踩坑最多的地方。
- 服务超时:前台服务20秒,后台服务200秒。这里要注意,不是你服务跑满了200秒才报,是从你收到
onStartCommand开始计时。
检测流程:从超时到生成trace
整个检测流程分四步,我画了一张图帮你理清逻辑:
关键组件:谁在背后做这件事?
系统层有几个关键角色参与检测:
| 组件 | 角色 | 说明 |
|---|---|---|
InputDispatcher |
输入事件分发器 | 用户点击屏幕后,它等待5秒,没响应就触发ANR |
BroadcastQueue |
广播队列管理 | 对前台广播计时10秒,后台广播60秒 |
ActiveServices |
服务调度器 | 跟踪服务超时,前台20秒,后台200秒 |
AnrHelper |
ANR辅助类 | 将超时信息包装,准备写入/traces |
ProcessCpuTracker |
CPU监控 | 采集各线程CPU使用情况,辅助判断是否真卡死 |
我个人习惯先查BroadcastQueue的日志,因为广播ANR出现频率最高。我记得有一次线上崩溃,就是后台广播里做了大量IO操作,活生生拖了50多秒。
检测时序:精确到毫秒
系统是怎么精确计时的?每个ANR监测点都挂了一个Handler消息。
InputDispatcher在dispatch事件时,postDelayed一个5秒的Runnable。- 如果事件处理完,就移除这个Runnable。
- 如果Runnable被执行了——恭喜,触发ANR。
看一段关键源码逻辑简化版:
// 伪代码:InputDispatcher检测逻辑
void dispatchEvent(InputEvent event) {
// 记录本次事件,并设置超时
mPendingEvent = event;
mHandler.postDelayed(mAnrRunnable, TIMEOUT_INPUT); // 5秒
// 交给应用处理
deliverToApp(event);
}
void finishedEvent(InputEvent event) {
mPendingEvent = null;
mHandler.removeCallbacks(mAnrRunnable); // 正常完成,移除超时
}
经验技巧: 看/data/anr/traces.txt时,重点关注"main" prio=5 tid=1的线程状态。如果显示BLOCKED或WAITING,问题往往就在那里。我曾经通过这个字段,一把揪出某个锁等待导致的ANR。
ANR触发后:系统会做什么?
一旦超时确定,系统执行以下操作:
- 写入traces.txt: 在
/data/anr/目录生成堆栈信息。每个线程的调用栈都在这。 - 弹出ANR对话框: 前台应用会有个"应用无响应"的弹窗,用户可以选择等待或关闭。
- 输出logcat: 可以看到
ANR in com.example.app这样的日志。 - 可能触发降级: 如果系统负载过高,ANR还可能引起SIGQUIT信号,直接dump所有线程。
避坑指南: 我曾经发现一台测试机频繁ANR但/data/anr/traces.txt为空。后来才搞清楚——是系统存储空间不足,写trace文件失败了。所以排查时,记得先确认存储是否正常。
你以为的超时,可能不是真的超时
系统还做了个聪明的判断:CPU是否真的在忙活?
如果主线程被BLOCKED或者WAITING,CPU实际是空闲的,系统可以判定这是真ANR。但如果主线程在跑一个死循环,CPU占满了,系统也需要等待超时时间到达。你想想看,这两种情况的trace文件内容完全不一样。
- CPU占用高且主线程正执行: 堆栈指向你的业务代码行。
- CPU占用低且主线程在等锁: 堆栈会看到
waiting to lock或parking等信息。
小结:检测机制的两条腿
系统检测ANR靠两条腿走路:
一条是超时计时器: 精确到毫秒的handler消息机制。
另一条是CPU采样: 通过ProcessCpuTracker每隔一段时间采集各线程CPU使用率,辅助判断是否真的卡死。
这两条腿配合,几乎不会漏报。但偶尔也会误报——比如系统负载极高时,输入事件5秒处理完但被线程调度延迟了。嗯,这种场景比较少见,遇到了再去深入分析。