大概
Android的ANR告急有两种方式:
1. 通过handler的耽误机制触发ANR
2. Input事故触发ANR
Service、BroadcastReceiver、ContentProvider都是通过Hander机制触发ANR。
ANR的发生的场景有:
- service timeout:前台服务在20s未实行完,配景服务200s未实行完。
- BroadcastQueue timeout:前台广播在10s未实行完,配景广播在60s未实行完。
- ContentProvider timeout: ContentProvider在发布时凌驾10s未实行完。
- InputDispatching Timeout:输入分发事故凌驾5s未实行完。
ANR的过程总体就是:装炸弹、拆炸弹、引爆炸弹
1. Service Timeout
在文章startService启动流程可以知道Service的生命周期和启动流程。
装弹
在ActiveServices.realStartServiceLocked()方法中开始真正实行Service的生命周期方法,并开始装炸弹的开始。
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { // handle发送耽误消息,假如在规定时间还没有被取消,则证明方法实行时间长,则抛ANR非常。 bumpServiceExecutingLocked(r, execInFg, "create"); //... try { //调用Service对应onCreate()方法 app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.getReportedProcState()); } catch (DeadObjectException e) { mAm.appDiedLocked(app, "Died when creating service"); throw e; } finally { //... } }// 通过Handler发送耽误时间,到时间内没被取消则抛ANR非常private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { .... // 发送Handler scheduleServiceTimeoutLocked(r.app); } // 发送耽误消息 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; //当超时后仍没有remove该SERVICE_TIMEOUT_MSG消息,则实行service Timeout流程 mAm.mHandler.sendMessageDelayed(msg, proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); } static final int SERVICE_TIMEOUT = 20 * 1000; static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;在实行生命周期的方法前会通过bumpServiceExecutingLocked()方法举行装炸弹,通过Handler机制发送一个标记为SERVICE_TIMEOUT_MSG的耽误消息,假如是前台则20s,是配景则200s实行。
拆弹
在实行完Service的生命周期方法后就会实行拆弹,比如onCreate()方法在Application.handleCreateService()实行完毕:
private class ApplicationThread extends IApplicationThread.Stub { // 创建对应的Service并实行onCreate()方法 private void handleCreateService(CreateServiceData data) { try { .... // 调用service.attach绑定资源文件 service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); // 调用 service.onCreate()方法 service.onCreate(); try { // onCreate()实行完成,拆弹过程,终极调用到ActiveServices.serviceDoneExecutingLocked方法 ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { //... } } // AMS public void serviceDoneExecuting(IBinder token, int type, int startId, int res) { synchronized (this) { if (!(token instanceof ServiceRecord)) { Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token); throw new IllegalArgumentException("Invalid service token"); } mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res); } } // ActiveServices private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { //... // 取消SERVICE_TIMEOUT_MSG消息,拆出炸弹 mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); //... }假如在生命周期方法内实行完,会回调AMS的方法,排除SERVICE_TIMEOUT_MSG耽误发送的消息。
引爆弹
假如Service方法在规定时间内没有实行完成,则会实行AMS.MainHandler的SERVICE_TIMEOUT_MSG类型的消息:
// AMS final class MainHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { mServices.serviceTimeout((ProcessRecord) msg.obj); } break; } } } // ActiveServices void serviceTimeout(ProcessRecord proc) { // 假如超时,调用appNotResponding()方法 if (anrMessage != null) { mAm.mAnrHelper.appNotResponding(proc, anrMessage); } }假如超时则会触发ANR,调用mAm.mAnrHelper.appNotResponding()方法。
2. BroadcastReceiver Timeout
装弹
在文章广播的注册、发送原理流程可以相识,发送广播后调用之行对应的广播接收器的方法,对应的方法在BroadcastQueue.processNextBroadcast():
public final class BroadcastQueue { final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { BroadcastRecord r; // 处理惩罚当前有序广播 do { // 获取BroadcastRecord final long now = SystemClock.uptimeMillis(); r = mDispatcher.getNextBroadcastLocked(now); //当广播处理惩罚时间超时,则欺压竣事这条广播 if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) { if ((numReceivers > 0) && (now > r.dispatchTime + (2 * mConstants.TIMEOUT * 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) { //... //处理惩罚广播消息消息,调用到onReceive() performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); //... } //拆炸弹 cancelBroadcastTimeoutLocked(); r = null; looped = true; continue; } //.. } while (r == null); //获取下一个receiver的index int recIdx = r.nextReceiver++; if (!mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; //装炸弹,设置广播超时时间,发送BROADCAST_TIMEOUT_MSG setBroadcastTimeoutLocked(timeoutTime); } //... } // 装弹 final void setBroadcastTimeoutLocked(long timeoutTime) { if (!mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; } } }通过setBroadcastTimeoutLocked()方法举行装弹。
拆弹
通过上面的processNextBroadcastLocked()方法可知,调用cancelBroadcastTimeoutLocked()举行拆弹。
// 拆弹 final void cancelBroadcastTimeoutLocked() { if (mPendingBroadcastTimeoutMessage) { mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); mPendingBroadcastTimeoutMessage = false; } }引爆弹
通过BroadcastHandler的BROADCAST_TIMEOUT_MSG类型的消息的实行,举行引爆炸弹。
public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { // 调用broadcastTimeoutLocked()方法 broadcastTimeoutLocked(true); } } break; } } final void broadcastTimeoutLocked(boolean fromMsg) { ... // 假如超时,调用AMS.mAnrHelper.appNotResponding if (!debugging && anrMessage != null) { mService.mAnrHelper.appNotResponding(app, anrMessage); } }末了也是调用AMS.mAnrHelper.appNotResponding()方法
3. ContentProvider Timeout
装弹
ContentProvider的注册在启动历程的时间就开始实行,在注册的过程中会向AMS绑定Application,假如有ContentProvider就装弹,方法在AMS.attachApplicationLocked()方法中:
// AMS private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { //... boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List<roviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null; if (providers != null && checkAppInLaunchingProvidersLocked(app)) { // 装弹 Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS); } } public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000;在绑定Application时,会判断是否有ContentProvider时会装炸弹举行一个CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息的耽误发送。
拆弹
在AT.installContentProviders()安装完后会调用AMS.publishContentProviders()方法举行拆弹。
public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { ... // 拆弹,移除CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息 mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r) }引爆弹
假如消息没被移除则引爆炸弹,CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG的handler在AMS.MainHandler中,
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; } } private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) { //移除殒命的provider cleanupAppInLaunchingProvidersLocked(app, true); //移除mProcessNames中的相应对象 mProcessList.removeProcessLocked(app, false, true, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, ApplicationExitInfo.SUBREASON_UNKNOWN, "timeout publishing content providers"); }4. InputDispatching Timeout
InputReader 不绝的从EventHub中监听是否有Input事故,InputReader把事故分发给InputDispatcher。
InputDispatcher调用dispatchOnce()方法开始把事故分发给对应的View,就从InputDispatcher的分发开始监控ANR,InputDispatcher的ANR区间是查找窗口findFocusedWindowTargetsLocked()方法到resetANRTimeoutsLocked()重置方法。
void InputDispatcher::dispatchOnce() { ... // 调用dispatchOnceInnerLocked举行分析 dispatchOnceInnerLocked(&nextWakeupTime); } void InputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime) { nsecs_t currentTime = now(); // ... // 重置标记 resetANRTimeoutsLocked(); switch (mPendingEvent -> type) { case EventEntry::TYPE_KEY: { ... // key类型 done = dispatchKeyLocked(currentTime, typedEntry, & dropReason, nextWakeupTime); break; } case EventEntry::TYPE_MOTION: { ... done = dispatchMotionLocked(currentTime, typedEntry, & dropReason, nextWakeupTime); break; } default: ALOG_ASSERT(false); break; } } void InputDispatcher::resetANRTimeoutsLocked() { // 将mInputTargetWaitCause设置为INPUT_TARGET_WAIT_CAUSE_NONE mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; mInputTargetWaitApplicationToken.clear(); }在分发之前会调用resetANRTimeoutsLocked()方法,重置mInputTargetWaitCause标记为:INPUT_TARGET_WAIT_CAUSE_NONE。接着根据下发的类型,探求对应的窗口,比如KEY类型,则调用dispatchKeyLocked()方法。
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry*entry, DropReason*dropReason, nsecs_t*nextWakeupTime) { // 探求目标窗口 int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); // 给目标窗口分发事故 dispatchEventLocked(currentTime, entry, inputTargets); return true; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry*entry, std::vector<InputTarget>&inputTargets, nsecs_t*nextWakeupTime) { ... // 查抄窗口不能input的缘故起因 reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused"); if (!reason.empty()) { // 调用handleTargetsNotReadyLocked()方法 injectionResult = handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } ... return injectionResult; } int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,const EventEntry*entry,const sp<InputApplicationHandle>&applicationHandle,const sp<InputWindowHandle>&windowHandle, nsecs_t*nextWakeupTime, const char*reason) { // 在resetANRTimeoutsLocked方法中,mInputTargetWaitCause为INPUT_TARGET_WAIT_CAUSE_NONE if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { // DEFAULT_INPUT_DISPATCHING_TIMEOUT为5s nsecs_t timeout; if (windowHandle != nullptr) { timeout = windowHandle -> getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != nullptr) { timeout = applicationHandle -> getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } // 要等到下次调用resetANRTimeoutsLocked时才能进 mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; // 当前时间加上5s mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationToken.clear(); } if (mInputTargetWaitTimeoutExpired) { return INPUT_EVENT_INJECTION_TIMED_OUT; } if (currentTime >= mInputTargetWaitTimeoutTime) { // 当前时间凌驾设定的5s,后实行onANRLocked()的ANR方法 onANRLocked(currentTime, applicationHandle, windowHandle, entry -> eventTime, mInputTargetWaitStartTime, reason); return INPUT_EVENT_INJECTION_PENDING; } else { // Force poll loop to wake up when timeout is due. if (mInputTargetWaitTimeoutTime < *nextWakeupTime){ *nextWakeupTime = mInputTargetWaitTimeoutTime; } return INPUT_EVENT_INJECTION_PENDING; } }在分发一次事故时,会调用resetANRTimeoutsLocked将标记为INPUT_TARGET_WAIT_CAUSE_NONE,以是第一次事故会设置一个5s后的超时时间,并把标记设置为INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,假如下次事故来临时当前的时间凌驾前次设置的5s时间就会调用onANRLocked()方法产生ANR。
void InputDispatcher:nANRLocked( nsecs_t currentTime, const sp<InputApplicationHandle>&applicationHandle, const sp<InputWindowHandle>&windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char*reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; // 网络ANR现场信息 time_t t = time(nullptr); struct tm tm; localtime_r( & t, &tm); char timestr[ 64]; strftime(timestr, sizeof(timestr), "%F %T", & tm); mLastANRState.clear(); mLastANRState += INDENT "ANR:\n"; mLastANRState += StringPrintf(INDENT2"Time: %s\n", timestr); mLastANRState += StringPrintf(INDENT2"Window: %s\n", getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); mLastANRState += StringPrintf(INDENT2"DispatchLatency: %0.1fms\n", dispatchLatency); mLastANRState += StringPrintf(INDENT2"WaitDuration: %0.1fms\n", waitDuration); mLastANRState += StringPrintf(INDENT2"Reason: %s\n", reason); //dump信息 dumpDispatchStateLocked(mLastANRState); //将ANR下令参加commandQueue CommandEntry * commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); commandEntry -> inputApplicationHandle = applicationHandle; commandEntry -> inputChannel = windowHandle != nullptr ? getInputChannelLocked(windowHandle -> getToken()) : nullptr; commandEntry -> reason = reason; }在下次实行InputDispatcher.dispatchOnce时会先实行commandQueue的队列下令,这里把InputDispatcher::doNotifyANRLockedInterruptible放入到了队列。
void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry*commandEntry) { mLock.unlock(); //mPolicy是指NativeInputManager nsecs_t newTimeout = mPolicy -> notifyANR( commandEntry -> inputApplicationHandle, commandEntry -> inputChannel ? commandEntry -> inputChannel -> getToken() : nullptr, commandEntry -> reason); mLock.lock(); resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry -> inputChannel); }mPolicy -> notifyANR通过JNI终极调用到InputManagerService.notifyANR()方法:
// InputManagerService private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, token, reason); }这里的mWindowManagerCallbacks是InputManagerCallback对象
//InputManagerCallback public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { final long startTime = SystemClock.uptimeMillis(); try { return notifyANRInner(inputApplicationHandle, token, reason); } finally { } } private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { ... // 调用AMS的inputDispatchingTimedOut()方法 long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, reason); return 0; // abort dispatching }终极调用到AMS.inputDispatchingTimedOut()方法
// AMS long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " + FILTER_EVENTS); } ProcessRecord proc; long timeout; synchronized (this) { synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid); } timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS; } // 调用inputDispatchingTimedOut if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) { return -1; } return timeout; } boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String reason) { // 调用appNotResponding方法 mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo, parentShortComponentName, parentProcess, aboveSystem, annotation); return true; }还是实行appNotResponding()方法。 |