anr触发机制与处理流程

0.前言

本文主要是针对窗口发生anr的情况进行梳理,其他情况诸如 Service、Broadcast等发生anr不在本文关注范围内。

1.anr类型

常见anr类型主要有两种,一种是no foucsed window类型的anr,即无焦点窗口类型的anr,主要针对key事件;另一种是input dispatching timeout类型的anr,即input事件处理超时类型的anr,主要是针对motion事件。

2.anr触发

2.1 no focused window anr触发

这种类型触发相对简单,在InputDispatcher派发key事件时会检测当前是否存在焦点窗口,若不存在焦点窗口则开始计时等待。检测到当前时间大于mNoFocusedWindowTimeoutTime(anr将要发生的时间点)时,则会触发no focused window anr。

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

>>开启key事件派发流程

1472  bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
1473                                          DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
1562      // Identify targets.
1563      std::vector<InputTarget> inputTargets;
>>确定inputTarget
1564      InputEventInjectionResult injectionResult =
1565              findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
1869  InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked(
1870          nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets,
1871          nsecs_t* nextWakeupTime) {
1872      std::string reason;
1873  
1874      int32_t displayId = getTargetDisplayId(entry);
>>获取focusedWindowHandle
1875      sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
>>获取focusedApplicationHandle
1876      std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
1877              getValueByKey(mFocusedApplicationHandlesByDisplay, displayId)
...
1893      // Compatibility behavior: raise ANR if there is a focused application, but no focused window.
1894      // Only start counting when we have a focused event to dispatch. The ANR is canceled if we
1895      // start interacting with another application via touch (app switch). This code can be removed
1896      // if the "no focused window ANR" is moved to the policy. Input doesn't know whether
1897      // an app is expected to have a focused window.
>>当focusedWindowHandle为null且focusedApplicationHandle不为null时,进入如下判断流程
1898      if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
>>当无焦点窗口超时时间mNoFocusedWindowTimeoutTime尚未设置时
1899          if (!mNoFocusedWindowTimeoutTime.has_value()) {
1900              // We just discovered that there's no focused window. Start the ANR timer
1901              std::chrono::nanoseconds timeout = focusedApplicationHandle->getDispatchingTimeout(
1902                      DEFAULT_INPUT_DISPATCHING_TIMEOUT);
>>对mNoFocusedWindowTimeoutTime进行赋值,其值为:当前时间+超时时间
1903              mNoFocusedWindowTimeoutTime = currentTime + timeout.count();
1904              mAwaitedFocusedApplication = focusedApplicationHandle;
1905              mAwaitedApplicationDisplayId = displayId;
1906              ALOGW("Waiting because no window has focus but %s may eventually add a "
1907                    "window when it finishes starting up. Will wait for %" PRId64 "ms",
1908                    mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
1909              *nextWakeupTime = *mNoFocusedWindowTimeoutTime;
1910              return InputEventInjectionResult::PENDING;
>>如果当前时间大于mNoFocusedWindowTimeoutTime,说明anr已经发生
1911          } else if (currentTime > *mNoFocusedWindowTimeoutTime) {
1912              // Already raised ANR. Drop the event
1913              ALOGE("Dropping %s event because there is no focused window",
1914                    ftl::enum_string(entry.type).c_str());
1915              return InputEventInjectionResult::FAILED;
>>否则,继续等待焦点窗口
1916          } else {
1917              // Still waiting for the focused window
1918              return InputEventInjectionResult::PENDING;
1919          }
1920      }
1921  
1922      // we have a valid, non-null focused window
>>如果当前存在焦点窗口,则重置mNoFocusedWindowTimeoutTime
1923      resetNoFocusedWindowTimeoutLocked();

2.2 input dispatching timeout anr触发

InputDispatcher每次被唤醒时都会执行dispatchOnce,开启新一轮的input事件派发流程以及检测anr是否发生。

602  void InputDispatcher::dispatchOnce() {
>>初始化下一次唤醒时间nextWakeupTime
603      nsecs_t nextWakeupTime = LONG_LONG_MAX;
604      { // acquire lock
605          std::scoped_lock _l(mLock);
606          mDispatcherIsAlive.notify_all();
607  
608          // Run a dispatch loop if there are no pending commands.
609          // The dispatch loop might enqueue commands to run afterwards.
610          if (!haveCommandsLocked()) {
>>开启新一轮的input事件派发流程
611              dispatchOnceInnerLocked(&nextWakeupTime);
612          }
613  
614          // Run all pending commands if there are any.
615          // If any commands were run then force the next poll to wake up immediately.
>>如果存在pending commands,则立即唤醒
616          if (runCommandsLockedInterruptable()) {
617              nextWakeupTime = LONG_LONG_MIN;
618          }
619  
620          // If we are still waiting for ack on some events,
621          // we might have to wake up earlier to check if an app is anr'ing.
>>计算下一次检测anr的时间nextAnrCheck
622          const nsecs_t nextAnrCheck = processAnrsLocked();
>>在nextWakeUp和nextAnrCheck之间取较小值
623          nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

InputDispatcher会在processAnrsLocked方法中检测是否发生anr,先检测无焦点窗口类型anr,再检测input事件处理超时类型的anr。若检测到anr,则开始anr的处理流程。

670  nsecs_t InputDispatcher::processAnrsLocked() {
671      const nsecs_t currentTime = now();
>>初始化nextAnrCheck
672      nsecs_t nextAnrCheck = LONG_LONG_MAX;
673      // Check if we are waiting for a focused window to appear. Raise ANR if waited too long
674      if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
>>如果当前时间已经超过 无焦点窗口等待时间,则说明已经发生了无焦点窗口类型的anr,并开始处理anr
675          if (currentTime >= *mNoFocusedWindowTimeoutTime) {
676              processNoFocusedWindowAnrLocked();
677              mAwaitedFocusedApplication.reset();
678              mNoFocusedWindowTimeoutTime = std::nullopt;
679              return LONG_LONG_MIN;
680          } else {
681              // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
682              nextAnrCheck = *mNoFocusedWindowTimeoutTime;
683          }
684      }
685  
>>执行到这里,说明没有发生无焦点窗口类型的anr,开始检测input事件处理超时的anr
686      // Check if any connection ANRs are due
>>取出mAnrTracker中存储的第一个超时时间
687      nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
>>如果当前时间小于nextAnrCheck,说明还没有发生anr
688      if (currentTime < nextAnrCheck) { // most likely scenario
689          return nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck
690      }
691  
>>执行到这里,说明当前时间>=nextAnrCheck,已经发生了anr
692      // If we reached here, we have an unresponsive connection.
>>根据token获取对应的connection
693      sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
694      if (connection == nullptr) {
695          ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
696          return nextAnrCheck;
697      }
>>将对应connection的responsive置为false
698      connection->responsive = false;
699      // Stop waking up for this unresponsive connection
700      mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
>>开始处理anr
701      onAnrLocked(connection);
702      return LONG_LONG_MIN;
703  }

每个connection的超时时间会在input事件开始派发时插入mAnrTracker中。

3214  void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
3215                                                 const sp<Connection>& connection) {
...
3225      while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
3226          DispatchEntry* dispatchEntry = connection->outboundQueue.front();
3227          dispatchEntry->deliveryTime = currentTime;
>>获取对应connection的派发超时时间
3228          const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
>>将超时时间加上当前时间,则为下一次检测anr的时间,赋值给dispatchEntry->timeoutTime
3229          dispatchEntry->timeoutTime = currentTime + timeout.count();
...
>>派发Motion事件
3252              case EventEntry::Type::MOTION: {
3253                  const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
...
3387          traceOutboundQueueLength(*connection);
3388          connection->waitQueue.push_back(dispatchEntry);
>>如果对应inputTarget对应connection的responsive为true,则向mAnrTracker中插入当前dispatchEntry的timeoutTime
3389          if (connection->responsive) {
3390              mAnrTracker.insert(dispatchEntry->timeoutTime,
3391                                 connection->inputChannel->getConnectionToken());
3392          }

待client端处理完input事件并反馈给InputDispatcher时,会将当前dispatchEntry的timeoutTime从mAnrTracker中移除。如果在下一次anr检测前还没有移除timeoutTime,则说明当前dispatchEntry派发超时或者说client端处理超时,会触发anr。

>>inputTarget处理完input事件,反馈给InputDiapatcher,
>>至此,input事件派发流程结束
5710  void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
5711                                                       const sp<Connection>& connection, uint32_t seq,
5712                                                       bool handled, nsecs_t consumeTime) {
5713      // Handle post-event policy actions.
5714      std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
...
5747      dispatchEntryIt = connection->findWaitQueueEntry(seq);
5748      if (dispatchEntryIt != connection->waitQueue.end()) {
5749          dispatchEntry = *dispatchEntryIt;
>>从waitQueue中移除dispatchEntry
5750          connection->waitQueue.erase(dispatchEntryIt);
5751          const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
>>从mAnrTracker中移除对应connectionToken和timeoutTime
>>注意这里同时指明了timeoutTime和connectionToken,说明mAnrTracker中可能存放了相同connectionToken的不同timeoutTime
5752          mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);

3.获取anr超时时间timeout

计算下一次anr检测时间时,会先根据connection去获取对应的timeout。如果是普通的窗口而非monitor,则会根据WindowInfoHandle.getDispatchingTimeout去获取对应窗口的timeout。

705  std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(
706          const sp<Connection>& connection) {
707      if (connection->monitor) {
708          return mMonitorDispatchingTimeout;
709      }
710      const sp<WindowInfoHandle> window =
711              getWindowHandleLocked(connection->inputChannel->getConnectionToken());
712      if (window != nullptr) {
713          return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
714      }
715      return DEFAULT_INPUT_DISPATCHING_TIMEOUT;
716  }
717  

4.设置anr超时时间timeout

前面WindowInfoHandle的timeout可以从上层设置到底层。WindowInfoHandle中得到的dispatchingTimeout来源于WindowInfo的dispatchingTimeout,而WindowInfo中的相关信息是由上层传下来的信息填充进去的。大致路径为:

frameworks/native/libs/gui/include/gui/WindowInfo.h

268  class WindowInfoHandle : public RefBase {
269  public:
270      explicit WindowInfoHandle();
271      WindowInfoHandle(const WindowInfoHandle& other);
272      WindowInfoHandle(const WindowInfo& other);
...
284      inline std::chrono::nanoseconds getDispatchingTimeout(
285              std::chrono::nanoseconds defaultValue) const {
>>WindowInfoHandle的dispatchingTimeout来源于WindowInfo的dispatchingTimeout
286          return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
287      }
...
304  protected:
305      virtual ~WindowInfoHandle();
306  
307      WindowInfo mInfo;

frameworks/base/core/jni/android_hardware_input_InputWindowHandle.cpp

109  bool NativeInputWindowHandle::updateInfo() {
110      JNIEnv* env = AndroidRuntime::getJNIEnv();
111      jobject obj = env->NewLocalRef(mObjWeak);
...
127      mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
128  
>>向WindowInfo中填充dispatchingTimeout
129      mInfo.dispatchingTimeout = std::chrono::milliseconds(
130              env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
131      mInfo.frameLeft = env->GetIntField(obj,
132              gInputWindowHandleClassInfo.frameLeft);
133      mInfo.frameTop = env->GetIntField(obj,
134              gInputWindowHandleClassInfo.frameTop);

frameworks/base/core/jni/android_view_SurfaceControl.cpp

876  static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj,
877          jlong nativeObject, jobject inputWindow) {
878      auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
879  
>>创建新的NativeInputWindowHandle类型的对象,并调用updateInfo函数填充窗口信息
880      sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
881              env, inputWindow);
882      handle->updateInfo();
883  
884      auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
885      transaction->setInputWindowInfo(ctrl, *handle->getInfo());
886  }

填充的窗口信息来源于现有的窗口信息。现有窗口中的dispatchingTimeout大致分为两种情况,一种是没有activity的窗口,比如NotificationShade、StatusBar这种系统窗口;另一种是拥有activity的普通应用窗口。

frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java

241      void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle,
242              final WindowState w) {
243          // Add a window to our list of input windows.
244          inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null
245                  ? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null);
246          inputWindowHandle.setToken(w.mInputChannelToken);
>>填充dispatchingTimeout
247          inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
248          inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
249          inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
250          inputWindowHandle.setWindowToken(w.mClient);

frameworks/base/services/core/java/com/android/server/wm/WindowState.java

1862      public long getInputDispatchingTimeoutMillis() {
1863          return mActivityRecord != null
1864                  ? mActivityRecord.mInputDispatchingTimeoutMillis
1865                  : DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
1866      }

对于第一种情况,超时时间为默认时间,即5s。

frameworks/base/core/java/android/os/InputConstants.java
20  public class InputConstants {
21      public static final int DEFAULT_DISPATCHING_TIMEOUT_MILLIS =
22              IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS
23              * Build.HW_TIMEOUT_MULTIPLIER;
24  }
frameworks/native/libs/input/android/os/IInputConstants.aidl
21  interface IInputConstants
22  {
23      // This should be multiplied by the value of the system property ro.hw_timeout_multiplier before
24      // use. A pre-multiplied constant is available in Java in
25      // android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS.
26      const int UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds

对于第二种情况,即普通应用窗口,也分为两种情况:当处于instrumentation时,超时时间为60s;一般情况为5s。

frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
2174      void setProcess(WindowProcessController proc) {
2175          app = proc;
2176          final ActivityRecord root = task != null ? task.getRootActivity() : null;
2177          if (root == this) {
2178              task.setRootProcess(proc);
2179          }
2180          proc.addActivityIfNeeded(this);
>>从ATMS设置ActivityRecord的dispatchingTimeout
2181          mInputDispatchingTimeoutMillis = getInputDispatchingTimeoutMillisLocked(this);
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
4420      static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) {
4421          if (r == null || !r.hasProcess()) {
4422              return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
4423          }
4424          return getInputDispatchingTimeoutMillisLocked(r.app);
4425      }
4426  
4427      private static long getInputDispatchingTimeoutMillisLocked(WindowProcessController r) {
4428          if (r == null) {
4429              return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
4430          }
4431          return r.getInputDispatchingTimeoutMillis();
4432      }
frameworks/base/services/core/java/com/android/server/wm/WindowProcessController.java
1096      /**
1097       * Get the current dispatching timeout. If instrumentation is currently taking place, return
1098       * a longer value. Shorter timeout is returned otherwise.
1099       * @return The timeout in milliseconds
1100       */
1101      public long getInputDispatchingTimeoutMillis() {
1102          synchronized (mAtm.mGlobalLock) {
>>如果正处于instrumentation,则超时时间为60s;若为一般情况,则为默认超时时间5s
1103              return isInstrumenting() || isUsingWrapper()
1104                      ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS :
1105                      DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
1106          }
1107      }

303      // How long we wait until we timeout on key dispatching during instrumentation.
304      static final long INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS = 60 * 1000;

5.处理anr以及相关log打印

InputDispatcher检测到anr发生后便开始处理anr,而处理anr的流程从onAnrLocked开始,主要是计算引发anr的dispatchEntry的等待时间并将其移出waitQueue,打印anr相关log并将anr相关信息通知到上层。InputDispatcher中处理以及通知上层发生anr的代码流程为:

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
5798  void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
...
5809      /**
5810       * The "oldestEntry" is the entry that was first sent to the application. That entry, however,
5811       * may not be the one that caused the timeout to occur. One possibility is that window timeout
5812       * has changed. This could cause newer entries to time out before the already dispatched
5813       * entries. In that situation, the newest entries caused ANR. But in all likelihood, the app
5814       * processes the events linearly. So providing information about the oldest entry seems to be
5815       * most useful.
5816       */
>>从waitQueue中取出第一个dispatchEntry
5817      DispatchEntry* oldestEntry = *connection->waitQueue.begin();
>>计算当前dispatchEntry的等待时间为:当前时间减去派发时间
5818      const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
>>reason中包含了发生anr的connection的相关信息以及等待的时间
5819      std::string reason =
5820              android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
5821                                          connection->inputChannel->getName().c_str(),
5822                                          ns2ms(currentWait),
5823                                          oldestEntry->eventEntry->getDescription().c_str());
5824      sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
5825      updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
5826  
>>通知上层发生anr
5827      processConnectionUnresponsiveLocked(*connection, std::move(reason));
5922  void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
5923                                                            std::string reason) {
5924      const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
5925      std::optional<int32_t> pid;
>>判断connection类型是momnitor还是window
5926      if (connection.monitor) {
>>发生anr后,第一次打印anr相关log是在InputDispatcher这里
>>这里是monitor发生anr
5927          ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
5928                reason.c_str());
5929          pid = findMonitorPidByTokenLocked(connectionToken);
5930      } else {
5931          // The connection is a window
>>走到这里说明发生anr的是winndow,是发生anr后第一次打印相关log
5932          ALOGW("Window %s is unresponsive: %s", connection.inputChannel->getName().c_str(),
5933                reason.c_str());
5934          const sp<WindowInfoHandle> handle = getWindowHandleLocked(connectionToken);
5935          if (handle != nullptr) {
5936              pid = handle->getInfo()->ownerPid;
5937          }
5938      }
>>发送command执行后续anr处理事务
5939      sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason));
5940  }
5898  void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
5899                                                            std::optional<int32_t> pid,
5900                                                            std::string reason) {
>>封装了一个command,后续执行mPolicy->notifyWindowUnresponsive
5901      auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {
5902          scoped_unlock unlock(mLock);
5903          mPolicy->notifyWindowUnresponsive(token, pid, reason);
5904      };
5905      postCommandLocked(std::move(command));
5906  }

InputDIspatcher中调用执行的"mPolicy->notifyWindowUnresponsive",最终会执行到NativeInputManager中的同名函数。因为这里的mPolicy是InputDispatcherPolicyInterface类型,而NativeInputManager继承了InputDispatcherPolicyInterface并重写了notifyWindowUnresponsive方法。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
831  void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
832                                                    std::optional<int32_t> pid,
833                                                    const std::string& reason) {
834  #if DEBUG_INPUT_DISPATCHER_POLICY
835      ALOGD("notifyWindowUnresponsive");
836  #endif
837      ATRACE_CALL();
838  
839      JNIEnv* env = jniEnv();
840      ScopedLocalFrame localFrame(env);
841  
842      jobject tokenObj = javaObjectForIBinder(env, token);
843      ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
844  
>>这里开始调用java层的同名方法
845      env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
846                          pid.value_or(0), pid.has_value(), reasonObj.get());
847      checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
848  }

对于java层,NativeInputManager会调用到InputManagerService的同名方法。

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
2927      // Native callback
2928      @SuppressWarnings("unused")
2929      private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
2930              String reason) {
2931          mWindowManagerCallbacks.notifyWindowUnresponsive(token,
2932                  isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
2933      }

InputManagerServcie中的mWindowManagerCallbacks为WindowManagerCallbacks类型,被InputManagerCallback所继承,因此会调用到InputManagerCallback中的notifyWindowUnresponsive方法,最终会执行AnrController中的相关逻辑。

frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
102      @Override
103      public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
104              @NonNull String reason) {
105          mService.mAnrController.notifyWindowUnresponsive(token, pid, reason);
106      }

AnrController中有三个notifyWindowUnresponsive同名方法。根据方法具体参数类型,InputManagerCallback直接调用的是notifyWindowUnresponsive同名方法有着三个参数,分别是token、pid、reason。然后依次执行第二个和第三个notifyWindoUnresponsive方法,若是window发生anr,则第二个notifyWindowUnresponsive方法会处理anr并返回true,不再向后执行;若是monitor发生anr,则会执行第三个notifyWindowUnresponsive方法去处理anr。

frameworks/base/services/core/java/com/android/server/wm/AnrController.java
88      void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
89              @NonNull String reason) {
>>若是window发生anr,则此方法返回true
90          if (notifyWindowUnresponsive(token, reason)) {
91              return;
92          }
93          if (!pid.isPresent()) {
94              Slog.w(TAG_WM, "Failed to notify that window token=" + token + " was unresponsive.");
95              return;
96          }
>>若是monitor发生anr,则最终会执行到此处
97          notifyWindowUnresponsive(pid.getAsInt(), reason);
98      }

执行第二个notifyWindowUnresponsive方法时,会先去根据inputToken从WMS获取到对应的window(WindowState或者embedded window),若获取的window不为null,则说明当前发生anr的是window,否则是monitor。存在monitor的进程不多,常见的有SystemUI、System_server、Launcher。在这个方法中,主要做两件事:一是打印anr发生的log,这是上层第一次在anr发生后打印相关log;二是执行anr后续流程,主要是dump此时系统的一些主要状态信息以及打印anr的相关log。

>>window发生anr时调用此方法
106      private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken, String reason) {
107          preDumpIfLockTooSlow();
108          final int pid;
109          final boolean aboveSystem;
110          final ActivityRecord activity;
111          synchronized (mService.mGlobalLock) {
112              InputTarget target = mService.getInputTargetFromToken(inputToken);
>>若是获取到的target为null,则直接return
113              if (target == null) {
114                  return false;
115              }
116              WindowState windowState = target.getWindowState();
117              pid = target.getPid();
118              // Blame the activity if the input token belongs to the window. If the target is
119              // embedded, then we will blame the pid instead.
120              activity = (windowState.mInputChannelToken == inputToken)
121                      ? windowState.mActivityRecord : null;
>>上层第一时间打印anr相关log:"WindowManager:ANr in Window xxx ...."
122              Slog.i(TAG_WM, "ANR in " + target + ". Reason:" + reason);
123              aboveSystem = isWindowAboveSystem(windowState);
124              dumpAnrStateLocked(activity, windowState, reason);
125          }
>>处理anr后续流程,主要是dump一些系统关键状态信息以及打印log: >>"am_anr:..."、"ActivityManager: Anr in xxx ..."
126          if (activity != null) {
127              activity.inputDispatchingTimedOut(reason, pid);
128          } else {
129              mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, reason);
130          }
>>返回true表明已经对当前anr进行了处理
131          return true;
132      }
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
5165      // Returns an input target which is mapped to the given input token. This can be a WindowState
5166      // or an embedded window.
>>根据inputToken查询对应的window
5167      @Nullable InputTarget getInputTargetFromToken(IBinder inputToken) {
5168          WindowState windowState = mInputToWindowMap.get(inputToken);
>>检查是否为WindowState
5169          if (windowState != null) {
5170              return windowState;
5171          }
5172  
5173          EmbeddedWindowController.EmbeddedWindow embeddedWindow =
5174                  mEmbeddedWindowController.get(inputToken);
>>检查是否为embedded window
5175          if (embeddedWindow != null) {
5176              return embeddedWindow;
5177          }
5178  
>>执行到这里,说明是monitor
5179          return null;
5180      }
>>monitor发生anr时调用此方法
137      private void notifyWindowUnresponsive(int pid, String reason) {
138          Slog.i(TAG_WM, "ANR in input window owned by pid=" + pid + ". Reason: " + reason);
139          dumpAnrStateLocked(null /* activity */, null /* windowState */, reason);
140  
141          // We cannot determine the z-order of the window, so place the anr dialog as high
142          // as possible.
143          mService.mAmInternal.inputDispatchingTimedOut(pid, true /*aboveSystem*/, reason);
144      }

AnrController在接收到底层InputDispatcher上报的anr相关信息后,会最终调用执行ProcessErrorStateRecord的appNotResponding方法,在这里会完成对上层对anr的主要处理过程,包括但不限于打印anr相关log、dump stackTraceFile、memory、cpu等信息。相关代码流程为:

frameworks/base/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
254      void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
255              String parentShortComponentName, WindowProcessController parentProcess,
256              boolean aboveSystem, String annotation, boolean onlyDumpSelf) {
...
>>打印anr相关log:"am_anr:..."
304              // Log the ANR to the event log.
305              EventLog.writeEvent(EventLogTags.AM_ANR, mApp.userId, pid, mApp.processName,
306                      mApp.info.flags, annotation);
>>打印anr相关信息info,包括进程信息、anr原因、cpu、memory等信息
366          // Log the ANR to the main log.
367          StringBuilder info = new StringBuilder();
368          info.setLength(0);
>>打印anr相关log:"ActivityManager: Anr in xxx..."
369          info.append("ANR in ").append(mApp.processName);
370          if (activityShortComponentName != null) {
371              info.append(" (").append(activityShortComponentName).append(")");
372          }
373          info.append("\n");
374          info.append("PID: ").append(pid).append("\n");
375          if (annotation != null) {
376              info.append("Reason: ").append(annotation).append("\n");
377          }
378          if (parentShortComponentName != null
379                  && parentShortComponentName.equals(activityShortComponentName)) {
380              info.append("Parent: ").append(parentShortComponentName).append("\n");
381          }
382          if (errorId != null) {
383              info.append("ErrorId: ").append(errorId.toString()).append("\n");
384          }
385          info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");
>>获取memory pressure信息
403          StringBuilder report = new StringBuilder();
404          report.append(MemoryPressureUtil.currentPsiState());
405          ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
>>打印anr trace堆栈信息
430          // For background ANRs, don't pass the ProcessCpuTracker to
431          // avoid spending 1/2 second collecting stats to rank lastPids.
432          StringWriter tracesFileException = new StringWriter();
433          // To hold the start and end offset to the ANR trace file respectively.
434          final long[] offsets = new long[2];
435          File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
436                  isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
437                  nativePids, tracesFileException, offsets, annotation, criticalEventLog);
438  
>>获取cpu相关信息
439          if (isMonitorCpuUsage()) {
440              mService.updateCpuStatsNow();
441              mService.mAppProfiler.printCurrentCpuState(report, anrTime);
442              info.append(processCpuTracker.printCurrentLoad());
443              info.append(report);
444          }
...
567              if (mService.mUiHandler != null) {
568                  // Bring up the infamous App Not Responding dialog
569                  Message msg = Message.obtain();
>>anr弹框
>>由于前面会dump各种信息,所以一般情况下anr弹框出现时距离anr发生已经过去几十秒了
570                  msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
571                  msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);
572  
573                  mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
574              }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值