Android ANR 触发原理详解
一、ANR 概述
┌─────────────────────────────────────────────────────────────────────┐
│ ANR (Application Not Responding) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 核心原理: 【埋炸弹】 → 【拆炸弹】 / 【炸弹爆炸】 │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 系统发起请求 App 处理中 结果判定 │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 埋炸弹 │────────► │ 处理中 │────────► │ 拆炸弹 │ │ │
│ │ │设置超时 │ │ │ 及时完成 │ 移除超时│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │ │ │
│ │ │ │ 超时未完成 │ │
│ │ │ ▼ │ │
│ │ │ ┌─────────┐ │ │
│ │ └─────────────►│ 爆炸! │ │ │
│ │ │ ANR触发 │ │ │
│ │ └─────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
二、ANR 类型与超时时间
| ANR 类型 | 超时时间 | 触发场景 |
|---|---|---|
| Input ANR | 5 秒 | 触摸、按键事件无响应 |
| Broadcast ANR | 前台 10 秒 / 后台 60 秒 | 广播接收器处理超时 |
| Service ANR | 前台 20 秒 / 后台 200 秒 | Service 生命周期方法超时 |
| ContentProvider ANR | 10 秒 | Provider 发布超时 |
三、Input ANR 原理
3.1 整体架构
┌─────────────────────────────────────────────────────────────────────┐
│ Input ANR 检测架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ system_server 进程 │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ InputReader InputDispatcher │ │
│ │ (读取输入事件) (分发输入事件) │ │
│ │ │ │ │ │
│ │ │ │ ┌─────────────────────┐ │ │
│ │ └──────────────────────► │ │ ANR 超时检测 │ │ │
│ │ │ │ │ │ │
│ │ │ │ - 记录发送时间 │ │ │
│ │ │ │ - 等待 App 回复 │ │ │
│ │ │ │ - 超时则触发 ANR │ │ │
│ │ │ └─────────────────────┘ │ │
│ │ │ │ │ │
│ └─────────────────────────────────┼───────────┼───────────────┘ │
│ │ │ │
│ Socket 通信 │ │ 超时通知 │
│ ▼ ▼ │
│ ┌─────────────────────────┐ │
│ │ App 进程 │ │
│ │ │ │
│ │ UI Thread │ │
│ │ 处理 Input 事件 │ │
│ │ 返回 "finished" │ │
│ │ │ │
│ └─────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
3.2 InputDispatcher 检测机制
// frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
// ANR 超时常量
constexpr std::chrono::nanoseconds DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5s;
// 分发事件时开始计时
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
for (const InputTarget& inputTarget : inputTargets) {
sp<Connection> connection = getConnectionLocked(inputTarget.inputChannel);
// 发送事件给 App
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
// ════════════════════════════════════════════════════════
// 【埋炸弹】记录等待开始时间
// ════════════════════════════════════════════════════════
connection->waitStartTime = currentTime;
}
}
// 检查是否 ANR
void InputDispatcher::checkWindowAnrStateLocked(const sp<Connection>& connection) {
nsecs_t currentTime = now();
// 计算等待时间
nsecs_t waitDuration = currentTime - connection->waitStartTime;
// ════════════════════════════════════════════════════════
// 超过 5 秒触发 ANR
// ════════════════════════════════════════════════════════
if (waitDuration > DEFAULT_INPUT_DISPATCHING_TIMEOUT) {
onAnrLocked(connection);
}
}
// App 处理完成后回调
void InputDispatcher::finishDispatchCycleLocked(nsecs_t finishTime,
const sp<Connection>& connection,
uint32_t seq, bool handled) {
// ════════════════════════════════════════════════════════
// 【拆炸弹】App 及时响应,清除等待状态
// ════════════════════════════════════════════════════════
connection->waitStartTime = LLONG_MAX;
}
3.3 Input ANR 流程图
┌─────────────────────────────────────────────────────────────────────┐
│ Input ANR 触发流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 时间线 ─────────────────────────────────────────────────────────► │
│ │ │
│ │ │
│ T0 │ 用户触摸屏幕 │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ │
│ │ InputReader │ 读取触摸事件 │
│ │ 从 /dev/input/ │ │
│ └──────────┬──────────┘ │
│ │ │
│ T1 ▼ │
│ ┌─────────────────────┐ │
│ │ InputDispatcher │ │
│ │ │ │
│ │ 1. 找到目标窗口 │ │
│ │ 2. 发送事件 │─────────────────────┐ │
│ │ 3. 记录发送时间 │ 【埋炸弹】 │ │
│ │ waitStartTime │ │ │
│ └──────────┬──────────┘ │ │
│ │ │ │
│ │ 等待回复... ▼ │
│ │ ┌─────────────────────┐ │
│ │ │ App UI Thread │ │
│ │ │ │ │
│ │ │ 正常: 处理事件 │ │
│ │ │ 异常: 阻塞中... │ │
│ │ │ (Binder调用) │ │
│ │ │ (死循环) │ │
│ │ │ (锁等待) │ │
│ │ └─────────────────────┘ │
│ │ │ │
│ ┌───────┴───────┐ │ │
│ │ │ │ │
│ 正常情况 异常情况 │ │
│ │ │ │ │
│ ▼ ▼ │ │
│ T < 5s T > 5s │ │
│ │ │ │ │
│ ┌──┴──┐ ┌────┴────┐ │ │
│ │收到 │ │未收到 │ │ │
│ │finish│ │finish │ │ │
│ └──┬──┘ └────┬────┘ │ │
│ │ │ │ │
│ ▼ ▼ │ │
│ 【拆炸弹】 【爆炸!】 │ │
│ 清除等待 触发ANR │ │
│ │ │ │
│ ▼ │ │
│ ┌─────────────────────┐ │ │
│ │ 通知 AMS │ │ │
│ │ 收集 ANR 信息 │ │ │
│ │ 弹出 ANR 对话框 │ │ │
│ └─────────────────────┘ │ │
│ │
└─────────────────────────────────────────────────────────────────────┘
四、Broadcast ANR 原理
4.1 广播处理流程
// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public final class BroadcastQueue {
// 超时时间常量
static final int BROADCAST_FG_TIMEOUT = 10 * 1000; // 前台广播 10秒
static final int BROADCAST_BG_TIMEOUT = 60 * 1000; // 后台广播 60秒
// 处理有序广播
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
// 获取下一个待处理的广播
r = mDispatcher.getNextBroadcastLocked(now);
if (r != null) {
// ════════════════════════════════════════════════════
// 【埋炸弹】设置超时消息
// ════════════════════════════════════════════════════
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
setBroadcastTimeoutLocked(timeoutTime);
// 发送广播给接收者
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, false, false, r.userId);
}
}
// 设置超时
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (!mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
// 发送延迟消息
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage = true;
}
}
// 广播处理完成
public void finishReceiverLocked(BroadcastRecord r, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort,
boolean waitForServices) {
// ════════════════════════════════════════════════════
// 【拆炸弹】取消超时消息
// ════════════════════════════════════════════════════
cancelBroadcastTimeoutLocked();
// 处理下一个广播
processNextBroadcastLocked(false, false);
}
// 超时处理
final void broadcastTimeoutLocked(boolean fromMsg) {
// ════════════════════════════════════════════════════
// 【爆炸】超时触发
// ════════════════════════════════════════════════════
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
if (r != null && r.receiverTime > 0) {
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
if (timeoutTime > now) {
// 还没超时,重新设置
setBroadcastTimeoutLocked(timeoutTime);
return;
}
}
// 真正超时,触发 ANR
if (r != null) {
mService.mAnrHelper.appNotResponding(r.curApp,
"Broadcast of " + r.intent.toString());
}
}
}
4.2 Broadcast ANR 时序图
┌─────────────────────────────────────────────────────────────────────┐
│ Broadcast ANR 触发流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ AMS (BroadcastQueue) App (BroadcastReceiver) │
│ │ │ │
│ │ │ │
│ T0 │ processNextBroadcast() │ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ 1. 获取下一个广播接收者 │ │ │
│ │ │ 2. 【埋炸弹】 │ │ │
│ │ │ sendMessageAtTime( │ │ │
│ │ │ BROADCAST_TIMEOUT_MSG, │ │ │
│ │ │ now + 10s) │ │ │
│ │ │ 3. 发送广播 │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ │ │
│ │ ─────────── 广播Intent ──────────────► │ │
│ │ │ │
│ │ │ onReceive() { │
│ │ │ // 处理广播 │
│ │ 等待完成... │ // 如果耗时操作 │
│ │ │ // 会导致超时 │
│ │ │ } │
│ │ │ │
│ ┌─────┴─────────────────────────────┐ │ │
│ │ │ │ │
│ │ 情况A: 10秒内完成 │ │ │
│ │ │ │ │
│ │ ◄────────── finish ──────────────│─────────│ │
│ │ │ │ │
│ │ finishReceiverLocked() │ │ │
│ │ 【拆炸弹】 │ │ │
│ │ cancelBroadcastTimeoutLocked() │ │ │
│ │ │ │ │
│ └────────────────────────────────────┘ │ │
│ │ │
│ ┌─────────────────────────────────────────────┐│ │
│ │ ││ │
│ │ 情况B: 超过10秒 ││ │
│ │ ││ (还在处理...) │
│ │ Handler 收到 BROADCAST_TIMEOUT_MSG ││ │
│ │ ││ │
│ │ broadcastTimeoutLocked() ││ │
│ │ 【爆炸!】 ││ │
│ │ appNotResponding() ││ │
│ │ ││ │
│ └─────────────────────────────────────────────┘│ │
│ │ │
└─────────────────────────────────────────────────────────────────────┘
五、Service ANR 原理
5.1 Service 超时检测
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public final class ActiveServices {
// 超时时间常量
static final int SERVICE_TIMEOUT = 20 * 1000; // 前台服务 20秒
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; // 后台 200秒
// 启动服务时
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
boolean execInFg) throws RemoteException {
// ════════════════════════════════════════════════════
// 【埋炸弹】设置超时
// ════════════════════════════════════════════════════
bumpServiceExecutingLocked(r, execInFg, "create");
// 调用 App 的 onCreate
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
}
private void bumpServiceExecutingLocked(ServiceRecord r, boolean fg,
String why) {
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executingStart = now;
// 计算超时时间
long timeout = fg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT;
// 发送延迟消息
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = r.app;
mAm.mHandler.sendMessageDelayed(msg, timeout);
r.app.executingServices.add(r);
}
r.executeNesting++;
}
// 服务方法执行完成
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
r.executeNesting--;
if (r.executeNesting == 0) {
// ════════════════════════════════════════════════════
// 【拆炸弹】取消超时消息
// ════════════════════════════════════════════════════
if (r.app != null) {
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
r.app.executingServices.remove(r);
}
}
}
// 超时处理
void serviceTimeout(ProcessRecord proc) {
// ════════════════════════════════════════════════════
// 【爆炸】触发 ANR
// ════════════════════════════════════════════════════
synchronized(mAm) {
if (proc.executingServices.size() == 0) {
return; // 已经处理完了
}
long now = SystemClock.uptimeMillis();
long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
// 检查是否真正超时
for (ServiceRecord sr : proc.executingServices) {
if (sr.executingStart < maxTime) {
// 真正超时,触发 ANR
mAm.mAnrHelper.appNotResponding(proc,
"executing service " + sr.shortInstanceName);
return;
}
}
}
}
}
5.2 Service 生命周期与 ANR 检测
┌─────────────────────────────────────────────────────────────────────┐
│ Service ANR 检测时机 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 以下 Service 生命周期方法都有超时检测: │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ onCreate() ──────► 超时 20/200 秒 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ onStartCommand() ──────► 超时 20/200 秒 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ onBind() ──────► 超时 20/200 秒 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ onUnbind() ──────► 超时 20/200 秒 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ onDestroy() ──────► 超时 20/200 秒 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 注意: 前台服务 20秒, 后台服务 200秒 │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Service ANR 时序图 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ AMS App │
│ │ │ │
│ │ realStartServiceLocked() │ │
│ │ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ bumpServiceExecutingLocked() │ │ │
│ │ │ 【埋炸弹】 │ │ │
│ │ │ sendMessageDelayed( │ │ │
│ │ │ SERVICE_TIMEOUT_MSG, 20s) │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ │ │
│ │ ─── scheduleCreateService() ──────► │ │
│ │ │ ActivityThread │
│ │ │ handleCreateService() │
│ │ │ │ │
│ │ 等待... │ ▼ │
│ │ │ service.onCreate() │
│ │ │ │ │
│ │ │ │ 【如果耗时】 │
│ │ │ │ 网络请求 │
│ │ │ │ 数据库操作 │
│ │ │ │ 复杂计算 │
│ │ │ │ │
│ │ │ ▼ │
│ │ ◄── serviceDoneExecutingLocked ──── │ (完成) │
│ │ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ 【拆炸弹】 │ │ │
│ │ │ removeMessages( │ │ │
│ │ │ SERVICE_TIMEOUT_MSG) │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ │ │
│ ──────────────── OR ────────────────── │
│ │ │ │
│ │ Handler 收到 SERVICE_TIMEOUT_MSG │ │
│ │ ┌──────────────────────────────┐ │ (还在处理...) │
│ │ │ serviceTimeout() │ │ │
│ │ │ 【爆炸!】 │ │ │
│ │ │ appNotResponding() │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ │
└─────────────────────────────────────────────────────────────────────┘
六、ContentProvider ANR 原理
// frameworks/base/services/core/java/com/android/server/am/ContentProviderHelper.java
final class ContentProviderHelper {
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10 * 1000; // 10秒
// 等待 Provider 发布
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage,
String callingTag, boolean stable, int userId) {
// 如果 Provider 还没启动,需要等待
synchronized (cpr) {
while (cpr.provider == null) {
// ════════════════════════════════════════════════════
// 【等待 Provider 发布,超时 10 秒】
// ════════════════════════════════════════════════════
long timeout = SystemClock.uptimeMillis() +
CONTENT_PROVIDER_PUBLISH_TIMEOUT;
try {
cpr.wait(CONTENT_PROVIDER_PUBLISH_TIMEOUT);
} catch (InterruptedException ex) {
}
if (cpr.provider == null &&
SystemClock.uptimeMillis() >= timeout) {
// 超时,触发 ANR
return null;
}
}
}
return cpr.newHolder(conn, false);
}
// App 发布 Provider
void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
synchronized (cpr) {
cpr.provider = src.provider;
cpr.notifyAll(); // 唤醒等待的线程
}
}
}
七、ANR 信息收集与处理
7.1 ANR 处理流程
// frameworks/base/services/core/java/com/android/server/am/AnrHelper.java
class AnrHelper {
void appNotResponding(ProcessRecord anrProcess, String annotation) {
// 在单独线程中处理,避免阻塞
AnrRecord anrRecord = new AnrRecord(anrProcess, annotation);
mAnrRecords.add(anrRecord);
// 启动处理线程
startAnrConsumerIfNeeded();
}
private void processAnrRecord(AnrRecord record) {
// 收集 ANR 信息
ProcessRecord proc = record.mApp;
// 1. Dump 主要进程的堆栈
File tracesFile = ActivityManagerService.dumpStackTraces(
firstPids, nativePids, extraPids, ...);
// 2. 收集 CPU 使用信息
updateCpuStatsNow();
// 3. 写入 ANR 日志
writeAnrToEventLog(proc, annotation);
// 4. 显示 ANR 对话框 (或直接杀进程)
if (showBackground || isInterestingForBackgroundTraces(proc)) {
Message msg = mHandler.obtainMessage(SHOW_NOT_RESPONDING_UI_MSG);
msg.obj = new AppNotRespondingDialog.Data(proc, annotation, ...);
mHandler.sendMessage(msg);
} else {
// 后台进程直接杀死
mService.mAppErrors.handleAppNotRespondingProcess(proc);
}
}
}
7.2 ANR 信息收集内容
┌─────────────────────────────────────────────────────────────────────┐
│ ANR 信息收集内容 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ /data/anr/traces.txt (或 traces_*.txt) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. 进程信息 │ │
│ │ - 进程名、PID、UID │ │
│ │ - ANR 类型和原因 │ │
│ │ │ │
│ │ 2. 主线程堆栈 (Main Thread) │ │
│ │ - 线程状态 (Running/Sleeping/Blocked/Waiting) │ │
│ │ - 完整调用栈 │ │
│ │ - 锁信息 (held/waiting) │ │
│ │ │ │
│ │ 3. 其他线程堆栈 │ │
│ │ - Binder 线程 │ │
│ │ - 工作线程 │ │
│ │ - AsyncTask 线程 │ │
│ │ │ │
│ │ 4. CPU 使用情况 │ │
│ │ - 各进程 CPU 占用 │ │
│ │ - iowait 情况 │ │
│ │ │ │
│ │ 5. 内存信息 │ │
│ │ - 进程内存使用 │ │
│ │ - 系统内存状态 │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ 其他日志: │
│ - /data/system/dropbox/ (压缩的ANR信息) │
│ - logcat 中的 ANR 信息 │
│ │
└─────────────────────────────────────────────────────────────────────┘
八、完整 ANR 触发时序总结
┌─────────────────────────────────────────────────────────────────────┐
│ ANR 完整触发时序 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ System Server App │
│ │ │ │
│ │ │ │
│ ═════╪════════════════════════════════════════════╪═══════════ │
│ 阶段1│【埋炸弹】 │ │
│ ═════╪════════════════════════════════════════════╪═══════════ │
│ │ │ │
│ │ 发起请求 (Input/Broadcast/Service...) │ │
│ │────────────────────────────────────────────► │
│ │ │ │
│ │ 设置超时定时器 │ │
│ │ Handler.sendMessageDelayed() │ │
│ │ 或 记录等待开始时间 │ │
│ │ │ │
│ │ │ │
│ ═════╪════════════════════════════════════════════╪═══════════ │
│ 阶段2│【处理中】 │ │
│ ═════╪════════════════════════════════════════════╪═══════════ │
│ │ │ │
│ │ │ 执行任务 │
│ │ │ (可能阻塞) │
│ │ 等待回复... │ │ │
│ │ │ │ │
│ │ │ │ │
│ ═════╪════════════════════════════════════════════╪════╪══════ │
│ 阶段3│【结果判定】 │ │ │
│ ═════╪════════════════════════════════════════════╪════╪══════ │
│ │ │ │ │
│ ┌───┴────────────────────────────────────────────┴────┴───┐ │
│ │ │ │
│ │ 路径A: 及时完成 路径B: 超时 │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ 收到完成回调 定时器触发 │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ 【拆炸弹】 【爆炸!】 │ │
│ │ 取消定时器 ANR 触发 │ │
│ │ 正常继续 │ │ │
│ │ ▼ │ │
│ │ 收集信息: │ │
│ │ - dump traces │ │
│ │ - CPU 使用 │ │
│ │ - 内存状态 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 显示 ANR 对话框 │ │
│ │ 或杀死进程 │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
九、各类 ANR 对比总结
┌─────────────────────────────────────────────────────────────────────┐
│ ANR 类型对比 │
├────────────┬─────────────┬────────────────┬────────────────────────┤
│ 类型 │ 超时时间 │ 检测位置 │ 触发条件 │
├────────────┼─────────────┼────────────────┼────────────────────────┤
│ │ │ │ │
│ Input │ 5 秒 │ InputDispatcher│ Input事件未及时 │
│ ANR │ │ (native层) │ 返回 "finished" │
│ │ │ │ │
├────────────┼─────────────┼────────────────┼────────────────────────┤
│ │ 前台 10秒 │ │ │
│ Broadcast │ │ BroadcastQueue │ onReceive() 未及时 │
│ ANR │ 后台 60秒 │ (Java层) │ 完成 │
│ │ │ │ │
├────────────┼─────────────┼────────────────┼────────────────────────┤
│ │ 前台 20秒 │ │ │
│ Service │ │ ActiveServices │ 生命周期方法未及时 │
│ ANR │ 后台 200秒 │ (Java层) │ 完成 │
│ │ │ │ │
├────────────┼─────────────┼────────────────┼────────────────────────┤
│ │ │ ContentProvider│ │
│ Provider │ 10 秒 │ Helper │ Provider 发布超时 │
│ ANR │ │ (Java层) │ │
│ │ │ │ │
└────────────┴─────────────┴────────────────┴────────────────────────┘
十、关键要点
┌─────────────────────────────────────────────────────────────────────┐
│ 核心要点 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. ANR 本质是【超时检测机制】 │
│ - 系统发起请求时设置超时定时器 (埋炸弹) │
│ - App 及时完成则取消定时器 (拆炸弹) │
│ - 超时未完成则触发 ANR (爆炸) │
│ │
│ 2. 检测发生在【系统侧】,不是 App 侧 │
│ - InputDispatcher 检测 Input ANR │
│ - AMS 检测 Broadcast/Service/Provider ANR │
│ │
│ 3. 【主线程阻塞】是根本原因 │
│ - Binder 同步调用 │
│ - 锁等待 (synchronized/Lock) │
│ - 死循环或复杂计算 │
│ - IO 操作 (网络/数据库/文件) │
│ │
│ 4. 预防措施 │
│ - 主线程只做 UI 相关轻量操作 │
│ - 耗时操作放到工作线程 │
│ - 避免主线程锁竞争 │
│ - 使用 StrictMode 检测 │
│ │
└─────────────────────────────────────────────────────────────────────┘