ANR发生的原理是什么, 怎么排查

定义

ANR 的全称是 Application No Responding,即应用程序无响应,具体是一些特定的 Message (Key Dispatch、Broadcast、Service) 在应用的UI线程(主线程)没有在规定的时间内处理完,进而触发 ANR 异常。

ANR类型

1.KeyDispatchTimeout

这个主要是按键或触摸事件在特定时间内无响应,一般 Android 平台默认超时时间是 5s 会报 anr,不过有些平台会修改这个时间,比如 MTK 有些平台就是 8s 的超时时间。

这个超时时间可以在 ActivityManagerService.java 查看:

// M: ANR debug mechanism (Ori: 5*1000)
static final int KEY_DISPATCHING_TIMEOUT = 8*1000;

2.BroadcastTimeout

这类超时会有 ANR 提示框弹出,用户可以选择 forceStop 或者继续等待。

这个主要是 BroadcastRecevier 在规定时间无法处理完成。前台广播超时时间是 10s后台广播超时是 60s,这类超时没有提示框弹出

==> AMS.java

// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;

3.ServiceTimeout&nbsp

Service 在规定时间内无法处理完成操作,即会报出服务超时,这类 ANR 同样没有提示框出现。超时时间,前台 Service 是 20s后台 Service 是 200s

==> ActivityServices.java

// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

三种 ANR 中只有第 1 种会显示系统提示对话框,因为用户正在做界面交互操作,如果长时间没有任何响应,会让用户怀疑设备死机了,大多数人此时会开始乱按,甚至拔出电池重启,给用户的体验肯定是非常糟糕的。

三种 ANR 发生时都会在 log 中输出错误信息,你会发现各个应用进程和系统进程的函数堆栈信息都输出到了一个 /data/anr/traces.txt 的文件中,这个文件是分析ANR原因的关键文件,同时在日志中还会看到当时的 CPU 使用率,这也是重要信息,在后面的章节会详细介绍如何利用它们分析ANR问题。

这三种ANR不是孤立的,有可能会相互影响。例如一个应用程序进程中同时有一个正在显示的 Activity 和一个正在处理消息的 BroadcastReceiver,它们都运行在这个进程的主线程中。如果 BR 的 onReceive 函数没有返回,此时用户点击屏幕,而 onReceive 超过 5 秒仍然没有返回,主线程无法处理用户输入事件,就会引起第 1 种 ANR。如果继续超过 10 秒没有返回,又会引起第 2 种ANR。

ANR发生的原理

  • 在进行相关操作调用 hander.sendMessageAtTime() 发送一个 ANR 的消息,延时时间为 ANR 发生的时间(如 activity 是当前时间 5s 之后)。
  • 进行相关的操作
  • 操作结束后向 remove 掉该条 message。如果相关的操作在规定时间没有执行完成,该条 message 将被 handler 取出并执行,就发生了 ANR。

Android 对于消息的处理都是通过 Handler 来完成的

怎么排查

当ANR发生时,我们往往通过Logcattraces文件(目录/data/anr/)的相关信息输出去定位问题。主要包含以下几方面:

  1. 基本信息,包括进程名、进程号、包名、系统build号、ANR 类型等等;
  2. CPU使用信息,包括活跃进程的CPU 平均占用率、IO情况等等;
  3. 线程堆栈信息,所属进程包括发生ANR的进程、其父进程、最近有活动的3个进程等等。

1.查看 log 日志文件

android系统会自动帮我们生成一个log日志输出文件,在data/system/dropbox/下,真机测试需要root权限,模拟器在DDMS下可以查看。

用这种方法,出现问题,根本不需要断点调试 , 直接定位到问题,屡试不爽 。
从LOG可以看出ANR的类型,CPU的使用情况,

一般在如下几种情况会产生log 。

1,程序异常退出 , uncaused exception
2,程序强制关闭 ,Force Closed (简称FC)
3,程序无响应 , Application No Response (简称ANR) , 顺便,一般主线程超过5秒么有处理就会ANR

步骤:

1.打开log文件 , 由于是ANR错误,因此搜索”ANR ” , 为何要加空格呢,你加上和去掉比较一下就知道了 。 可以屏蔽掉不少保存到anr.log文件的无效信息

定位到关键的事件信息如下:

01-15 16:49:02.433 E/ActivityManager( 2466): ANR in com.android.mms (com.android.mms/.ui.SlideshowActivity)
01-15 16:49:02.433 E/ActivityManager( 2466): Reason: keyDispatchingTimedOut
01-15 16:49:02.433 E/ActivityManager( 2466): Load: 0.6 / 0.61 / 0.42
01-15 16:49:02.433 E/ActivityManager( 2466): CPU usage from 1337225ms to 57ms ago:
01-15 16:49:02.433 E/ActivityManager( 2466):   sensorserver_ya: 8% = 0% user + 8% kernel / faults: 40 minor
......
01-15 16:49:02.433 E/ActivityManager( 2466):  -com.android.mms: 0% = 0% user + 0% kernel
01-15 16:49:02.433 E/ActivityManager( 2466):  -flush-179:8: 0% = 0% user + 0% kernel
01-15 16:49:02.433 E/ActivityManager( 2466): TOTAL: 25% = 10% user + 14% kernel + 0% iowait + 0% irq + 0% softirq
01-15 16:49:02.436 I/        ( 2466): dumpmesg > "/data/log/dumpstate_app_anr.log"

我们用自然语言来描述一下日志,

01-15 16:49:02.433 E/ActivityManager( 2466): ANR in com.android.mms (com.android.mms/.ui.SlideshowActivity)

翻译:在16:49分2秒433毫秒的时候 ActivityManager (进程号为2466) 发生了如下错误:com.android.mms包下面的.ui.SlideshowActivity 无响应 。

01-15 16:49:02.433 E/ActivityManager( 2466): Reason: keyDispatchingTimedOut

翻译:原因 , keyDispatchingTimeOut - 按键分配超时

01-15 16:49:02.433 E/ActivityManager( 2466): Load: 0.6 / 0.61 / 0.42

翻译:5分钟,10分钟,15分钟内的平均负载分别为:0.6 , 0.61 , 0.42

我们大概知道问题是什么了,问题是在点击按钮某时候可能处理不过来按钮事件,导致超时无响应 。但我们不能准确的知道到底问题在哪儿 , 只是猜测 ,比如这个应用程序中,多个IO操作的地方都在主线程中,可能引起问题,但不好判断到底是哪个 ,所以我们目前掌握的信息还不够 。
于是我们再分析虚拟机信息 ,搜索“Dalvik Thread”关键词,快速定位到本应用程序的虚拟机信息日志

2.Trace 文件(data/anr/traces.txt)真机导出,模拟器在DDMS下查看

连接真机,在AndroidStudio右下角有一个Device File Explorer 点击可以查看手机文件 ,然后data/anr 找到traces.txt文件

 如果ANR发生,对应的应用会收到SIGQUIT异常终止信号,dalvik虚拟机就会自动在/data/anr/目录下生成trace.txt文件,将异常信息写入到traces文件中,系统会记录异常的位置、CPU和内存当时的使用情况,通过查看日志基本就能判断问题所在。

接下来用adb shell命令导出该文件,通过shell命令就可以了。

adb pull /data/anr/traces.txt d:/ =》意思是将手机上的traces.txt导出到电脑的d目录下
或者
1、adb shell
2、cat /data/anr/xxx >/mnt/sdcard/yy/zz.txt
3、exit
4、adb pull /mnt/sdcard/yy/zz.txt d: ,即可将文件导出到了d盘。

在发生ANR时,

步骤:
1. 找到ANR关键字(大写匹配)
2. 向上查找timeout关键字,这个时候能找到ANR的原因,如: Application do too much work in main thread 等。
3. 查看trace 文件找出出现的最终原因。

3.在源代码中插入ANR检测工具(BlockCanary、StrictMode)

根据提示找到来找到原因,

4.使用第三方SDK输出Crach信息到后台服务器:

如腾讯bugly 和umeng

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值