公众号:代码与生活手记,持续分享Android进阶知识,App性能优化,Framework学习,应用架构设计
文章基于Android14,目录:
- 埋炸弹(开启定时检测任务)
- 拆炸弹(取消定时任务)
- 引爆炸弹(执行消息)
- 有用的日志
众所皆知,Service主要有两类:
- 前台服务,则超时为
SERVICE_TIMEOUT = 20s;
- 后台服务,则超时为
SERVICE_BACKGROUND_TIMEOUT = 200s
源码中的定义:
java
private static final long DEFAULT_SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
private static final long DEFAULT_SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_TIMEOUT * 10;
埋炸弹(开启定时检测任务)
Service
一般会通过Context
的startService
启动,然后通过AMS一路走到system_server
进程,最后一路走到ActiveServices
(不同版本可能不一样)的 realStartServiceLocked()
方法来埋下炸弹.
java
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
.......
// 开启anr定时任务
bumpServiceExecutingLocked(r, execInFg, "create",
OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);
try {
......
//启动service
thread.scheduleCreateService(r, r.serviceInfo,
null /* compatInfo (unused but need to keep method signature) */,
app.mState.getReportedProcState());
created = true;
}
.......
}
首先会调用bumpServiceExecutingLocked
方法来开启一个SERVICE_TIMEOUT_MSG
定时任务
java
private boolean bumpServiceExecutingLocked(
ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason) {
.......
scheduleServiceTimeoutLocked(r.app);
......
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
}
总结: 1、在启动Service
之前启动一个SERVICE_TIMEOUT_MSG
的定时任务,用来检测ANR
2、该任务会根据Service
是否是前后台进程,定义不同的ANR时间
拆炸弹(取消定时任务)
在启动 Service
过程中,会经过一系列的调用,走回到应用进程的 ActivityThread
的 handleCreateService
方法,如下:
java
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
Service service = null;
try {
.......
context.setOuterContext(service);
// 执行Service的创建和attach
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
......
service.onCreate();
.......
try {
// service启动完成
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
.......
}
这里通过 AMS
又回到了 system_server
中的 serviceDoneExecuting
,如下:
java
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing, boolean enqueueOomAdj, @OomAdjReason int oomAdjReason) {
.......
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
.......
}
总结: 1、system_server
中经过一系列的调用,回到应用进程的 ActivityThread
的 handleCreateService
方法。这个方法创建Service
对象,并调用onCreate
方法 2、Service
执行完成后,就会调用serviceDoneExecuting
通知AMS执行完成,最终会取消SERVICE_TIMEOUT_MSG
任务
注意:这里处理 Handler 对应的线程用的是 AMS 中的
HandlerThread
,和广播用的是同一个线程
引爆炸弹(执行消息)
如果我们没有及时的取消 SERVICE_TIMEOUT_MSG
任务,时间到了之后,就会执行该消息,如下:
java
public void handleMessage(Message msg) {
switch (msg.what) {
.......
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord) msg.obj);
} break;
最终还是调用了 ActiveServices
的 serviceTimeout
方法
java
void serviceTimeout(ProcessRecord proc) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceTimeout()");
TimeoutRecord timeoutRecord = null;
synchronized (mAm) {
......
// 打印timeout日志
if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, " ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer,
LAST_ANR_LIFETIME_DURATION_MSECS);
String anrMessage = "executing service " + timeout.shortInstanceName;
timeoutRecord = TimeoutRecord.forServiceExec(anrMessage);
} ......
}
// 处理anr信息的收集
if (timeoutRecord != null) {
mAm.mAnrHelper.appNotResponding(proc, timeoutRecord);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
总结: 1、如果任务 SERVICE_TIMEOUT_MSG
没有取消,则会执行该任务 2、调用调用了 ActiveServices
的 serviceTimeout
方法,打印 Timeout executing service
日志 3、调用 mAm.mAnrHelper.appNotResponding
收集 ANR 信息
涉及的日志
Timeout executing service
日志打印 这里的 timeout
是一个 ServiceRecord
对象,这个时间是最接近 anr 的发生时间的。
java
Slog.w(TAG, "Timeout executing service: " + timeout);
ANR系列文章 : 性能优化之ANR系列-BroadCastReceiver ANR原理 ANR系列之-ContentProvider为什么ANR?
欢迎阅读和关注ANR系列