前记
发现好久没写博客了,主要是最近忙着春招,忙着看算法和将以前的知识重新回顾,所以很久没更了,其实一直在写,只是写的不系统,所以没更出来,今天抽空特地更一下。
ps:春招真难,还没找到工作。。。
ANR分析
ANR流程
什么是ANR
ANR是指在Android中,当触摸或者按键事件以及特殊事件没有在规定的时间中完成,那么就会出现ANR(也有可能不会出现ANR),这里的特殊事件就是指Service
、BroadCastReceiver
、ContentProvider
。
在源码中是如何体现的?
以Service
为例:
1.在realStartServiceLocked
方法中会调用bumpServiceExecutingLocked(r, execInFg, "create");
方法,这个函数的作用就是延时发送消息,当在Service
的onCreate
方法回调之后,就会调用AMS.serviceDoneExecuting(IBinder token, int type, int startId, int res)
来清除之前发送的消息。所以在onCreate()
方法中不能超过20S。
2.在AS.sendServiceArgsLocked
方法中也会bumpServiceExecutingLocked(r, execInFg, "start");
,然后当回调onStartCommand();
方法后也会调用AMS.serviceDoneExecuting(IBinder token, int type, int startId, int res)
方法来清除之前发送的消息。所以在onStartCommand()
中也不能超过20S,同时因为在onStartCommand()
会调用onStart()
,所以在onStart()
中也不能超过20S。
也就是说采用的手法是消息机制,就是在启动的时候延时发送一个消息,如果成功启动,那么就会移除这个消息,反之就会使用AMS
中的MainHandler
去发送SERVICE_TIMEOUT_MSG
这个消息,在MainHandler
中的handleMessage
来处理消息,最后会调用到AMS.appNotResponding()
。
以BroadCastReceiver
为例:
在processNextBroadcast
方法中调用setBroadcastTimeoutLocked(timeoutTime);
方法设置超时时间,当没超时时,调用cancelBroadcastTimeoutLocked();
超时时,由BroadcastHandler
发送BROADCAST_TIMEOUT_MSG
,在BroadcastHandler
的handleMessage
中调用broadcastTimeoutLocked(false);
来强制结束广播。并且调用mService.appNotResponding(mApp, null, null, false, mAnnotation);
使用的依然是handler
消息机制。
以ContentProvider
为例:ContentProvider
发生ANR
和其他的都不一样,当使用ContentProvider
的时候,若是目标进程不存在,则会创建目标进程,在创建目标进程后会调用AMS.attachApplicationLocked
,此时就会延时发送一个消息,延时也是10S,当provider
成功publish
之后,也就是在AMS.publishContentProviders
中会移除这个消息,反之最后会调用到AMS.removeProcessLocked
。杀掉ContentProvider
所在的进程。
注意:关于CONTENT_PROVIDER_PUBLISH_TIMEOUT
超时时机是指在startProcessLocked
之后会调用AMS.attachApplicationLocked
为起点,一直到AMS.publishContentProviders
的过程。
所以对于ContentProvider
而言,如果不需要创建新进程,那么就不会出现这个情况,在不需要创建新进程的时候,也可能会出现ANR
,并且会调用AMS.appNotResponding()
。
总结
ANR
发生的原因是,在Android的源码中规定了事件或者特殊事件需要在规定时间内完成,提升用户的体验,但是没有完成。在这里事件指触摸或者按键,特殊事件指Service
、BroadCastReceiver
、ContentProvider
。 所采取的措施都是通过Handler
消息机制。
对于Service
而言:在Service
的onCreate
,onStart
、onStartCommnand
生命周期方法中超时20S。
对于BroadCastReceiver
而言:在onReceive()
超时10S。
对于ContentProvider
而言:从AMS.attachApplicationLocked
到AMS.publishContentProviders
的过程中耗时超过10S。
对于ContentProvider
而言,不会走AMS.appNotResponding()
,其他的都走。AMS.appNotResponding()
处理中主要是将CPU使用情况和进程的trace文件信息,保存到/data/system/dropbox;