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 }