Android ANR 源码解析

引言

ANR(Application Not Responding)是指在 Android 应用中,当主线程在执行某个耗时操作时,无法及时响应用户的交互事件,导致应用无响应的情况。ANR 可能会给用户带来不好的体验,因此解决 ANR 问题是 Android 开发过程中的重要任务之一。本文将深入分析 Android 系统中 ANR 的机制以及源码实现。

ANR 机制

在 Android 系统中,ANR 是由系统提供的一种机制,用于检测应用是否出现无响应的情况,并根据一定的策略来处理。当系统检测到应用发生 ANR 时,会弹出一个 ANR 对话框,提示用户当前应用无响应,并提供选择是否终止应用的选项。

ANR 检测原理

Android 系统通过监控主线程的消息队列来实现 ANR 检测。主线程的消息队列使用了 Looper 类来管理,主线程通过调用 Looper.loop() 方法来进入消息循环。当主线程在执行某个耗时操作时,无法及时处理消息队列中的消息,就会触发 ANR 检测。

ANR 检测流程

下面是 ANR 检测的整体流程:

sequenceDiagram
    participant System as Android系统
    participant App as 应用程序
    participant Looper as 主线程Looper

    System ->> App: 发送检测消息
    App ->> Looper: 调用Looper.loop()
    Looper -->> App: 循环处理消息
    App -->> System: 响应消息
    System ->> App: 计算响应时间
    App ->> System: 返回响应时间
    System ->> App: 检查响应时间
    App ->> System: 返回结果
    System ->> App: 弹出ANR对话框

上述流程中,Android 系统通过发送一个检测消息给应用程序,然后应用程序调用 Looper.loop() 方法进入消息循环,主线程会循环处理消息。在主线程处理消息的过程中,系统会计算响应时间并检查是否超过了一定的阈值。如果超过了阈值,系统会弹出 ANR 对话框。

ANR 检测的实现

ANR 检测的具体实现涉及到两个关键类:ActivityManagerServiceActivityThread

ActivityManagerService

ActivityManagerService 类是 Android 系统中的一个重要服务,负责管理应用程序的生命周期、任务栈以及进程通信等。在 ANR 检测中,ActivityManagerService 类负责发送检测消息并处理 ANR 检测的结果。

ActivityThread

ActivityThread 类是应用程序的入口类,负责创建和管理应用程序的主线程。在 ANR 检测中,ActivityThread 类主要负责消息循环的处理。

下面是 ActivityThread 类中与 ANR 检测相关的代码片段:

// ActivityThread.java
private void main(String[] args) {
    ...
    Looper.prepareMainLooper();
    ...
    Looper.loop();
    ...
}

private static void loop() {
    ...
    for (;;) {
        Message msg = queue.next();
        if (msg == null) {
            // No message available.
            // Check if we need to quit.
            if (quitAllowed) {
                return;
            }
            continue;
        }

        long now = SystemClock.uptimeMillis();
        long nextPollTimeoutMillis = msg.nextPollTimeoutMillis;
        if (nextPollTimeoutMillis == 0) {
            msg.target.dispatchMessage(msg);
        } else if (nextPollTimeoutMillis > now) {
            ...
        } else {
            ...
            dispatchMessage(msg);
            ...
        }

        ...
    }
}

private void dispatchMessage(Message msg) {
    ...
    if (msg.callback != null) {
        // Handle callback message.
        msg.callback.run();
    } else {
        // Handle normal message.
        if (msg.target != null) {
            msg.target.dispatchMessage(msg);
        } else {
            ...
        }
    }
    ...
}