ANR may be a relatively rare question in our daily development process. It can be seen from the assessment process that few students can answer it well. Since we will encounter it in development, we need to know at least how the Framework layer works. How does ANR monitor? How to analyze and solve ANR? These three dimensions.

ANR can be roughly divided into two types: the four component startup timeout and the Input response timeout. The underlying implementation principles of the four component startup timeout ANR are also somewhat different. The four component startup timeout ANR is a process of burying and defusing bombs, while the Input response timeout ANR is a process of mine clearance. I believe you can understand the principle of the four components startup timeout, but the Input response timeout may not be so, because it requires some C++ foundation.

1. Startup timeout ANR of the four components

We covered the Service startup process in detail in the Framework source analysis section. The realStartServiceLocked() method is called to bury the bomb while the Service attaches to the system_server process.

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ... / / send delay messages (SERVICE_TIMEOUT_MSG) bumpServiceExecutingLocked (r, execInFg, "create"); try { ... / / in the end to create a Service and perform the Service of the onCreate () method of the app. The thread. ScheduleCreateService (r, r.s erviceInfo, 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; // If the SERVICE_TIMEOUT_MSG message is not removed after the timeout, Execute the service Timeout process mAm. MHandler. SendMessageAtTime (MSG, proc. ExecServicesFg? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT)); }Copy the code

The method’s main job is to send the delay message (SERVICE_TIMEOUT_MSG). The bomb is planted, we don’t want it to go off, so we need to defuse it before it goes off.

private void handleCreateService(CreateServiceData data) { ... / / reflection to create a Service object in Java. Lang. This cl = packageInfo. GetClassLoader (); Service service = (Service) cl.loadClass(data.info.name).newInstance(); . Try {/ / create ContextImpl object ContextImpl context. = ContextImpl createAppContext (this, packageInfo); context.setOuterContext(service); / / create the Application object Application app = packageInfo makeApplication (false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); // Call the service onCreate() method service.oncreate (); / / lead ActivityManagerNative bomb was defused. 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 (of state Richard armitage pp. ExecutingServices. The size () = = 0) {/ / the current service without being performed in the process of service mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); . }... }Copy the code

RemoveMessages are removed if all goes well during startup, and detonates the bomb if not

final class MainHandler extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { ... 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 ! AppNotResponding (proc, null, null, false, anrMessage) {// If there is a timeout service, appNotResponding mam. appNotResponding(proc, null, null, false, anrMessage); }}Copy the code

2. The Input response times out ANR

Before we begin to analyze the ANR trigger mechanism and trigger scenarios for Input events, we need to review the distribution process for Input events, which is also in the Framework source analysis section.

Input ANR dispatch time interval is refers to the current events in the process of execution findFocusedWindowTargetsLocked () method to the next execution resetANRTimeoutsLocked () time interval. Look at the source code has 5 opportunities to reset. Both are in the inputDispatcher.cpp file:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // Ready to start a new event. // If we don't already have a pending event, go grab one. if (! mPendingEvent) { ...... // Get ready to dispatch the event. resetANRTimeoutsLocked(); }... switch (mPendingEvent->type) { case EventEntry::TYPE_MOTION: { ...... done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; }... } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; String8 reason; // If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle ! = NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); goto Unresponsive; } goto Failed; }... 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) { if (applicationHandle == NULL && windowHandle == NULL) { ... } else { if (mInputTargetWaitCause ! = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { if (windowHandle ! = NULL) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle ! = NULL) { timeout = applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; mInputTargetWaitStartTime = currentTime; / / this is the timeout mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); if (windowHandle ! = NULL) { mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; } if (mInputTargetWaitApplicationHandle == NULL && applicationHandle ! = NULL) { mInputTargetWaitApplicationHandle = applicationHandle; } } } if (mInputTargetWaitTimeoutExpired) { return INPUT_EVENT_INJECTION_TIMED_OUT; }}Copy the code

Video link: pan.baidu.com/s/1bYHPvx3I… Video password: L5DF