ContentProvider Timeout
ContentProvider Timeout 发生在应用启动过程中。如果应用启动时,Provider 发布超过限定时间就会触发 ANR。应用进程创建后,会调用 attachApplicationLocked() 进行初始化。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java // How long we wait for an attached process to publish its content providers // before we decide it must be hung. static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000; ...... private final boolean attachApplicationLocked(IApplicationThread thread, int pid, int callingUid, long startSeq) { ...... // 如果应用存在 Provider,设置延迟消息处理 Provider 超时 if (providers != null && checkAppInLaunchingProvidersLocked(app)) { Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT); } ...... }
当在限定时间内没有完成 Provider 发布时,会发送消息 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,Handler 会进行相应处理。
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 CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: { // 处理 Provider 超时消息 ProcessRecord app = (ProcessRecord)msg.obj; synchronized (ActivityManagerService.this) { processContentProviderPublishTimedOutLocked(app); } } break ...... } } ...... boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) { final String name = app.processName; final int uid = app.uid; ...... // 移除mProcessNames中的相应对象 removeProcessNameLocked(name, uid); ...... boolean needRestart = false; if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) { int pid = app.pid; if (pid > 0) { // 杀进程前处理一些相关状态 ...... } // 判断是否需要重启进程 boolean willRestart = false; if (app.persistent && !app.isolated) { if (!callerWillRestart) { willRestart = true; } else { needRestart = true; } } app.kill(reason, true); // 杀死进程 handleAppDiedLocked(app, willRestart, allowRestart); // 回收资源 if (willRestart) { removeLruProcessLocked(app); addAppLocked(app.info, null, false, null /* ABI override */); } } else { mRemovedProcesses.add(app); } return needRestart; } ...... private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) { // 清理 Provider cleanupAppInLaunchingProvidersLocked(app, true); // 清理应用进程 removeProcessLocked(app, false, true, "timeout publishing content providers"); } ...... boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) { boolean restart = false; for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) { ContentProviderRecord cpr = mLaunchingProviders.get(i); if (cpr.launchingApp == app) { if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) { restart = true; } else { // 移除死亡的 Provider removeDyingProviderLocked(app, cpr, true); } } } return restart; }
可以看到 ContentProvider Timeout 发生时并没有调用 AMS.appNotResponding() 方法,仅仅杀死问题进程及清理相关信息。Provider 的超时消息会在发布成功时被清除,相关代码如下。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { ...... synchronized (this) { final ProcessRecord r = getRecordForAppLocked(caller); ...... final int N = providers.size(); for (int i = 0; i < N; i++) { ContentProviderHolder src = providers.get(i); ...... ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (dst != null) { ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); mProviderMap.putProviderByClass(comp, dst); ...... if (wasInLaunchingProviders) { // 移除超时消息 mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); } ...... } } Binder.restoreCallingIdentity(origId); } }