输入超时ANR
InputDispatcher
InputDispatcher 是 Android 输入系统(InputFlinger)的核心组件,负责将输入事件(如触摸、按键)从系统层分发给目标应用窗口。它在 Input ANR(Application Not Responding) 的检测和触发过程中扮演关键角色,主要涉及 事件分发、超时监控、ANR 触发 三个核心机制。
事件分发
- start()
初始化 InputDispatcher 线程,进入事件分发主循环。 - dispatchOnce()
每次调用处理 一个输入事件,并检查 ANR 超时。 - dispatchOnceInnerLocked()
这个方法主要做的事情是根据从 mInboundQueue(输入事件队列)中取出的 mPendingEvent 决定事件类型和分发方式。 - enqueueDispatchEntryLocked()
这里会将新创建的 DispatchEntry 放入到 connection#outboundQueue(待发送队列)中。 - startDispatchCycleLocked()
通过 connection 发布最终的事件,并且将发布的事件保存在connection#waitQueue(等待响应队列,属于某个窗口)中,并设置超时时间点到 mAnrTracker(统一管理所有窗口的 ANR 超时计时)中。
至此,事件分发完成,分发的事件保存在 waitQueue 中,mAnrTracker 中记录超时时间。
通过 EventHub 从内核设备读取原始的输入事件,加工封装后放入mInboundQueue中。
超时监控和ANR触发
- processAnrsLocked()
ANR 检测的核心方法,检查并决定触发哪种类型的 ANR。如果等待特定焦点窗口超时,进入processNoFocusedWindowAnrLocked()分支处理;否则如果ANR追踪器(mAnrTracker)发现有超时事件,调用onAnrLocked(connection)处理;以上情况都不是的时候,返回下次检查的时间点。 - processNoFocusedWindowAnrLocked()
在触发 ANR 之前做最后的检查,比如 application 有没有改变,focused window 有没有得到。 - onAnrLocked(application)
这里处理无焦点窗口的情况,记录日志并通过一系列调用到 java 层 IMS 的 notifyNoFocusedWindowAnr()。 - onAnrLocked(connection)
这里处理某个窗口未及时处理输入时间的情况,记录日志并通过一系列调用到 java 层 IMS 的 notifyWindowUnresponsive()。
onAnrLocked() 中可以看到 reason 的合成:
“%s is not responding. Waited %” PRId64 “ms for %s, seq=%” PRIu32 “, triggerTime=%ld”
“%s does not have a focused window”, application->getName().c_str()
ANR的处理 - 对话框的显示
- notifyWindowUnresponsive分支
services/core/java/com/android/server/am/AppNotRespondingDialog.java : show()
services/core/java/com/android/server/am/ErrorDialogController.java : showAnrDialogs()
services/core/java/com/android/server/am/AppErrors.java : handleShowAnrUi()
services/core/java/com/android/server/am/ActivityManagerService.java : UiHandler.SHOW_NOT_RESPONDING_UI_MSG
services/core/java/com/android/server/am/ProcessErrorStateRecord.java : appNotResponding()
services/core/java/com/android/server/am/AnrHelper.java : AnrRecord.appNotResponding()
services/core/java/com/android/server/am/AnrHelper.java : AnrConsumerThread.run()
services/core/java/com/android/server/am/AnrHelper.java : startAnrConsumerIfNeeded()
services/core/java/com/android/server/am/AnrHelper.java : appNotResponding()
services/core/java/com/android/server/am/ActivityManagerService.java : inputDispatchingTimedOut()
services/core/java/com/android/server/am/ActivityManagerService.java : LocalService.inputDispatchingTimedOut()
services/core/java/com/android/server/wm/ActivityRecord.java : inputDispatchingTimedOut()
services/core/java/com/android/server/wm/AnrController.java : notifyWindowUnresponsive()
services/core/java/com/android/server/wm/InputManagerCallback.java : notifyWindowUnresponsive()
services/core/java/com/android/server/input/InputManagerService.java : notifyWindowUnresponsive()
- notifyNoFocusedWindowAnr分支
services/core/java/com/android/server/am/AppNotRespondingDialog.java : show()
services/core/java/com/android/server/am/ErrorDialogController.java : showAnrDialogs()
services/core/java/com/android/server/am/AppErrors.java : handleShowAnrUi()
services/core/java/com/android/server/am/ActivityManagerService.java : UiHandler.handleMessage()
services/core/java/com/android/server/am/ProcessErrorStateRecord.java : appNotResponding()
services/core/java/com/android/server/am/AnrHelper.java : AnrRecord.appNotResponding()
services/core/java/com/android/server/am/AnrHelper.java : AnrConsumerThread.run()
services/core/java/com/android/server/am/AnrHelper.java : startAnrConsumerIfNeeded()
services/core/java/com/android/server/am/AnrHelper.java : appNotResponding()
services/core/java/com/android/server/am/ActivityManagerService.java : inputDispatchingTimedOut()
services/core/java/com/android/server/am/ActivityManagerService.java : LocalService.inputDispatchingTimedOut()
services/core/java/com/android/server/wm/ActivityRecord.java : inputDispatchingTimedOut()
services/core/java/com/android/server/wm/AnrController.java : notifyAppUnresponsive()
services/core/java/com/android/server/wm/InputManagerCallback.java : notifyNoFocusedWindowAnr()
services/core/java/com/android/server/input/InputManagerService.java : notifyNoFocusedWindowAnr()
- AnrController#notifyAppUnresponsive() 和 AnrController#notifyWindowUnresponsive() 中会通过 dumpAnrStateLocked() 保存 ANR 信息。
- 从上面两个分支可以看出,从 ActivityRecord#inputDispatchingTimedOut() 开始堆栈就是相同的。
- ActivityManagerService#inputDispatchingTimedOut() 会拼接出注释:annotation = "Input dispatching timed out (" + reason + “)”;
- AnrHelper#appNotResponding() 将 anr 信息保存到 mAnrRecords(ArrayList) 中,然后 AnrHelper#AnrConsumerThread#run() 启动线程遍历 mAnrRecords 并处理。
- 接着来到 ProcessErrorStateRecord#appNotResponding(),这里会将 ANR 记录到主日志中,转储堆栈信息到跟踪文件中,发出显示anr对话框的消息。ErrorDialogController 负责控制对话框,AppNotRespondingDialog 即是对话框的实现。
其他
Input ANR超时时间
超时时间的获取
- class InputDispatcher#getDispatchingTimeoutLocked() (frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp)
默认值是 UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * HwTimeoutMultiplier(),通过2、3可以知道这个默认值是5000。
如果通过 getDispatchingTimeout() 方法得到超时时间,由4、5可以知道这个值一定会是5000,也就是5秒。
const std::chrono::duration DEFAULT_INPUT_DISPATCHING_TIMEOUT = std::chrono::milliseconds(
android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
HwTimeoutMultiplier());
std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) {
sp<InputWindowHandle> window = getWindowHandleLocked(token);
if (window != nullptr) {
return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
}
return DEFAULT_INPUT_DISPATCHING_TIMEOUT;
}
- interface IInputConstants (frameworks/native/libs/input/android/os/IInputConstants.aidl)
const int UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds
- HwTimeoutMultiplier() (system/libbase/include/android-base/properties.h)
static inline int HwTimeoutMultiplier() {
return android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
}
- class InputWindowHandle#getDispatchingTimeout() (frameworks/native/include/input/InputWindow.h)
inline std::chrono::nanoseconds getDispatchingTimeout(
std::chrono::nanoseconds defaultValue) const {
return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
}
- struct InputWindowInfo (frameworks/native/include/input/InputWindow.h)
std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
超时时间的设定
-
可动态修改的 dispatchingTimeout
上文中提到,除了默认值 DEFAULT_INPUT_DISPATCHING_TIMEOUT外,还有一个可以动态修改的值 mInfo.dispatchingTimeout,可以通过后者去针对窗口动态设置超时时间,而这个值的获取路线是:
InputDispatcher::mWindowHandlesByDisplay
->InputWindowHandle::mInfo
->InputWindowInfo::dispatchingTimeout
所以想知道如何设定的就需要找到mWindowHandlesByDisplay在哪里被修改。
- 修改堆栈
InputDispatcher::updateWindowHandlesForDisplayLocked
InputDispatcher::setInputWindowsLocked
InputDispatcher::setInputWindows
InputManager::setInputWindows()
SurfaceFlinger::setInputWindowsWithFlowControl()
SurfaceFlinger::updateInputWindowInfo()
SurfaceFlinger::updateInputFlinger()
SurfaceFlinger::onMessageInvalidate()
SurfaceFlinger::onMessageReceived()
MessageQueue::Handler::handleMessage()
MessageQueue::Handler::dispatchInvalidate()
MessageQueue::vsyncCallback()
MessageQueue::initVsync()
下一步需要着重介绍SurfaceFlinger::updateInputWindowInfo()函数
- 这一部分遍历SurfaceFlinger::State::layerssortedByZ并对每个Layer执行回调函数Visitor,用Layer的State::inputInfo给InputWindowInfo赋值:
Layer::fillInputInfo() --- 这里用Layer::State(mDrawingState)::inputInfo给要返回的InputWindowInfo对象填充内容,mDrawingState.inputInfo在Layer::setInputInfo()中被修改
LayerVector::Visitor() ---- Visitor是函数指针类型
Layer::traverseInReverseZOrder()
LayerVector::traverseInReverseZOrder()
SurfaceFlinger::State::traverseInReverseZOrder()
SurfaceFlinger::updateInputWindowInfo()
下一步需要知道Layer:: setInputInfo()在哪被调用
- 这一部分将mPendingTransactionQueues中transaction的窗口信息取出来作为参数,这里面包含着InputWindowInfo变量
Layer:: setInputInfo()
SurfaceFlinger::setClientStateLocked() --- 这里将ComposerState的layer_state_t类型成员state取出,这个类型的变量用于SF和Client之间传递图层信息,state中包含InputWindowHandle类型变量
SurfaceFlinger::applyTransactionState()
SurfaceFlinger::flushTransactionQueues() --- 这里将unordered_map容器mPendingTransactionQueues中的transaction取出来放到vector容器transactions中,transaction有一个Vector< ComposerState > states成员将作为applyTransactonState()的第二个参数传入
下一步需要知道mPendingTransactionQueues在哪被赋值
- 这一部分用mTransactionQueue赋值mPendingTransactionQueues
SurfaceFlinger::flushTransactionQueues() --- 这里也会将mTransactionQueue的事务收集到mPendingTransactionQueues中
下一步需要知道mTransactionQueue在哪里被赋值
- 这一部分用Transaction更新输入超时时间
SurfaceFlinger::queueTransaction() --- 用TransactionState& state构造 mTransactionQueue的元素
SurfaceFlinger::setTransactionState()
SurfaceFlinger::Transaction::apply() --- apply之前执行Transaction的其他方法修改变量值,比如setInputWindowInfo()
WindowManagerService.updateInputChannel() --- 这里举个例子,WMS这里使用的还是默认值5s,代码如下:
InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
SurfaceControl.Transaction t = mTransactionFactory.get();
t.setInputWindowInfo(surface, h);
t.apply();
t.close();
- 被标记成@hide的SurfaceControl.Transaction.setInputWindowInfo()
/**
* @hide
*/
public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
checkPreconditions(sc);
nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
return this;
}
setInputwindowInfo()是修改超时时间的接口,标记成@hide意味着如果在应用中直接调用会报编译错误,只能由系统管理超时时间的修改。
- 点赞
- 收藏
- 关注作者
评论(0)