一、引言
ANR问题是android中常见且令人头疼的问题,相当多的时候不易直接分析出原因。
二、ANR的定义
下面先看下百度百科给ANR的定义:
ANR问题常因在main(主线程)线程执行了复杂耗时的操作,比如文件IO、网络访问、无限循环等,最终无奈地被系统抛出ANR。
三、ANR的一般分析思路
1) 从手机的/data/traces/目录导出traces.txt文件;
2) 从traces.txt文件获取ANR产生的时间点T1;
3) 从traces.txt文件获取main线程的运行状态、调用栈;
4) 查看logcat日志,搜索"ANR in",找出ANR产生的时间点T2,以及时间点T2 前后几秒钟,在系统中运行的各进程CPU耗时占比;
5) 在步骤4)找出目标进程的cpu耗时占比,确认是user占比高,还是kernel占比高,还是iowait占比高;
6) 根据时间点T1、时间点T2,校准ANR产生的时间范围 [T1, T2] 或 [T2, T1];
7) 查看logcat日志,将日志定位到步骤2)中获取的时间点 [T1, T2] 或 [T2, T1]附近;
8) 查看logcat日志在时间点 [T1, T2] 或 [T2, T1]附近前后2分钟的日志,以还原ANR产生前后的场景;
9) 根据以上步骤得出的信息,定位代码中可能的问题代码块;
10) 解决问题,或提出阶段分析结论。
四、ANR的分析示例
产生ANR后,系统会在/data/traces/下生成traces.txt文件,我们首先将该traces.txt文件从手机对应的目录导出。
打开traces.txt后,先确认产生ANR的进程及ANR产生时间,如下图红框所示,产生ANR的进程是cn.evergrande.it.phone,ANR产生的时间是2018-08-16 10:34:43,
注意,在ANR分析中,ANR产生的时间点非常重要,是串接traces.txt和logcat相关日志线索的连接线,是推理ANR产生原因的重要线索。
继续分析traces.txt,找到cn.evergrande.it.phone进程的main线程调用栈快照,如下图所示,main线程在2018-08-16 10:34:43处于Runnable状态,并且正在
执行java层代码以测量layout布局中的RecylerView。
查看logcat日志,搜索"ANR in",定位到如下图所示的CPU usage from 35958ms to 0ms ago部分的日志,可知 2018-08-16 10:34:07.546 到 2018-08-16 10:34:43.504 时间段,cn.evergrande.it.phone进程并没有较多的cpu占比。
继续查看CPU usage from 372ms to 893ms later部分的日志,可知在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398 时间段,ANR问题开始出现,
其中cn.evergrande.it.phone进程的grande.it.phone、HDLogicThread-2、ReqTimer三个线程的cpu占比都比较高,可推断是cn.evergrande.it.phone进程引发了ANR。
综合上述ago、later两部分的ANR日志,基本可以断定ANR产生的源头是cn.evergrande.it.phone进程,
其中,线程grande.it.phone的线程id是20974、HDLogicThread-2的线程id是21000,ReqTimer的线程id是20974,而在traces.txt中,main的线程id是20974,所以可断定是
cn.evergrande.it.phone进程阻塞引发了ANR。
接下来要确认ANR产生的原因,先校准ANR产生的时间点,
1) traces.txt给出的时间点是 2018-08-16 10:34:43
2) logcat给出的时间范围是 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398
综合1)、2)时间(点)的交集,校准后的ANR产生时间范围是 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398。
接下来,查看logcat在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398范围的日志,还原ANR产生时的情景。
上图日志显示了logcat在 2018-08-16 10:34:43.877 到 2018-08-16 10:34:44.398附近的日志,可还原出此时间段系统正在播放音乐、用户正在操作进度条控制音乐的播放,
但并没有与ANR产生原因相关的线索,由于traces.txt是在main线程Runnable时生成的,所以不能从main的调用栈分析出ANR产生的可能原因。
五、小结
第四节中举的示例是没有足够数据,以分析出产生ANR的原因,但本文旨在告诉读者一种分析ANR的思路,以供大家借鉴和不断完善。
原文地址:https://www.cnblogs.com/tgltt/p/9849792.html