android的ANR原理剖析及图解(基于android9.0)

android中如果在主线程执行耗时操作,那么将会弹出系统弹窗ANR,那么framework层是如何实现超时的判定、都有哪些情况会产生ANR呢?
经过分析framework源码发现,有以下四种场景会引起ANR

  • InputDispatching Timeout: 输入事件分发超时5s,包括按键分发事件的超时
  • Service Timeout:服务在12s内未执行完成
  • BroadcastQueue Timeout:比如前台广播在10s内执行完成
  • ContentProvider Timeout:内容提供者执行超时

Service的ANR判定及处理

首先我们来看一下从启动service到弹出ANR dialog的调用时序图
android的ANR原理剖析及图解(基于android9.0)_第1张图片
一共有4个大步骤

  1. ams先startService
  2. ActiveServices启动service后,通过ams中的handler发送一个延迟执行消息,低版本android是20秒,9.0的android是12秒,期间如果service执行完成,将会移除这个msg,如果未移除,则在12秒后,ams会执行ActiveServices的serviceTimeout方法进行超时判定
  3. 执行ActiveServices的serviceTimeout方法,如果 执行开始时间 > (当前时间-超时时间) 时,则超时,调用AppErrors的appNotResponding方法进行超时处理
  4. AppErrors的appNotResponding超时处理分为以下6个步骤
    - 忽略关机时的ANR
    - 记录ANR事件
    - 记录ANR,打印到main log中
    - dump栈信息,输出CPU相关信息
    - 添加ANR信息到dropbox日志
    - 通知UI线程弹出anr的dialog

输入事件超时判定

和service不同的是,输入事件的超时是在C层的InputDispatcher.cpp中进行判断的,在c中判定超时后通知ams,ams再调用AppErrors进行处理ANR,详细的时序图如下
android的ANR原理剖析及图解(基于android9.0)_第2张图片
整个过程一共分为4个大步骤

  1. dispatchMotionLocked: 分发输入事件
  2. handleTargetsNotReadyLocked:处理输入事件,并判定是否超时
  3. notifyANR:一步步通知ANR,通知次序如图所示
  4. appNotResponding:处理超时,记录日志、弹出ANR的dialog等,此处和service中的处理逻辑一致

在这里我们详细剖析以下handleTargetsNotReadyLocked方法来看一下超时的判定

int32_t InputDispatcher::handleTargetsNotReadyLocked(){
	...
	//记录当前事件为第一次分发时间
    mInputTargetWaitStartTime = currentTime;
    //设置超时时间
    mInputTargetWaitTimeoutTime = currentTime + timeout;
	...
	//判断是否超时超时,当前时间大于上次输入事件记录超时时间,说明有事件分发超时了,需要触发ANR
    if (currentTime >= mInputTargetWaitTimeoutTime) {
        onANRLocked(currentTime, applicationHandle, windowHandle,
                entry->eventTime, mInputTargetWaitStartTime, reason);
        *nextWakeupTime = LONG_LONG_MIN;
        return INPUT_EVENT_INJECTION_PENDING;
    }
}

你可能感兴趣的:(android,源码,framework)