Android ANR原因和流程总结

目录

一、概述

二、ANR原因和类型和发生场景

ANR原因

ANR类型

常见的ANR发生场景

三、ANR流程分析

inputDispatching Timeout

BroadcastTimeout

发送BROADCAST_TIMEOUT_MSG

处理BROADCAST_TIMEOUT_MSG

删除BROADCAST_TIMEOUT_MSG

ServiceTimeout

发送SERVICE_TIMEOUT_MSG

处理SERVICE_TIMEOUT_MSG

删除SERVICE_TIMEOUT_MSG

四、总结

流程总结:

避免措施:


一、概述

       ANR全称是Application Not Responding(应用程序无响应),发生ANR的时候一般会弹出一个应用无响应对话框,同时会候产生一个日志文件trace.txt,位于/data/anr/文件夹下面,我们可以通过ANR产生的traces日志文件分析应用在哪里产生了ANR,以此来解决应用中的ANR问题。

二、ANR原因和类型和发生场景

ANR原因

当应用程序的UI线程响应超时就会引起ANR,超时原因一般有两种:

  • 当前事件没有机会得到处理,如UI线程正在响应另一个事件,当前事件由于某种原因被阻塞了。
  • 当前事件正在被处理,但是由于耗时太长没有能够及时完成。

ANR类型

根据发生ANR的原因和超时时间分类,大致有三种ANR:

  • inputDispatching Timeout:最常见的一种类型,主要是事件分发超时,事件在特定时间内(5s)无法得到响应
  • BroadcastTimeout:BroadcastReceiver的onReceive函数运行在主线程,并在特定的时间内(10s)无法完成处理
  • ServiceTimeout:Service的各个生命周期函数在特定时间内(20s,后台服务200s)无法完成响应。.

常见的ANR发生场景

  1. 主线程频繁进行IO操作,比如读写文件或者数据库;
  2. 硬件操作如进行调用照相机或者录音等操作;
  3. 多线程操作的死锁,导致主线程等待超时;
  4. 主线程操作调用join()方法、sleep()方法或者wait()方法;
  5. 耗时动画/耗资源行为导致CPU负载过重
  6. ystem server中发生WatchDog ANR;
  7. service binder的数量达到上限

三、ANR流程分析

ANR类型分为三种,我们就分析下这三种ANR发生的流程:

inputDispatching Timeout

应用程序接收输入事件(按键、触屏、轨迹球等),当5秒内没有处理完毕时,则会引发ANR。

Android中的输入事件都是交给InputDispatcher,InputDispatcher则在其线程循环中将派发队列中的事件取出,查找合适的窗口,将事件写入到窗口的事件接收管道中。窗口事件接收线程的Looper从管道中将事件取出,交由窗口事件处理函数进行事件响应。是否超时也是在InputDispatcher.cpp中进行判断的。

流程图:

整个过程一共分为3个步骤:

  1. onANRLocked;执行ANR方法。
  2. notifyANR:通知JAVA层执行ANR,通知次序如图所示。
  3. appNotResponding:处理超时,记录日志、弹出ANR的dialog等。

BroadcastTimeout

BroadcastReceiver的onReceive方法执行耗时操作前台广播10s,后台广播60秒)超时引发的ANR。BroadcastQueue中的mHandler收到BROADCAST_TIMEOUT_MSG消息时触发。我们下面看下消息的发送和处理流程。

当匹配到广播后,AMS会调用BroadcastQueue的processNextBroadcast方法进行处理广播。

我们进入processNextBroadcast方法看下执行了哪些方法。

发送BROADCAST_TIMEOUT_MSG

首先调用了broadcastTimeoutLocked方法。

在broadcastTimeoutLocked方法中调用setBroadcastTimeoutLocked方法。

setBroadcastTimeoutLocked方法来向BroadcastHandler发送消息。

我们接下来看下消息的处理。

处理BROADCAST_TIMEOUT_MSG

BroadcastHandler接收消息后悔再次调用broadcastTimeoutLocked方法。在broadcastTimeoutLocked方法中判断是否超时。如果超时就会执行下面的代码。

最后调用AMS的appNotResponding方法通知用户ANR了。

删除BROADCAST_TIMEOUT_MSG

这里就是整个的流程。整个过程为下面几个步骤:

  1. setBroadcastTimeoutLocked方法;发送一个超时消息。
  2. serviceTimeout方法:判断是否ANR。
  3. appNotResponding:处理超时,记录日志、弹出ANR的dialog等。

ServiceTimeout

创建Service过程中的各个生命周期函数超时(20s,后台服务200s)引发的ANR。AMS中的mHandler收到SERVICE_TIMEOUT_MSG消息时触发。我们跟着Serviced的创建流程梳理一下ANR发生的流程:

发送SERVICE_TIMEOUT_MSG

Service启动时,会调用system_server进程中的ActiveServices的attachApplicationLocked方法,然后调用realStartServiceLocked方法完成服务的启动。

通过bumpServiceExecutingLocked方法发送SERVICE_TIMEOUT消息。

在方法中看到向发送消SERVICE_TIMEOUT_MSG息。我们这里先看下是如何处理这个消息的。

处理SERVICE_TIMEOUT_MSG

我们看下AMS的MainHandler是如何处理SERVICE_TIMEOUT_MSG的呢?

这里又调用ActiveServices的serviceTimeout方法进行处理,serviceTimeout方法核心逻辑如下,

这里就调用了appNotResponding()方法来弹框提示ANR了。

删除SERVICE_TIMEOUT_MSG

然后我们接着之前的realStartServiceLocked方法梳理下消息在哪里会删除的。

realStartServiceLocked方法执行了ApplicationThread的scheduleCreateService方法。

最后调用ActivityThread的handleCreateService方法。这个方法会先加载service 对象。

handleCreateService方法接着调用serviceDoneExecuting方法删除之前发送的消息。

 

整个的流程就结束了。过程为3个步骤

  1. bumpServiceExecutingLocked方法;先发送一个超时消息,然后开始创建Service。
  2. serviceTimeout方法:判断是否ANR。
  3. appNotResponding:处理超时,记录日志、弹出ANR的dialog等。

四、总结

流程总结:

  • 前台服务,超时为SERVICE_TIMEOUT = 20s;
  • 后台服务,超时为SERVICE_BACKGROUND_TIMEOUT = 200s
  • 前台广播,超时为BROADCAST_FG_TIMEOUT = 10s;
  • 后台广播,超时为BROADCAST_BG_TIMEOUT = 60s;
  • 应用页面相应为5s;
  • Service, Broadcast, Input发生ANR之后,最终都会调用AMS.appNotResponding方法来处理超时,记录日志、弹出ANR的dialog等操作。

避免措施:

  • 在Activity和Service的生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。建议使用Handler+Message的方式做一些耗时的创建操作。
  • 避免在主线程上进行复杂耗时的操作。可以把耗时操作放在线程中去执行。
  • 避免在BroadcastReceiver里做耗时的操作。如果要进行复杂的耗时操作,可以在onReceive()方法中启动一个Service来处理。
  • 编写代码一定要仔细,避免出现同步/死锁或者错误处理不恰当等情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值