ANR(Application Not Responding), 如果 Android 应用的界面线程处于阻塞状态的时间过长,会触发“应用无响应”(ANR) 错误。如果应用位于前台,系统会向用户显示一个对话框,如图 1 所示。
ANR 对话框会为用户提供强行退出应用的选项。
ANR分类
- Input dispatching timed out:输入时间分发超过5s,包括按键和触屏事件。目前项目上为主要类型。
- Broadcast of Intent:前台广播需要在10s内完成,后台广播需要在60s内完成。
- executing service:前台服务需要在20s内完成,后台则需要在200s内完成。
- ContentProvider:几乎非常少见,publish执行未在10s内完成。
- Context.startForegroundService() did not then call Service.startForeground():应用调用startForegroundService,然后5s内未调用startForeground出现ANR或者Crash,此问题属于应用未适配sdk。
产生ANR的原因
诊断 ANR 时需要考虑以下几种常见模式
- 应用在主线程上非常缓慢地执行涉及 I/O 的操作,如有复杂的layout布局、频繁的I/O操作。
-
应用在主线程上进行长时间的计算,如一些耗时操作。
-
主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。
-
主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。
-
主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。
发生ANR的原因
-
主线程存在耗时操作:主线程阻塞(Blocked)、挂起(suspend)、死锁、死循环、耗时操作等;
-
cpu资源被抢占:其他进程某一时间点cpu占比高、某一刻系统的cpu占比过高,都会导致这一时间段无法抢到cpu时间片;
-
主线程卡在binder通信的对端:需要通过binderinfo查看对端信息;
-
系统或者应用自身可用内存紧张:系统一直在执行lowmemorykiller操作查杀进行;
-
应用频繁crash:包括应用自身也容易导致前台应用出现anr的现象;
-
应用内存泄露;
-
系统原因导致:如冻结(freeze)、温控策略(horae、thermalControlUtils)、多媒体(音视频、解码)、包管理、Block I/O(balance_dirty_pages_ratelimited等)、相机服务挂掉等。
分析日志思路
首先在android(system)日志中搜索“ANR in”关键字,通过此关键字主要查看
- 发生ANR的应用进程、pid、类型;
-
cpu负载、内存压力、cpu使用情况等。
event日志:
trace日志:
以上是中国农业银行应用的主线程trace日志,主线程在执行native方法,调用到nSyncAndDrawFrame说明进行GPU渲染的过程中出现耗时操作。
CPU占比信息分析
从android(高通平台在android.txt,MTK平台在system*.txt)日志中,查看系统中各个进程的cpu使用率,首先关注的进程就是发生anr的进程、system_server、kswapd0和其他占比较高的进程、以及最终统计的整体cpu占比信息。如果kswapd0占比较高,就说明内存存在一定的压力;iowait很高就说明系统在进行一些I/O操作,就可以结合上下文日志辅助分析发生ANR的原因。如果很多进程的cpu使用率普遍较高,此时可以怀疑发生anr的应用拿不到cpu时间片导致anr等。
Memory角度分析
可以搜索关键字“Athena”,查看发生anr时间点前后的可用内存情况,以及系统查杀应用的频繁程度。也可以查看日志文件中dumpsys_mem.txt文档查看详细信息。需要注意时间点一致。
kernel日志分析思路
在日志中直接搜索关键字“lowmemorykiller”、“iowait”等,查看发生的时间点与发生anr的时间点是否基本对应。如果发生anr时间点附近,出现大量的lowmemorykiller日志信息,则说明当时内存已经严重紧张,可以较大概率认为是内存不足导致后台一直在查杀进程,同时影响前台应用的操作,导致前台应用操作耗时出现anr问题;如果出现iowait,则表示出现了I/O卡顿。
综合系统功能进行整体分析
大部分情况根据trace日志很难能够直接确定发生anr的原因,需要根据当时的系统运行情况进行辅助分析。综合当前的系统环境,可以从阻塞消息队列(ANR_LOG 、MessageQueue)、系统可用内存(Athena)、发热功耗(horae(MTK)、system_server(QCOM))、后台GC频率(GC)、dex2oat耗时(dex2oat)、冻结(ColorHansManager或OplusHansManager)、频繁crash(fatal、am_crash)、限频、温控策略(ThermalControlUtils)、lowmemorykiller(kernel日志)、root权限(银行类应用)、system.err、system.out、binder_sample情况等日志进行分析问题。也存在这种情况,系统日志信息不足以分析出anr的问题,此时需要借助日志中的systrace日志进行详细分析,虽然说大部分时间都对不上,但是也存在对上的时候。
总之,分析ANR问题需要进行整体分析,结合系统中的所有关键信息共同得出ANR发生原因的准确结论。
目前项目中的典型实例
Block I/O
gms频繁冻结导致chrome发生ANR
冻结导致
GPU渲染
对端被冻结
应用适配sdk
相机问题
限频导致负载高
音频问题
APK签名认证
无焦点窗口
频繁崩溃
内存泄露
Binder耗尽
barrier阻塞
消息过量
内存不足
应用死锁
窗口检查
MessageQueue
这种情况很有可能是该进程的其他子线程消耗CPU资源导致,这就需要分析其他子线程的trace以及主线程在anr前后打印出的日志。一般情况分析top占比的子线程trace。
自身NE导致ANR
wifi权限拦截
mediacodec进程大量vpp bypass模式fail
Google库导致
provider问题
park锁耗时
GMS TIME_SET广播超时
总结
通过以上的实例剖析,可以看出除了正常的接收处理超时外,也会有其他额外因素引发应用产生ANR,比如系统的kswapd0过高引发频繁的内存交换、cpu占比过高导致无法获取足够的时间片、binder资源耗尽无法及时通讯等,这些都可以从系统日志中获取到。所以如果单凭trace日志无法分析出来的时候,我们要尽可能多的查看影响发生anr的因素,搜索关键字帮我们快速定位发生的anr问题。对于一些日志不全的,只能寻求测试同事帮忙复现,抓取现场完整有效日志进一步分析。解决此类问题,需要有更多的系统洞察能力。