一、ANR的触发条件与类型
ANR(Application Not Responding)是 Android 系统为保障用户体验而设计的机制,它在应用主线程长时间阻塞时触发。
| 类型 | 超时时间 | 触发场景 |
|---|---|---|
| 输入事件 | 5 秒 | 主线程未处理输入事件(如点击、按键)。 |
| 广播接收器 | 10 秒 | BroadcastReceiver.onReceive() 未及时完成。 |
| 服务 | 20 秒 | Service 的生命周期方法(如 onStartCommand())未及时返回。 |
二、ANR的底层监控机制
ANR 的监控是一个跨进程的协作过程,由 system_server 进程中的核心服务完成。
1. 系统服务超时监控
InputDispatcher:在system_server进程中,InputDispatcher会等待应用进程在 5 秒内处理输入事件。如果超时,它会通知ActivityManagerService(AMS)。BroadcastQueue:AMS内部的BroadcastQueue会为每个广播设置一个超时定时器。如果onReceive()方法在超时时间内没有完成,BroadcastQueue会触发 ANR。ActiveServices:AMS内部的ActiveServices会为每个Service的生命周期方法设置一个超时定时器。
2. system_server 中的 ANR Watchdog
- Android 系统内置一个 ANR Watchdog。它是一个运行在
system_server进程中的线程,会定期检查AMS的主线程是否被阻塞。如果system_server的主线程被阻塞,Watchdog 会触发 ANR,这会直接导致系统重启。
三、ANR的触发流程与诊断
当系统检测到超时后,会执行一个标准的 ANR 流程,并生成日志文件供开发者诊断。
1. 触发链路
InputDispatcher或BroadcastQueue检测到超时,通知ActivityManagerService。AMS在其主线程中启动 ANR 流程,调用ProcessRecord.appNotResponding()。appNotResponding()方法会向目标应用进程发送SIGQUIT信号。
2. 堆栈信息收集
- 收到
SIGQUIT信号后,应用进程的主线程和所有子线程会被强制挂起。 debuggerd服务会收集所有线程的堆栈信息,并将其写入/data/anr/traces.txt文件。AMS随后会记录 ANR 事件到EventLog,并显示“应用无响应”对话框。
3. ANR日志分析
traces.txt:这是分析 ANR 的核心文件。它包含了 ANR 发生时,所有线程的调用栈。开发者可以通过分析主线程的调用栈,找到导致阻塞的耗时操作。adb shell dumpsys:dumpsys activity anrs命令可以查看最近的 ANR 记录。
四、ANR的优化策略
1. 主线程优化
- 异步化:将所有耗时操作(如 I/O、网络请求、数据库查询)移至子线程。
- 减少锁竞争:避免在主线程中持有锁,防止主线程与子线程因锁竞争而阻塞。
2. 组件生命周期优化
BroadcastReceiver:在onReceive()中,避免执行耗时操作。对于耗时任务,应使用goAsync()或JobIntentService。Service:对于后台耗时任务,应使用WorkManager或JobScheduler。
结论:
ANR 机制的本质是系统对应用主线程响应能力的强制监控。其底层依赖于 ActivityManagerService 的超时检测和 Binder 线程池的调度。开发者需深入理解 ANR 的触发逻辑和诊断方法,才能有效避免 ANR,提升应用性能。