Android系统中,ANR机制是一个比较大的话题。四大组件Activity、Service、BroadCastReceiver、ContentProvider都会涉及到。四大组件对于Anr的监控机制是不尽相同的,BroadCastReceiver和Service比较类似。Activity作为强交互的组件,有一套基于InputDispatcher的独特Anr检测机制,涉及JNI层。在这里我们的重点是:针对Service组件,在Android 系统层是如何建立Anr机制的。这里的话题涵盖以下方面:
- Service 的 Anr监控机制都由那些重量级角色参与
- Service 的 Anr监控机制的建立流程是怎样的
- Service 的 Anr监控机制的实现原理是什么
我们一般启动一个Service,会调用startService(),我们追进去发现,调用这句话的其实是ContextImpl这个类。ContextImpl前面我们已经讲过了,是Context的子类,跟ContextWrapper是兄弟关系。然后,它调用自己的startServiceCommon()跨进程调用到sys_server进程中的ActivityManagerService(后续简称AMS)的startService()方法申请资源。
在AMS 的startService()中,又调用到ActiveServices类(后续简称AS)中的startServiceLocked(),依次经历startServiceInnerLocked()->bringUpServiceLocked()->realStartServiceLocked()去真正执行startService的操作。
在realStartServiceLocked()中,首先执行bumpServiceExecutingLocked(),走到scheduleServiceTimeoutLocked()方法,就是在这里,Anr的监控机制,通过AMS中的Handler,埋下了一颗“延时炸弹”,并通过区分Service的前后台情况,选用不同的“引爆时长”。如果是ForegroundService,则超时时长为20s,后台则相对长一些,200s
<pre language="javascript" code_block="true">void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
到此,Anr机制在监控Service startService时的第一步已经迈出了,那就是,埋入一个延时消息(延时炸弹)。那么埋入了延时炸弹干什么呢?当然是为了能够在有效时间内解除这个炸弹咯。如果这个炸弹最终在延时时间内没有被移除,则Handler最终被dispatch到该消息的时候,不就触发了Anr了吗。这就是我们Anr的一个整体猜想。下面咱就验证一下这个想法吧。
在AS中的scheduleCreateService()方法,执行了bumpServiceExecutingLocked()之后,调用了app.thread.scheduleCreateService()这句话,跨进程调用到了发起startService这个进程中的ApplicationThread类,它是ActivityThread的内部类,通过Binder机制负责跨进程通信。下面是该类执行scheduleCreateService()的内容:
<pre language="javascript" code_block="true">//ApplicationThread 代码:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData(