1. ANR基础与现象识别
1.1 ANR定义与核心机制
ANR(Application Not Responding,应用无响应)是Android系统内置的进程看护机制。当应用的主线程(UI线程)在指定阈值时间内未能完成输入事件分发、广播处理、服务启动或ContentProvider发布等操作时,系统会判定该应用已无响应,并向用户弹出强制关闭或等待的对话框。
ANR的本质是主线程阻塞超时。Android系统通过InputManager、ActivityManager、ServiceManager等多个系统组件协同监控主线程的响应状态。一旦超时阈值被触发,系统会立即采集当前进程的线程堆栈,写入/data/anr/traces.txt,并弹出ANR对话框。
核心结论:ANR不是崩溃,而是系统对主线程“失联”的保底保护。理解触发场景是排查的第一步。
1.2 现象识别:四大触发场景与用户现象
Android系统中ANR分为四种触发场景,每种场景对应不同的系统组件和超时阈值。以下是详细的触发场景对比表:
| 触发场景 | 系统组件 | 超时时间 | 日志关键字 | 典型主线程阻塞原因 |
|---|---|---|---|---|
| 输入事件超时 | Activity / View | 5s | Input dispatching timed out |
触摸事件/按键事件未在5s内分发完毕 |
| 广播超时 | BroadcastReceiver | 10s(前台) 60s(后台) |
Broadcast of intent timed out |
onReceive() 方法执行耗时 |
| 服务超时 | Service | 20s | Service timed out |
onCreate() / onStartCommand() 阻塞 |
| ContentProvider超时 | ContentProvider | 10s | ContentProvider timed out |
query() / insert() 等CRUD操作耗时 |
用户侧现象:无论哪种触发场景,用户看到的界面表现基本一致:
- 应用界面完全卡死,触摸无响应,点击按键无反馈。
- 系统弹出ANR对话框,标题为“应用无响应”,提供“关闭应用”和“等待”两个选项。
- 如果ANR发生在后台广播中,用户可能不会直接看到对话框,但系统会在日志中记录
am_anr事件。 - 在某些Android版本(如Android 14+)中,ANR对话框被替换为系统通知,但日志标记机制不变。
排查经验:如果用户反馈“点不动”“卡死了”,优先怀疑输入事件超时ANR;如果用户反馈“应用突然没反应然后闪退”,可能是广播或服务超时导致的ANR后系统强制杀进程。
1.3 数据采集:系统日志标记与获取方法
ANR发生后的第一时间,系统会在多个日志通道留下关键标记。排查人员需要从以下三个数据源采集信息:
(1)Event Log 中的 am_anr 事件
// 使用 adb logcat -b events 抓取
I/am_anr: [0,com.example.app,12345,Input dispatching timed out,
com.example.app/.MainActivity,10000,10001]
// 字段说明:PID、进程名、超时类型、前后台标志
(2)主日志中的 ANR 关键字
// 使用 adb logcat -v time | grep -E "ANR|anr" 抓取
01-15 14:30:00.000 W/ActivityManager: ANR in com.example.app
01-15 14:30:00.000 W/ActivityManager: Reason: Input dispatching timed out
01-15 14:30:00.000 W/ActivityManager: Load: 12.5 / 8.3 / 6.7
01-15 14:30:00.000 W/ActivityManager: CPU usage from 0ms to 5000ms:
01-15 14:30:00.000 W/ActivityManager: com.example.app: 4% user + 2% kernel
01-15 14:30:00.000 W/ActivityManager: system_server: 2% user + 1% kernel
(3)traces.txt 中的主线程堆栈
// 路径:/data/anr/traces.txt 或 /data/anr/anr_*
----- pid 12345 at 2024-01-15 14:30:00 -----
Cmd line: com.example.app
Build fingerprint: 'google/...'
ABI: 'arm64'
"main" prio=5 tid=1 Blocked
| group="main" sCount=1 dsCount=0 flags=1 obj=0x...
| sysTid=12345 nice=0 cgrp=default sched=0/0 handle=0x...
at com.example.app.MainActivity.onClick(MainActivity.java:45)
- waiting to lock <0x12345678> (a java.lang.Object)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8506)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(...)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:...)
数据采集命令速查表:
| 数据源 | 采集命令 | 说明 |
|---|---|---|
| Event Log | adb logcat -b events -v time | grep am_anr |
快速定位ANR发生时间 |
| Main Log | adb logcat -v time | grep -E "ANR|anr|timed out" |
查看ANR详细原因和CPU负载 |
| traces.txt | adb pull /data/anr/traces.txt ./ |
获取主线程及所有线程堆栈 |
| Bugreport | adb bugreport ./bugreport.zip |
全量系统诊断数据 |
关键提醒:traces.txt 是定位ANR根因的核心证据。必须在ANR发生后的5分钟内拉取,否则可能被后续ANR覆盖。生产环境建议集成自动抓取工具。
1.4 原因定位:排查路径图与判断规则
以下ANR排查路径图展示了从ANR发生到根因定位的完整链路。排查人员可以从“用户现象”或“系统日志标记”任一端切入,沿路径反向追溯触发场景。