0%

Android-ANR分析

概述

AMS 和 WMS 会检测App的响应时间,如果App在特定时间无法响应屏幕触摸或键盘输入时间,或者特定事件(生命周期等)没有处理完毕,就会出现 ANR(Application Not Responding)。

ANR 一般有以下几种类型:

  • KeyDispatchTimeout: input 事件在 5s 内没有处理完成, logcat 关键字: Input dispatching timed out
  • BroadcastTimeout: 前台广播 onReceiver 在 10S 内没有处理完成,后台广播 onReceiver 在 60s 内没有处理完成, logcat 关键字: Timeout of broadcast BroadcastRecord
  • ServiceTimeout: 前台服务 onCreate, onStart, onBind 等生命周期在20s内没有处理完成,后台服务 onCreate, onStart, onBind 等生命周期在 200s 内没有处理完成, logcat 关键字: Timeout executing service
  • ContentProviderTimeout: ContentProvider 在 10s 内没有处理完成, logcat 关键字: timeout publishing content providers

案例分析

发生 ANR 后在日志中搜索关键字 ANR 可以看到如下日志:

1
2
3
4
2021-03-12 19:52:42.224 2092-2171/? E/ActivityManager: ANR in com.hearing.demo (com.hearing.demo/.MainActivity)
PID: 14354
Reason: Input dispatching timed out (com.hearing.demo/com.hearing.demo.MainActivity, Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 8. Wait queue head age: 9363.1ms.)
Load: 2.42 / 2.41 / 2.16

从上面可以看到发生 ANR 的时间,进程及 ANR 类型,由此可以根据进程过滤一下日志,然后由于该类型是 KeyDispatchTimeout, 所以可以重点看一下 5s 前有没有关键信息。

最关键的解决办法是从 /data/anr/ 下 pull 出 anr 相关的日志文件,里面有 ANR 发生的堆栈信息。

在确定了大概位置后还可以通过 CPU Profile 工具查看具体方法的执行时长。

线上ANR处理

线上可以使用 ANRWatchDog 开源库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ANRWatchDog extends Thread {
private final Runnable _ticker = new Runnable() {
@Override public void run() {
_tick = 0;
_reported = false;
}
};

public void run() {
long interval = _timeoutInterval; // 默认是 5 秒
while (!isInterrupted()) {
boolean needPost = _tick == 0;
_tick += interval;
if (needPost) {
// 往主线程发送一条消息
_uiHandler.post(_ticker);
}
// sleep(interval) 5 秒后检查 _tick 值是否被修改
if (_tick != 0 && !_reported) {
// ANRListener 回调 ANRError(包含调用栈信息), 默认是将其抛出
}
}
}
}