ANR,Application Not responding,也就是应用程序未响应。
Android 系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间不能得到响应或者响应时间过长,都会造成ANR。
所有与 ANR 相关的消息,都会经过系统进程 system_server
来调度,然后派发到应用进程完成对消息的实际处理, 一旦应用程序处理消息超时,系统就会收集一些系统状态,如 CPU/IO 使用情况、进程函数调用栈,并且报告用户有进程出现 ANR 了,同时会弹出 ANR 的对话框。
ANR机制可以分为两部分:
Android 是通过 Handler 机制设置定时消息来实现检测 Service 超时的。
Service 运行在应用程序的主线程,如果在前台进程中执行 Service ,时间超过 20 秒,则会引发ANR,如果在后台进程中执行 Service ,时间超过 200 秒,则会引发ANR。
如何检测 Service 的 ANR 问题,分为两步:
那么 Service 发生 ANR 的原理是怎样的呢,下面我们将从源码角度上进行分析。
下面我们先分析 Service 的启动流程。
// 点击按钮 - 启动服务
fun clickToBindService(view: View) {
Intent(this, MyNewService::class.java).also {
startService(it)
}
}
点击按钮启动服务的方法中,调用了 startService 方法来启动一个 Service,跟踪该方法,会调用到 ContextImpl.startService
中:
// ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
进而继续执行 ContextImpl.startServiceCommon
方法:
// ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
// …………………………………………………………………………………………………………………………………………………………………………………………
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
// …………………………………………………………………………………………………………………………………………………………………………………………
}
ContextImpl.startServiceCommon
方法中可以看到,执行了 ActivityManagerService,即 AMS
的 startService
方法,跟踪该方法:
// ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
UserHandle user) {
// …………………………………………………………………………………………………………………………………………………………………………………………
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
UserHandle user) {
// …………………………………………………………………………………………………………………………………………………………………………………………
return res;
}
}
可见,调用了 mServices.startServiceLocked
方法,而这个 mServices 则是一个 ActiveServices 对象,因此,代码继续执行 ActiveServices.startServiceLocked
方法:
// ActivityService.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
callingPackage, callingFeatureId, userId, false, null);
}
在 ActivityService 中,经过一系列的调用,会执行到 ActivityService.realStartServiceLocked
方法
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
// ............................................................
// 设置ANR超时,可见在正式启动 Service之前,会开始 ANR 的监测
bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
// ............................................................
// 启动 Service
thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.mState.getReportedProcState());
// ............................................................
// 调动 Service 的其他方法,如 onStartCommand
sendServiceArgsLocked(r, execInFg, true);
}
在 realStartServiceLocked 方法中,执行到了 ApplicationThread.scheduleCreateService
方法(这里就不看了),最终又会执行到 ActivityThread.scheduleCreateService
方法,如下:
// ActivityThread.java
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;
// 通过 handler 发送创建 Service 的消息
sendMessage(H.CREATE_SERVICE, s);
}
在 ActivityThread.scheduleCreateService
方法中,会通过 handler 发送一个创建 Service 的消息:CREATE_SERVICE,当接收到这个消息时,会执行 ActivityThread.handleCreateService
方法,最终会执行到 service.onCreate()
方法,进而执行 Service 的声明周期,如下所示:
// ActivityThread.java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
// ..........................................
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj);
break;
}
// ..........................................
}
// 最终执行到这里,调用 service.onCreate() 方法
private void handleCreateService(CreateServiceData data) {
// ..........................................
service.onCreate();
// ..........................................
}
以上就是 Service 的启动流程了,整体还是比较清晰的。
Service 超时监测机制可以从 Service 启动流程中找到。
在上述 Service 启动流程中,我们跟踪执行到了 ActivityService.realStartServiceLocked
方法,在该方法中,通过调用 bumpServiceExecutingLocked
方法来开始监测 ANR,代码如下:
// ActivityService.java:
private boolean bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why,
@Nullable String oomAdjReason) {
// ..........................................
scheduleServiceTimeoutLocked(r.app);
// ..........................................
}
bumpServiceExecutingLocked
方法会继续调用到 scheduleServiceTimeoutLocked
方法:
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;
// 延时指定时间后,发送消息:SERVICE_TIMEOUT_MSG
// 前台进程中执行 Service,SERVICE_TIMEOUT = 20s
// 后台进程中执行 Service,SERVICE_BACKGROUND_TIMEOUT = 200s
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
如果在指定的时间内没有将 SERVICE_TIMEOUT_MSG 这个消息 remove 掉,则该消息会在 ActivityManagerService 中处理:
// ActivityManagerService.java:
final class MainHandler extends Handler {
// ..........................................
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// ..........................................
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord) msg.obj);
} break;
case SERVICE_FOREGROUND_TIMEOUT_MSG: {
mServices.serviceForegroundTimeout((ServiceRecord) msg.obj);
} break;
// ..........................................
}
}
这里我们看到,会调用 mServices.serviceTimeout()
方法,而 mServices 指的是 ActivityService,因此我们进入 ActivityService.serviceTimeout
方法中:
// ActivityService.java:
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
if (proc.isDebugging()) {
// 应用程序正在调试,忽略超时
return;
}
final ProcessServiceRecord psr = proc.mServices;
if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null) {
return;
}
final long now = SystemClock.uptimeMillis();
final long maxTime = now -
(psr.shouldExecServicesFg() ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
// 遍历所有正在执行的服务,寻找运行超时的 Service
for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
ServiceRecord sr = psr.getExecutingServiceAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
// 判断执行 Service 超时的进程是否在最近运行进程列表,如果不在,则忽略这个ANR
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);
anrMessage = "executing service " + timeout.shortInstanceName;
} else {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
}
}
// 当存在timeout的service,则执行appNotResponding,报告ANR
if (anrMessage != null) {
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
可见,在该方法的最后,如果存在 ANR,则会执行到 AnrHelper.appNotResponding
方法来报告一个 ANR。
以上就是本文的所有内容,下一篇文章将会继续从源码的角度上探究 输入事件处理超时 引入的 ANR 原理。