ANR(Application Not Responding )应用无响应的简称,是为了在 APP卡死时,用户 可以强制退出APP的选择,从而避免卡机无响应问题,这是Android系统的一种自我保护机制。

通过本篇阅读,您将学习到以下内容

  1. 什么是ANR
  2. ANR的类型
  3. ANR 产生的原因
  4. 如何分析解决 ANR问题
  5. ANR 问题分析解决建议
  6. MTK 平台 ANR问题分析

1. 什么是ANR

Android中,应用程序响应由Activity ManagerWindow Manager系统服务进行监视。ANR(Application Not Responding ),则是Android的一种自我保护措施,当主线程出现卡顿时候,Android 系统会给用户一个弹出提示,让用户手动选择继续等待还是强制关闭此APP

当Android检测到以下情况之一时,Android将显示特定应用程序的ANR对话框,比如以下三种情况下ANR将经常发生:

  1. UI Thread超过 5 s没有响应
  2. Broadcast广播超过10 s没响应
  3. Service 服务超过 20s 没响应
    因此,为避免ANR发生,请不要在主线程中进行耗时操作,耗时操作请尽量在子线程中运行。
  4. 发生ANR截图 如下:

android 无响应问题查找 android无响应 崩溃_应用程序

2. ANR的类型

ANRAndroid 手机中很常见,按其相应类型可以分为以下 常见 三种类型。

ANR类型:

1.输入事件/按键响应分发超时(Key Dispatch Timeout)
默认 5 s,超过则会出现ANR。

1. 1输入事件处理无响应
当应用程序的窗口处于活动状态并且能够接收输入事件(例如按键事件、触摸事件等)时,系统底层上报的事件就会被InputDispatcher 分发给该应用程序。对大多数窗口而言“处于活动状态”可以理解为“能够获得焦点且已经获取焦点”,但是一些具有FLAG_NOT_FOCUSABLE 属性的窗口(设置之后window永远不会获取焦点,所以用户不能给此window发送点击事件焦点会传递给在其下面的可获取焦点的window)除外。

应用程序的主线程通过InputChannel读取输入事件并交给界面视图处理,界面视图是一个树状结构,DecorView是视图树的根,事件从树根开始一层一层向焦点控件(例如一个 Button)传递。开发者通常需要注册监听器来接收并处理事件,或者创建自定义的视图控件来处理事件。

InputDispatcher运行在system_server进程的一个子线程中,每当接收到一个新的输入事件,InputDispatcher就会检测前一个已经发给应用程序的输入时间是否已经处理完毕,如果超时,会通过一系列的回调通知WMS的notifyANR函数报告ANR发生。

需要注意的是,产生这种ANR的前提是要有输入事件,如果没有输入事件,即使主线程阻塞了也不会报告ANR。从设计的角度看,此时系统会推测用户没有关注手机,寄希望于一段时间后阻塞会自行消失,因此会暂时“隐瞒不报”。从实现的角度看,InputDispatcher没有分发事件给应用程序,当然也不会检测处理超时和报告ANR了。

此类ANR发生时的提示语是:Reason: Input dispatching timed out (Waiting because the focused window has not finished processing the input events that were previously delivered to it.)需要注意区分同为Input dispatching timed out大类的窗口获取焦点超时,这两类超时括号内的提示语是不同的。

此类ANR的超时时间在ActivityManagerService.java中定义,默认为5秒。如果有需要可以修改代码将小内存设备上的超时时间改为大于5秒。或者在某一段时间内将此参数值设置为相应合理值。

1.2 .get focus timeout 窗口获取焦点超时
窗口获取焦点超时是用户输入事件处理超时的一种子类型,它们都由InputDispatcher向AMS上报。当应用程序的窗口处于“活动状态”并且能够接收输入事件时,系统底层上报的事件就会被InputDispatcher分发给该应用程序。如果由于某种原因,窗口迟迟不能达到“活动状态”,不能接收输入事件,此时InputDispatcher就会报出“窗口获取焦点超时”。

此类ANR发生时的提示语是:Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)需要注意区分同为Input dispatching timed out大类的用户输入事件处理超时,这两类超时括号内的提示语是不同的。

为了研究窗口为什么会获取焦点超时,我们需要简单了解在窗口切换过程中焦点应用和焦点窗口的切换逻辑。假设当前正处于应用A中,将要启动应用B。启动过程中焦点应用和焦点窗口转换如下:

流程开始,焦点应用是A,焦点窗口是A(的某一个窗口) ====》 当A开始OnPause流程后,焦点应用是A,焦点窗口是null  ====》 在zygote创建B的进程完毕后,焦点应用是B,焦点窗口是null  ====》 应用B的OnResume流程完成后,焦点应用是B,焦点窗口是B(的某一个窗口)

在这个过程当中有两个阶段的焦点窗口是null,那么如果焦点窗口为 null 阶段的时间超过了5秒,应用就会被报告为窗口获取焦点超时类的ANR。另外这个过程当中有两个阶段的焦点窗口是null,系统报告的ANR应用不一定是真实产生ANR的应用。因此在分析窗口获取焦点超时的ANR时,一定要注意分析当前焦点应用和焦点窗口是否一致,首先要明确ANR的真正应用是哪一个,再进行进一步分析才会更有意义。

那么“焦点窗口为 null 阶段的时间超过了5秒”这种情况又是为什么会出现呢?一般由下面几个原因导致:

应用程序创建慢。程序的OnCreate/OnStart/OnResume方法执行速度慢/存在死锁/死循环导致OnResume迟迟不能执行完毕,超时造成ANR。
应用程序'OnPause'慢。对同一个应用而言,前一次OnPause执行完毕之前后一次OnResume不会执行。但不同应用之间不会互相影响。
系统整体性能慢。由于系统性能原因,如CPU占用率高/平均等待队列长/内存碎片化/页错误高/GC慢/用户空间冻结/进程陷入不可打断的睡眠,会造成整体运行慢使ANR频繁发生。

2.广播超时(Broadcast Timeout)
默认 10 s,超过则会出现ANR。

3.服务超时(Service Timeout)
默认 20 s,超过则会出现ANR。

3. ANR 产生的原因

Android系统中,APP 通常运行在一个UI Thread或者叫MainThread里。并且Android中只有一个MainThread 和Main Message QueueMainThread主要用于UI的绘制、事件响应,监听与接收事件处理等功能。Main Message Queue 主要存放用户要处理消息的队列,主线程MainThread从消息队列Main Message Queue中取消息Message后,尽快分发下去,一旦某条消息分发超时,则ANR可能发生。

因此,当ANR 发生时,我们要分析ANR产生的原因,也就是查找消息处理不及时的原因。例如可以从以下几个疑问点进行分析:

  1. 为什么 APP不能获取CPU时间片?
  2. APP 是否是等待一些没能及时处理的事件完成?
  • 3 . 消息处理流程是不是太复杂?

4. 如何分析解决 ANR问题

在分析ANR时有一些常见的模式可供选择:

  1. APP正在主线程上进行缓慢的I/O操作。
  2. APP正在主线程中进行很复杂的计算操作
  3. 主线程正在对另一个进程执行同步Binder程序调用,但另一个进程需要很长时间才能返回结果。
  4. 主线程在等待另一个正在长时间执行块操作的子线程时被阻塞。
  5. 主线程因为另一个线程死锁,无论是Bind调用还是主线程调用,都不能让主线程等待很久,更不能在主线程中进行复杂的计算。

知道产生ANR的原因,那么如何避免ANR 问题呢?

a.Strict mode

使用StrictMode可以帮助您在开发应用程序时在主线程上发现意外的I / O操作。 您可以在applicationactivity使用StrictMode

b.关闭 ANR Dialog 提示

查看方法ANR控制的方法:
设置---- 开发者选项---显示所有ANR

注意 :
如没有开发者选项,请进入设置---关于手机--- 多次连击 版本号 即可打开隐藏的开发者选项的item

android 无响应问题查找 android无响应 崩溃_应用程序_02

c.Traceview

Traceview获取正在运行的应用程序的跟踪信息,分析此traces.txt文件 可以推测出主线程在忙于某些事情。

traces文件通常保存在/data/anr/traces.txt下,你可以直接用adb cat 查看,或者 adb pull出来都可以。

  • 直接查看trace 信息

个人不太建议

adb rootadb shellcat /data/anr/traces.txt

  • pull trace 文件到桌面

建议使用此方法

adb rootadb remountadb pull /data/anr/traces.txt C:\Users\Administrator\Desktop\新建文件夹

android 无响应问题查找 android无响应 崩溃_获取焦点_03

5. ANR 问题分析解决建议

分析查看ANR原因,接着解决ANR问题。

  1. 耗时操作
    请放在工作现场中进行,可以使用Handler、AsyncTask等。
  2. IO 操作
    (比如:网络操作、存储操作等)也是引起ANR的常见因素。强烈建议在工作线程中进行。
  3. 程序锁竞争

某些情况,ANR产生的原因不是直接因为在主线程中产生的。 比如: 工作线程对某个资源等上锁,恰好此时,主线程需要此资源,如等待超时,则此时ANR可能发生。

  1. 死锁

当主线程因为请求一个其他线程正在持有的资源而进入等待状态时,ANR可能会发生。

  1. 广播接收慢

应用程序可以通过广播接收器响应广播消息,例如启用或禁用飞行模式或更改连接状态。 当应用程序花费太长时间来处理广播消息时,理论上超过10s 未处理完成,ANR可能会发生。

广播 ANR发生在下列情况下:

  1. onReceive() 方法长时间未执行完毕。

尽量避免在onReceive() 中进行耗时操作。

  1. 广播接收者调用goAsync()方法并且未能在PendingResult对象上调用finish()

如要处理的广播内容较多,请使用IntentService 进行处理。

比如下面例子:

  • 不建议在onReceive 方法中进行耗时操作,超过10s 未处理,会引起ANR

android 无响应问题查找 android无响应 崩溃_android_04

  • 建议使用IntentService ,避免ANR发生

android 无响应问题查找 android无响应 崩溃_获取焦点_05

您的广播接收机可以使用goAsync()来通知系统需要更多的时间来处理消息。 但是,您应该在PendingResult对象上调用finish()。 以下示例显示如何调用finish()以让系统回收广播接收器并避免ANR:

android 无响应问题查找 android无响应 崩溃_主线程_06

6. MTK 平台 ANR问题分析(跟平台关系不大,高通的这样搜一样可以)

前提,抓取一份ANRMTK log

1.event_log 中 搜索关键字 am_anr或者anr,分析并查看ANR原因

android 无响应问题查找 android无响应 崩溃_主线程_07

2. main_log中 搜索关键字Application Not Responding或者anr ,分析并查看ANR原因。

android 无响应问题查找 android无响应 崩溃_android_08

3. MTK ANR 策略建议

android 无响应问题查找 android无响应 崩溃_应用程序_09

android 无响应问题查找 android无响应 崩溃_获取焦点_10

android 无响应问题查找 android无响应 崩溃_主线程_11

android 无响应问题查找 android无响应 崩溃_应用程序_12

常见ANR 举例分析如下:

android 无响应问题查找 android无响应 崩溃_主线程_13

android 无响应问题查找 android无响应 崩溃_android_14

android 无响应问题查找 android无响应 崩溃_主线程_15

android 无响应问题查找 android无响应 崩溃_android_16

android 无响应问题查找 android无响应 崩溃_获取焦点_17

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ANR问题分析:

导致ANR主要有3种原因
ANR(application no response)
(一)导致ANR主要有3种原因:
ANR的产生原因就是由于应用程序的主线程响应超时导致的,只要超过最大限制的超时时间就必然会产生ANR:

原因一: KeyDispatchTimeout(5 seconds)–按键或触摸事件在特定时间内无响应;(输入事件)
KeyDispatchTimeout anr一般分析方法:
1.1 在event_log中搜关键字am_anr
1.2 在main_log中搜Application Not Responding

原因二: BroadcastTimeout(10 seconds)–BroadcastReceiver在特定时间内无法处理完成;(特定操作)
BroadcastTimeout anr一般分析方法:
2.1 在event_log中搜关键字am_anr
2.2 在main_log中搜Timeout of broadcast BroadcastReceiver

原因三: ServiceTimeout(20 seconds)–Service在特定的时间内无法处理完成;(特定操作)
ServiceTimeout anr一般分析方法:
2.1 在event_log中搜关键字am_anr
2.2 在main_log中搜Timeout executing service

(二)获取log方法
(1.1)获取实时log: adb logcat -v time >anr.log 或 adb logcat -v time | tee anr.log
(1.2)获取traces.txt文件:adb pull /data/anr/traces.txt C:\monkey
(三)分析log
从log可以看出ANR的类型:
1.cpu使用量接近100%,说明当前设备很忙,有可能是cpu饥饿导致ANR;
2.cpu使用量很低,说明主线程有可能被阻塞;
3.IOwait很高,说明有可能是主线程在进行I/O操作导致ANR;
(四)分析traces