Android-Service-ANR-的监控机制,看完这篇彻底明白了

  1. Service 的 Anr监控机制都由那些重量级角色参与
  2. Service 的 Anr监控机制的建立流程是怎样的
  3. 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

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()的内容:

//ApplicationThread 代码:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;

sendMessage(H.CREATE_SERVICE, s);
}

//ActivityThread代码:
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);//类H,继承Handler,专门接收AMS调度过来的四大组件调度消息。
}

//H代码:
public void handleMessage(Message msg) {
switch (msg.what) {
。。。//省略
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
。。。//省略
}
}

//ActivityThread代码:
private void handleCreateService(CreateServiceData data) {
...//省略

try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);

Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();//调用onCreate()
mServices.put(data.token, service);
try {//跨进程传达service创建成功。
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}


由上面的核心代码片段可以看出,最终Service的创建流程会由sys_server进程中的AMS,跨进程调用ApplicationThread,在App进程通过Handler发送消息的形式,执行handleCreateService(),调用Service.onCreate()后,再跨进程通知AMSserviceDoneExecuting()。走到这里,Service在App进程就创建完毕了。onCreate()执行完成。

这一步的流程中,埋下的炸弹时间也在悄然流逝。我们继续往下看,接下来就看AMS中如何处理炸弹了。

AMS被调用到了serviceDoneExecuting() 方法后,会调用AS的serviceDoneExecutingLocked()。 在处理了Service.START_STICKY等各种乱七八糟的标记位之后,走到serviceDoneExecutingLocked()方法,这里真正执行到了“拆除炸弹"的过程,将此前埋入的延时消息remove。

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean fin

> **《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》**
>
> **【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享**

ishing) {
//省略...
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
//拆除炸弹!!!
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app, true);
}
r.executeFg = false;
if (r.tracker != null) {
r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
}
r.app = null;
}
}
}


那么问题来了,如果在调用mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);的时候发现没有该消息了会发生什么呢? 那其实就说明,mAm.mHandler 已经处理了该消息。我们进入到mAm.mHandler中去一探究竟,它收到该消息会做什么事情。

final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null, true);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//...省略
case SERVICE_TIMEOUT_MSG: {

你可能感兴趣的:(程序员,面试,移动开发,android)