如果 Android 应用的界面(主)线程处于阻塞状态的时间过长,会触发“应用无响应”(ANR) 错误。如果应用位于前台,系统会向用户显示一个对话框,如图 1 所示。ANR 对话框会为用户提供强行退出应用的选项(摘自Google官方介绍ANR)。
图1 ANR对话框
笔者基于aosp android-11.0.0_r21的源码对ANR的机制进行剖析,以期彻底了解相关原理。
主要从三个方面解读:
-
系统显示ANR机制
-
系统触发ANR机制
-
分析ANR的方法
系统显示ANR机制
用户最直观看见的是如图1所示,发生ANR之后显示的对话框。
为了方便理解,本文从显示机制开始。
在Android11前的AOSP源码中,ANR自身dump相关log的耗时容易导致system_server发生WatchDog,从而影响开发者分析相关的异常信息。为了解决这个在Android 11上,Google增加了一个新的 AnrHelper.java
来协助处理ANR的相关请求,主要作用:
- 创建独立线程,不用担心当前Anr收集相关信息耗时影响当前的系统分析。
- 如果当前ANR记录的等待时间已经超过了1分钟,捕获log的时候,只dump当前进程的信息。
com.android.server.am.AnrHelper.AnrConsumerThread
/**
* The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
* records are handled.
*/
private class AnrConsumerThread extends Thread {
AnrConsumerThread() {
super("AnrConsumer");
}
private AnrRecord next() {
synchronized (mAnrRecords) {
return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
}
}
@Override
public void run() {
AnrRecord r;
while ((r = next()) != null) {
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
final long reportLatency = startTime - r.mTimestamp;
// b. 如果已经超过了一分钟,只dump自身应用的相关信息。
final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
r.appNotResponding(onlyDumpSelf);
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
+ (endTime - startTime) + "ms, latency " + reportLatency
+ (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
}
mRunning.set(false)