最终在 AppErrors.appNotResponding() 中打印 log 信息、dump 栈信息、打印 CPU 信息。Broadcast Timeout
Android 的广播机制在接收到广播进行处理时,可能会出现 receiver 处理很慢从而影响后续 receiver 接收的情形。因此,Android 对广播的接收处理增加了一个限定时间,超出限定时间将触发 ANR。需要说明,广播超时值会出现在串行广播中。并行广播因为并不存在传输的依赖关系,所以不会发生广播超时。对于不同的广播存在两个限定时间:前台广播10s和后台广播60s。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java // How long we allow a receiver to run before giving up on it. static final int BROADCAST_FG_TIMEOUT = 10*1000; static final int BROADCAST_BG_TIMEOUT = 60*1000; ...... public ActivityManagerService(Context systemContext) { ...... mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); mHandler = new MainHandler(mHandlerThread.getLooper()); ...... // 创建广播队列,前台和后台 mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; ...... }
广播队列创建时会设置超时时间,接下来直接看下广播的处理过程。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { BroadcastRecord r; ...... // 处理并行广播 while (mParallelBroadcasts.size() > 0) { ...... } // 广播正在处理时,检查进程是否存活 if (mPendingBroadcast != null) { ...... } boolean looped = false; // 处理串行广播 do { ...... r = mOrderedBroadcasts.get(0); boolean forceReceive = false; // 如果广播处理超时,强行结束它 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } ...... if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { if (r.resultTo != null) { try { // 处理完广播,发送最终结果 performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); r.resultTo = null; ...... } // 撤销 BROADCAST_TIMEOUT_MSG 消息 cancelBroadcastTimeoutLocked(); .... } } while (r == null); // 获取下一个广播 int recIdx = r.nextReceiver++; r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { // 在 receiver 启动时开启跟踪 r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); ...... } if (! mPendingBroadcastTimeoutMessage) { // 设置广播超时时间,发送 BROADCAST_TIMEOUT_MSG long timeoutTime = r.receiverTime + mTimeoutPeriod; setBroadcastTimeoutLocked(timeoutTime); } final BroadcastOptions brOptions = r.options; final Object nextReceiver = r.receivers.get(recIdx); // 处理动态注册的广播 if (nextReceiver instanceof BroadcastFilter) { ...... } // 处理静态注册的广播 ResolveInfo info = (ResolveInfo)nextReceiver; ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); .... // 获取 receiver 对应的进程 String targetProcess = info.activityInfo.processName; ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false); ...... // 如果相应进程存在,直接进行处理 if (app != null && app.thread != null && !app.killed) { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app, skipOomAdj); return; } catch (RemoteException e) { } catch (RuntimeException e) {. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } } // 如果相应进程不存在,则创建进程 if ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx; }
上述代码是广播处理的简单流程,与 ANR 触发相关的主要是两个地方,
- 设置广播超时的消息,setBroadcastTimeoutLocked()
- 撤销广播超时消息,cancelBroadcastTimeoutLocked()
在开始处理一个广播时,会根据超时时间来设置一个延迟发送的消息。在限定时间内,如果该消息没有被撤销就会触发 ANR。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { // 发送延迟消息 BROADCAST_TIMEOUT_MSG Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; } }
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java private final class BroadcastHandler extends Handler { public BroadcastHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { .... case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } } ...... final void broadcastTimeoutLocked(boolean fromMsg) { ...... long now = SystemClock.uptimeMillis(); BroadcastRecord r = mOrderedBroadcasts.get(0); if (fromMsg) { ...... long timeoutTime = r.receiverTime + mTimeoutPeriod; if (timeoutTime > now) { // 如果当前时间没有达到限定时间,重新设置超时消息 setBroadcastTimeoutLocked(timeoutTime); return; } } BroadcastRecord br = mOrderedBroadcasts.get(0); if (br.state == BroadcastRecord.WAITING_SERVICES) { // 广播已经处理完,正在等待 service 执行。继续处理下一条广播 br.curComponent = null; br.state = BroadcastRecord.IDLE; processNextBroadcast(false); return; } ...... // 获取 APP 进程 if (curReceiver != null && curReceiver instanceof BroadcastFilter) { BroadcastFilter bf = (BroadcastFilter)curReceiver; if (bf.receiverList.pid != 0 && bf.receiverList.pid != ActivityManagerService.MY_PID) { synchronized (mService.mPidsSelfLocked) { app = mService.mPidsSelfLocked.get( bf.receiverList.pid); } } } else { app = r.curApp; } ...... // 继续处理下一条广播 finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); if (!debugging && anrMessage != null) { // 触发 ANR mHandler.post(new AppNotResponding(app, anrMessage)); } }
在广播处理完成时会撤销超时消息。
final void cancelBroadcastTimeoutLocked() { if (mPendingBroadcastTimeoutMessage) { mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); mPendingBroadcastTimeoutMessage = false; } }
Service Timeout
Service Timeout 发生在 Service 的启动过程中,如果在限定时间内无法完成启动就会触发 ANR。根据 Service 类型的不同,赋予前台服务和后台服务不同的超时时间。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java // How long we wait for a service to finish executing. static final int SERVICE_TIMEOUT = 20*1000; // How long we wait for a service to finish executing. static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
在 Service 的启动过程中,会根据限定时间来设置一个延迟消息,用来触发启动超时。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { ...... scheduleServiceTimeoutLocked(r.app); ...... } ...... private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ...... r.app = app; r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); final boolean newService = app.services.add(r); bumpServiceExecutingLocked(r, execInFg, "create"); // 发送超时消息 mAm.updateLruProcessLocked(app, false, null); // 更新 LRU updateServiceForegroundLocked(r.app, /* oomAdj= */ false); mAm.updateOomAdjLocked(); // 更新 OOM ADJ boolean created = false; try { ...... mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); // 最终执行服务的 onCreate() 方法 app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); r.postNotification(); created = true; ...... } ...... 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); }
当服务启动超时,会向 AMS 发送一个 SERVICE_TIMEOUT_MSG 消息。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 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: { mServices.serviceTimeout((ProcessRecord)msg.obj); } break; ...... } } };
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java void serviceTimeout(ProcessRecord proc) { String anrMessage = null; synchronized(mAm) { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } final long now = SystemClock.uptimeMillis(); final long maxTime = now - (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); ServiceRecord timeout = null; long nextTime = 0; for (int i=proc.executingServices.size()-1; i>=0; i--) { // 寻找超时的服务 ...... } if (timeout != null && mAm.mLruProcesses.contains(proc)) { // 服务超时,生成超时信息 ...... mAm.mHandler.removeCallbacks(mLastAnrDumpClearer); mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS); anrMessage = "executing service " + timeout.shortName; } else { // 服务未超时,重置超时信息 Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT)); } } if (anrMessage != null) { // 触发 ANR mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage); } }
上面描述了 Service Timeout 的产生过程,如果想避免超时消息的产生,就需要在限定时间内将消息移除。移除操作在服务启动完成后进行,下面看一下真正进行服务启动的代码。
frameworks/base/core/java/android/app/ActivityThread.java private void handleCreateService(CreateServiceData data) { unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { // 创建 service java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); ...... try { // 创建ContextImpl对象 ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service); // 创建Application对象 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 { // 服务启动完成 ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); ...... }
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { r.executeNesting--; if (r.executeNesting <= 0) { if (r.app != null) { r.app.execServicesFg = false; r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { // 当前进程中没有正在执行的 service 时,移除服务超时消息 mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); ......