ANR 定义与触发场景:主线程阻塞、无响应的阈值、系统日志特征

1.1 什么是 ANR

Application Not Responding(ANR)是 Android 系统对应用主线程(UI 线程)长时间未完成事件处理或未响应输入事件时,主动触发的保护机制。当用户操作(如点击、触摸、按键)无法在规定时间内被主线程处理完毕,系统会弹出一个“应用无响应”对话框,用户可选择“等待”或“关闭应用”。ANR 的本质是主线程阻塞——任何耗时操作(网络请求、磁盘 I/O、复杂计算、锁竞争等)直接放在主线程执行,都可能导致 ANR。

核心原则:Android 主线程负责所有 UI 绘制、事件分发、广播接收、Service 生命周期回调,任何阻塞超过阈值都会触发 ANR。

1.2 触发场景与阈值

不同组件有不同的阈值时间,系统从收到事件/请求开始计时,若主线程在指定时间内未完成处理,则判定 ANR。常见触发场景及对应阈值如下表:

组件 / 事件类型阈值(超时时间)触发条件描述
Activity 输入事件5 秒系统发送了触摸/按键事件,主线程 5s 内未完成 dispatch 和 onUserInteraction
Service 启动 / 绑定20 秒Service 的 onCreate / onStartCommand / onBind 未在 20s 内返回
ContentProvider 超时10 秒ContentProvider 的 onCreate 或 query / insert / update / delete 长时间未返回
BroadcastReceiver onReceive(同步)10 秒主线程 BroadcastReceiver 的 onReceive 执行超过 10s(前台广播);后台广播阈值更短(约 3-5s)
Input 事件堆积5 秒输入队列中某个事件超过 5s 未被处理(即使前一个事件未完成)
💡 常见误区:ANR 并不仅发生在用户可见的 Activity 中。后台 Service、ContentProvider、BroadcastReceiver 同样会触发 ANR,且阈值更短。

1.3 系统日志特征

当 ANR 发生时,系统会将详细的堆栈信息写入 /data/anr/traces.txt(Android 10 之后会分文件存储),同时通过 logcat 输出关键日志。识别 ANR 的关键日志特征包括:

  • Logcat 中出现的标记:ANR in 加上应用包名,例如:
I/ActivityManager( 1234): ANR in com.example.myapp (com.example.myapp/.ui.MainActivity)
I/ActivityManager( 1234): Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 5000.0ms ago.)
I/ActivityManager( 1234): Load: 2.34 / 1.98 / 1.67
I/ActivityManager( 1234): CPU usage from 0ms to 6193ms later (2023-08-15 10:30:00.123):
I/ActivityManager( 1234):   7% 1234/system_server: 2% user + 1% kernel / faults: 123 minor
I/ActivityManager( 1234):   92% 5678/com.example.myapp: 80% user + 12% kernel / faults: 456 minor 3 major
  • traces.txt 文件内容:主线程以及所有存活线程的堆栈信息,主线程通常堆栈卡在某个锁、sleep、I/O 函数上。示例:
----- pid 5678 at 2023-08-15 10:30:06.123 -----
Cmd line: com.example.myapp
"main" prio=5 tid=1 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x72b00000 self=0x7c800000
  | sysTid=5678 nice=0 cgrp=default sched=0/0 handle=0x7c800000
  | state=S schedstat=( 123456789 1000000 2345 ) utm=123 stm=45 core=0 HZ=100
  | stack=0x7c600000-0x7c620000 stackSize=8192KB
  | held mutexes=
  at java.lang.Thread.sleep(Native Method)
  at com.example.myapp.MainActivity.onClick(MainActivity.java:45)
  ... (frame省略)
⚠️ 关键排查点:traces.txt 中主线程的 state 字段常见值为 Blocked(等待锁)、Sleeping(主动睡眠)、Runnable(长时间 CPU 计算)。如果主线程持续 Runnable 状态且长时间未 submit 新事件,通常是由于死循环或巨大计算量导致。

1.4 ANR 触发流程 SVG

ANR 触发与检测流程 ANR 触发与检测流程 用户输入事件 / 系统广播 主线程(主 Looper)处理 是否在规定阈值内完成? 正常返回 系统判定 ANR 输出 logs / 生成 /data/anr/traces.txt 应用无响应对话框弹出 说明:灰色箭头表示流程方向;绿色节点“正常返回”表示处理完成,否则进入红色 ANR 流程

1.5 实际排查调试方法

当你需要确认是否发生 ANR 时,按以下步骤确认:

  1. 实时查看 logcat:过滤 ANR in 或 ActivityManager 级别为 I/W。
  2. 获取 traces.txt:通过 adb 拉取 /data/anr/traces.txt(需要 root 或 debug 版)。
  3. 查看主线程堆栈:在 traces 中查找以 "main" prio=5 tid=1 开头的线程块,定位卡住的具体方法。
  4. 分析嵌套锁:如果主线程状态为 Blocked,查看它正在等待哪个锁,并寻找持锁线程。
  5. 检查 CPU 负载:结合 metrics 看是否系统资源不够,CPU 使用率过高会导致主线程调度延迟。