Android里面的ANR机制进阶思考

508 阅读3分钟

在 Android 系统中,ANR(Application Not Responding)  是系统检测到应用主线程(UI 线程)长时间阻塞时触发的机制,目的是防止应用无响应影响用户体验。其核心原理基于 消息队列超时监控 和 系统服务状态检测。以下从 触发条件类型分析底层源码实现 到 调试策略 的深度解析:


一、ANR 的触发条件与类型

1. ANR 的三种核心类型

类型超时时间触发场景
Input Dispatch5 秒主线程未处理输入事件(如触摸、按键)。
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 触发链路

  1. 超时检测:系统服务(如 BroadcastQueue)检测到组件未及时响应。
  2. 发送信号:通过 ProcessRecord.appNotResponding() 进入 ANR 流程。
  3. 收集信息:Dump 主线程堆栈、CPU 使用率、进程状态。
  4. 弹出对话框:显示 "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、网络请求移至子线程(如 AsyncTaskKotlin 协程)。
  • 减少锁竞争:避免主线程与子线程竞争共享资源。

2. 组件生命周期优化

  • BroadcastReceiver:使用 goAsync() 或 JobIntentService 处理耗时逻辑。
  • Service:前台服务需显式通知,后台任务使用 WorkManager

3. 监控与预警

  • ANR WatchDog:通过子线程轮询主线程状态,提前预警。

    public class ANRWatchDog extends Thread {
        @Override
        public void run() {
            while (!isInterrupted()) {
                mUiHandler.post(mCheckRunnable);
                // 若超时未响应,触发回调
            }
        }
    }
    

六、总结

ANR 机制的本质是 系统对主线程响应能力的强制监控,其触发流程涉及:

  1. 超时检测:系统服务通过延迟消息监控组件状态。
  2. 信息收集:Dump 堆栈、CPU 使用率等数据。
  3. 用户提示:弹出对话框防止应用完全卡死。

通过分析 ActivityManagerServiceBroadcastQueue 和 ProcessRecord 的源码,开发者可深入理解 ANR 的触发逻辑,结合工具(Systrace、ANR 日志)定位阻塞点,从而优化应用性能,提升用户体验。