ANR(Application Not responding),是指應用程序未響應,Android系統對於一些事件須要在必定的時間範圍內完成,若是超過預約時間能未能獲得有效響應或者響應時間過長,都會形成ANR。java
形成ANR的場景:app
觸發ANR的過程可分爲三個步驟: 埋炸彈, 拆炸彈, 引爆炸彈ide
<1> Service Timeout是位於」ActivityManager」線程中的AMS.MainHandler收到SERVICE_TIMEOUT_MSG
消息時觸發。post
對於Service有兩類:this
由變量ProcessRecord.execServicesFg來決定是否前臺啓動.spa
埋炸彈階段:在Service進程attach到system_server進程的過程當中會調用realStartServiceLocked()
方法 (準確說是scheduleServiceTimeoutLocked方法) 中來埋下炸彈.線程
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ... //發送delay消息(SERVICE_TIMEOUT_MSG), bumpServiceExecutingLocked(r, execInFg, "create"); try { ... //最終執行服務的onCreate()方法 app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); } catch (DeadObjectException e) { mAm.appDiedLocked(app); throw e; } finally { ... } }
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { ... scheduleServiceTimeoutLocked(r.app); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } long now = SystemClock.uptimeMillis(); Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; //當超時後仍沒有remove該SERVICE_TIMEOUT_MSG消息,則執行service Timeout流程 mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT)); }
拆炸彈階段:通過Binder等層層調用進入目標進程的主線程ActivityThread.handleCreateService()的過程. 在這個過程會建立目標服務對象,以及回調onCreate()方法, 緊接再次通過屢次調用回到system_server來執行serviceDoneExecuting.code
最終在serviceDoneExecutingLocked中移除服務超時消息SERVICE_TIMEOUT_MSG
。orm
private void handleCreateService(CreateServiceData data) { ... java.lang.ClassLoader cl = packageInfo.getClassLoader(); Service service = (Service) cl.loadClass(data.info.name).newInstance(); ... 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, ActivityManagerNative.getDefault()); //調用服務onCreate()方法 service.onCreate(); //拆除炸彈引線[見小節2.2.2] ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (Exception e) { ... } }
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { ... 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); ... } ...
引爆炸彈階段:在system_server進程中有一個Handler線程, 名叫」ActivityManager」.當倒計時結束便會向該Handler線程發送 一條信息SERVICE_TIMEOUT_MSG
,server
final class MainHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { ... //【見小節2.3.2】 mServices.serviceTimeout((ProcessRecord)msg.obj); } break; ... } ... } }
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--) { ServiceRecord sr = proc.executingServices.valueAt(i); if (sr.executingStart < maxTime) { timeout = sr; break; } if (sr.executingStart > nextTime) { nextTime = sr.executingStart; } } if (timeout != null && mAm.mLruProcesses.contains(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.shortName; } } if (anrMessage != null) { //當存在timeout的service,則執行appNotResponding mAm.appNotResponding(proc, null, null, false, anrMessage); } }
其中anrMessage的內容爲」executing service [發送超時serviceRecord信息]」;
<2> BroadcastReceiver Timeout是位於」ActivityManager」線程中的BroadcastQueue.BroadcastHandler收到BROADCAST_TIMEOUT_MSG
消息時觸發。
對於廣播隊列有兩個: foreground隊列和background隊列:
經過調用 BroadcastQueue.processNextBroadcast() 來處理廣播.其流程爲先處理並行廣播,再處理當前有序廣播,最後獲取並處理下條有序廣播.
final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { ... //part 2: 處理當前有序廣播 do { r = mOrderedBroadcasts.get(0); //獲取全部該廣播全部的接收者 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); ... } } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { if (r.resultTo != null) { //處理廣播消息消息 performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); r.resultTo = null; } //拆炸彈 cancelBroadcastTimeoutLocked(); } } while (r == null); ... //part 3: 獲取下條有序廣播 r.receiverTime = SystemClock.uptimeMillis(); if (!mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; //埋炸彈 setBroadcastTimeoutLocked(timeoutTime); } ... } }
對於廣播超時處理時機:
final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; } }
設置定時廣播BROADCAST_TIMEOUT_MSG,即當前日後推mTimeoutPeriod時間廣播還沒處理完畢,則進入廣播超時流程。
在processNextBroadcast()過程, 執行完performReceiveLocked,便會拆除炸彈.
final void cancelBroadcastTimeoutLocked() { if (mPendingBroadcastTimeoutMessage) { mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); mPendingBroadcastTimeoutMessage = false; } }
private final class BroadcastHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { //【見小節3.3.2】 broadcastTimeoutLocked(true); } } break; ... } ... } }
不會引爆的四種狀況
<3> ContentProvider Timeout是位於」ActivityManager」線程中的AMS.MainHandler收到CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息時觸發。
ContentProvider 超時爲CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s. 這個跟前面的Service和BroadcastQueue徹底不一樣, 由Provider進程啓動過程相關.
埋炸彈的過程 實際上是在進程建立的過程,進程建立後會調用attachApplicationLocked()進入system_server進程. 10s以後引爆該炸彈
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { ProcessRecord app; if (pid != MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); // 根據pid獲取ProcessRecord } } ... //系統處於ready狀態或者該app爲FLAG_PERSISTENT進程則爲true boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null; //app進程存在正在啓動中的provider,則超時10s後發送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息 if (providers != null && checkAppInLaunchingProvidersLocked(app)) { Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT); } thread.bindApplication(...); ... }
當provider成功publish以後,便會拆除該炸彈
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); //將該provider添加到mProviderMap String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.putProviderByName(names[j], dst); } int launchingCount = mLaunchingProviders.size(); int j; boolean wasInLaunchingProviders = false; for (j = 0; j < launchingCount; j++) { if (mLaunchingProviders.get(j) == dst) { //將該provider移除mLaunchingProviders隊列 mLaunchingProviders.remove(j); wasInLaunchingProviders = true; j--; launchingCount--; } } //成功pubish則移除該消息 if (wasInLaunchingProviders) { mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); } synchronized (dst) { dst.provider = src.provider; dst.proc = r; //喚醒客戶端的wait等待方法 dst.notifyAll(); } ... } } } }
在system_server進程中有一個Handler線程, 名叫」ActivityManager」.當倒計時結束便會向該Handler線程發送 一條信息CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
,
final class MainHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: { ... ProcessRecord app = (ProcessRecord)msg.obj; synchronized (ActivityManagerService.this) { processContentProviderPublishTimedOutLocked(app); } } break; ... } ... } }
總結:
當出現ANR時,都是會調用到AMS.appNotResponding()方法
Service超時檢測機制:
BroadcastReceiver超時檢測機制:
另外: