关于Service的ANR场景还是比较少见的,它的ANR设计原理也是比较简单,在很多监控的方案中都可以看得到
通过查阅Android官方文档,我们知道出现以下任何情况,系统都会针对我们的应用触发ANR:
在了解Service触发ANR之前,要先了解Service的工作机制
Service的启动过程分为两种
两种启动方式最终的调用链都来到ActiveServices.realStartServiceLocked()
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
......
// 1.发送delay消息(SERVICE_TIMEOUT_MSG)
bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
try {
// 2.创建Service对象,并且调用onCreate()
thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.mState.getReportedProcState());
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
......
}
......
}
private boolean bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why,
@Nullable String oomAdjReason) {
......
scheduleServiceTimeoutLocked(r.app);
......
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
ActiveServices.realStartServiceLocked()
做了两个事情
mHandler
发送延时消息,在这里将会埋下炸弹Service
的onCreate()
从发送的延时时间可以看出,Service的炸弹是指前台服务Timeout时间为20s,后台服务Timeout时间是前台服务的10倍,200s
static final int SERVICE_TIMEOUT = 20*1000;
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
Service正常运行情况下,最终会执行到ActivityThread
的handleCreateService
方法
private void handleCreateService(CreateServiceData data) {
......
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
......
}
在ActiveServices
我们找到了这个移除SERVICE_TIMEOUT_MSG
消息的方法serviceDoneExecutingLocked
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing, boolean enqueueOomAdj) {
......
if (psr.numberOfExecutingServices() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortInstanceName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
......
}
在创建Service之前如果消息没被移除,也就代表着Service没有被顺利的执行下来,就会导致Handler
去处理当前的Timeout消息
final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null , true);
}
@Override
public void handleMessage(Message msg) {
...
// 1.处理消息
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord) msg.obj);
}
...
}
}
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
......
if (anrMessage != null) {
// 2.触发ANR弹窗
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
appNotResponding
方法内会开始生成trace文件等信息,然后通过ActivityManagerService
的mUiHandler
发送SHOW_NOT_RESPONDING_UI_MSG
展示ANR弹窗