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发生到根因定位的完整链路。排查人员可以从“用户现象”或“系统日志标记”任一端切入,沿路径反向追溯触发场景。

ANR排查路径图:从触发到定位 ANR 发生 应用无响应 输入事件超时 5s 无响应 广播超时 10s / 60s 服务超时 20s 未就绪 ContentProvider 10s 未发布 用户侧现象 ANR对话框 / 界面完全卡死 系统日志标记 event log / traces.txt 数据采集与定位 bugreport / traces / 堆栈分析 ← 上一章 📖 返回目录 下一章 →