在 Android 系统中,ANR(Application Not Responding) 是系统检测到应用主线程(UI 线程)长时间阻塞时触发的机制,目的是防止应用无响应影响用户体验。其核心原理基于 消息队列超时监控 和 系统服务状态检测。以下从 触发条件、类型分析、底层源码实现 到 调试策略 的深度解析:
一、ANR 的触发条件与类型
1. ANR 的三种核心类型
类型 | 超时时间 | 触发场景 |
---|---|---|
Input Dispatch | 5 秒 | 主线程未处理输入事件(如触摸、按键)。 |
Broadcast Receiver | 前台广播 10 秒,后台广播 60 秒 | BroadcastReceiver.onReceive() 未及时完成(后台广播为 Android 8.0+ 行为)。 |
Service | 前台服务 20 秒,后台服务 200 秒 | Service 的生命周期方法(如 onStartCommand() )未及时返回。 |
注意:Android 12+ 引入了 ContentProvider ANR(发布 ContentProvider 超时 10 秒)。
二、ANR 的底层监控机制
1. 消息队列监控:MessageQueue
与 Looper
Android 主线程通过 Looper
循环处理消息队列(MessageQueue
),系统通过 埋点监控消息处理时间:
-
关键源码:
Looper.loop()
每次处理消息时记录时间差。// frameworks/base/core/java/android/os/Looper.java public static void loop() { for (;;) { Message msg = queue.next(); // 可能阻塞 final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); msg.target.dispatchMessage(msg); final long end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); // 若处理时间超过阈值,触发 ANR 检测 if (end - start > slowDispatchThresholdMs) { // 记录 ANR 日志 } } }
2. 系统服务超时调度
Android 系统服务(如 ActivityManagerService
)通过 延迟消息(Delayed Message) 监控组件状态:
-
Service 超时:
ActiveServices
调度延迟消息,若服务未及时启动则触发 ANR。// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java void serviceTimeout(ProcessRecord proc) { if (timeout) { mAm.mHandler.post(mAppNotResponding); // 触发 ANR } }
-
Broadcast 超时:
BroadcastQueue
监控BroadcastReceiver
的执行时间。// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java void processNextBroadcast(boolean fromMsg) { final long timeoutTime = SystemClock.uptimeMillis() + timeoutPeriod; setBroadcastTimeoutLocked(timeoutTime); // 执行 BroadcastReceiver.onReceive() }
三、ANR 触发流程与源码分析
1. ANR 触发链路
- 超时检测:系统服务(如
BroadcastQueue
)检测到组件未及时响应。 - 发送信号:通过
ProcessRecord.appNotResponding()
进入 ANR 流程。 - 收集信息:Dump 主线程堆栈、CPU 使用率、进程状态。
- 弹出对话框:显示 "Application Not Responding" 提示。
2. 核心源码解析
-
ProcessRecord.appNotResponding()
// frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java void appNotResponding(String activityShortComponentName, ...) { // 1. 收集堆栈信息 File tracesFile = ActivityManagerService.dumpStackTraces(pid, ...); // 2. 记录 ANR 日志到 EventLog EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info); // 3. 弹出 ANR 对话框 mService.mUiHandler.obtainMessage(SHOW_NOT_RESPONDING_UI_MSG, ...).sendToTarget(); }
-
ActivityManagerService.dumpStackTraces()
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java static File dumpStackTraces(int pid, ...) { // 发送 SIGQUIT 信号触发进程生成 traces Process.sendSignal(pid, Process.SIGNAL_QUIT); // 生成 traces.txt 文件(位于 /data/anr/) }
四、ANR 日志与调试
1. ANR 日志路径
- 系统日志:
/data/anr/traces.txt
(需 root 权限访问)。 - EventLog:通过
adb logcat -b events
查看am_anr
事件。
2. 关键日志字段
ANR in com.example.app (com.example.app/.MainActivity)
PID: 12345
Reason: Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED }
Load: 2.5 / 2.3 / 1.8
CPU usage from 0ms to 10000ms later:
5% 1234/system_server: 3% user + 2% kernel
3% 5678/com.example.app: 2% user + 1% kernel
...
3. 调试工具
- Systrace/Perfetto:分析主线程阻塞原因。
- StrictMode:检测主线程耗时操作(如磁盘 I/O、网络访问)。
五、ANR 的优化策略
1. 主线程优化
- 避免耗时操作:将 I/O、网络请求移至子线程(如
AsyncTask
、Kotlin 协程
)。 - 减少锁竞争:避免主线程与子线程竞争共享资源。
2. 组件生命周期优化
- BroadcastReceiver:使用
goAsync()
或JobIntentService
处理耗时逻辑。 - Service:前台服务需显式通知,后台任务使用
WorkManager
。
3. 监控与预警
-
ANR WatchDog:通过子线程轮询主线程状态,提前预警。
public class ANRWatchDog extends Thread { @Override public void run() { while (!isInterrupted()) { mUiHandler.post(mCheckRunnable); // 若超时未响应,触发回调 } } }
六、总结
ANR 机制的本质是 系统对主线程响应能力的强制监控,其触发流程涉及:
- 超时检测:系统服务通过延迟消息监控组件状态。
- 信息收集:Dump 堆栈、CPU 使用率等数据。
- 用户提示:弹出对话框防止应用完全卡死。
通过分析 ActivityManagerService
、BroadcastQueue
和 ProcessRecord
的源码,开发者可深入理解 ANR 的触发逻辑,结合工具(Systrace、ANR 日志)定位阻塞点,从而优化应用性能,提升用户体验。