ANR(Application Not Responding)通常发生在主线程被长时间阻塞,导致无法响应用户的操作,一般会弹应用无响应的对话框让用户选择等待或者强制退出。
一、ANR产生的条件
(1)主线程:只有应用程序的主线程响应超时才会产生ANR
(2)超时时间:产生 ANR 的上下文不同,超时时间也会不同,但只要在这个时间上限内没有响应就会ANR
(3)输入事件/特定操作:输入事件是指按键、触屏等设备输入事件,特定操作是指 BroadcastReceiver 和 Service 的生命周期中的各个函数,产生 ANR 的上下文不同,导致 ANR 的原因也会不同
需要注意的是:主线程做耗时操作本身是不会产生ANR的,如果不需要应用响应操作是不会产生ANR的。
二、ANR类型
(1)KeyDispatch Timeout :按键或触摸事件在特定时间内无响应,超时时间5秒。
(2)Broadcast Timeout :BroadcastReceiver在特定时间内无法处理完成,前台广播10秒,后台广播60秒。
(3)Service Timeout :Service在特定的时间内生命周期函数无法处理完成,前台服务20秒,后台服务200秒。
(4)ContentProvider Timeout :ContentProvider在特定的时间内没有完成发布,超时时间10秒。
三、ANR原因
(1)应用在主线程上执行耗时 的 I/O操作;
(2)应用在主线程上进行长时间的计算;
(3)主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
(4)主线程处于阻塞状态,等待另一个线程的锁。
(5)主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。
四、ANR分析基本流程
1、日志抓取
通常我们都知道通过adb pull /data/anr/traces.txt xxx获取trace.txt文件来分析卡顿的地方:
adb pull /data/anr/traces.txt 本地目录
但有的手机没权限抓取,则使用adb bugreport获取错误日志:
adb bugreport 本地目录
一份完整的bugreport包含下面的信息,对分析ANR问题很关键
Log名称 |
作用 |
获取命令 |
system.log |
包含ANR发生时间点信息、ANR发生前的CPU信息,还包含大量系统服务输出的信息 |
adb logcat –b system |
main.log |
包含ANR发生前应用自身输出的信息,可供分析应用是否有异常;此外还包含输出的GC信息,可供分析内存回收的速度,判断系统是否处于低内存或内存碎片化状态 |
adb logcat –b main |
event.log |
包含AMS与WMS输出的应用程序声明周期信息,可供分析窗口创建速度以及焦点转换情况 |
adb logcat –b event |
kernel.log |
包含kernel打出的信息,LowMemoryKiller杀进程、内存碎片化或内存不足,mmc驱动异常都可以在这里找到。 |
2、分析日志
备注:此处缺一个图,因可能涉及项目隐私,后续会通过demo来补充。
在main log(见上图红色箭头)搜索“ANR in”,查看发生的时间和进程,在 mainlog 日志分析发生 ANR 时的 CPU 状态
在 traces.txt 找到 ANR 信息(发生 ANR 时间节点、主线程状态、事故点、ANR 类型),根据进程寻找主线程的trace,发现被blocked的堆栈等信息,
在 traces.txt 分析发生 ANR 时的 GC 情况(分析内存)
3、结合源码分析
有可能通过这两个步骤无法定位到ANR发生的原因,那就需要更深入的分析问题了。
备注:此处后续也会通过demo来补充。