一、前言
在Service组件StartService()方式启动流程分析文章中,针对Context#startService()启动Service流程分析了源码,其实关于Service启动还有一个比较重要的点是Service启动的ANR,因为因为线上出现了上百例的"executing service " + service.shortName的异常。
二、Service-ANR原理
2.1 Service启动ANR原理简述
Service的ANR触发原理,是在启动Service前使用Handler发送一个延时的Message(埋炸弹过程),然后在Service启动完成后remove掉这个Message(拆炸弹过程)。如果在指定的延迟时间内没有remove掉这个Message,那么就会触发ANR(没有在炸弹爆炸前拆掉就会爆炸),弹出AppNotResponding的弹窗。
其实这个机制跟Windows/MacOS的应用程序无响应,是类似的交互设计。
2.2 Service启动ANR源码执行过程
ps: 还是基于Android SDK28源码分析
基于文章:Service组件StartService()方式启动流程分析的总结,我们已经很清楚,通过startService的方式启动Service的源码过程。因此,本文直接从com.android.server.am.ActiveServices#bringUpServiceLocked方法的源码开始分析,如有不清楚前置的启动流程的同学,可以参考我之前的文章,然后打开AS对照看下这部分的代码。
2.2.1 ActiveServices#bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
realStartServiceLocked(r, app, execInFg);
}
2.2.2 ActiveServices#realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
// ...
// 会转调到scheduleServiceTimeoutLocked(r.app)方法进行埋炸弹操作
bumpServiceExecutingLocked(r, execInFg, "create");
try {
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
} catch (DeadObjectException e) {
mAm.appDiedLocked(app);
throw e;
} finally {
// serviceDoneExecutingLocked方法内会拆除炸弹
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
// ...
}
}
2.2.4 埋炸弹过程:ActiveServices#bumpServiceExecutingLocked
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
// ...
scheduleServiceTimeoutLocked(r.app);
// ...
}
- com.android.server.am.ActiveServices#scheduleServiceTimeoutLocked
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);
}
2.2.4 拆炸弹过程:ActiveServices#serviceDoneExecutingLocked
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
// ...
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
// ...
}