输入超时ANR

举报
咕菇 发表于 2025/10/14 16:04:22 2025/10/14
【摘要】 InputDispatcherInputDispatcher 是 Android 输入系统(InputFlinger)的核心组件,负责将输入事件(如触摸、按键)从系统层分发给目标应用窗口。它在 Input ANR(Application Not Responding) 的检测和触发过程中扮演关键角色,主要涉及 事件分发、超时监控、ANR 触发 三个核心机制。 事件分发InputManage...

InputDispatcher

InputDispatcher 是 Android 输入系统(InputFlinger)的核心组件,负责将输入事件(如触摸、按键)从系统层分发给目标应用窗口。它在 Input ANR(Application Not Responding) 的检测和触发过程中扮演关键角色,主要涉及 事件分发超时监控ANR 触发 三个核心机制。

事件分发

InputManagerServiceInputDispatcherApplicationInputDispatcher线程启动start()dispatchOnce()dispatchOnceInnerLocked()dispatchKeyLocked()dispatchMotionLocked()alt[是按键事件][是触摸事件]prepareDispatchCycleLocked()enqueueDispatchEntryLocked()startDispatchCycleLocked()事件通过InputChannel发送到应用输入事件(IPC)alt[有输入事件待处理]loop[主事件循环]InputManagerServiceInputDispatcherApplication
  1. start()
    初始化 InputDispatcher 线程,进入事件分发主循环。
  2. dispatchOnce()
    每次调用处理 一个输入事件,并检查 ANR 超时。
  3. dispatchOnceInnerLocked()
    这个方法主要做的事情是根据从 mInboundQueue(输入事件队列)中取出的 mPendingEvent 决定事件类型和分发方式。
  4. enqueueDispatchEntryLocked()
    这里会将新创建的 DispatchEntry 放入到 connection#outboundQueue(待发送队列)中。
  5. startDispatchCycleLocked()
    通过 connection 发布最终的事件,并且将发布的事件保存在connection#waitQueue(等待响应队列,属于某个窗口)中,并设置超时时间点到 mAnrTracker(统一管理所有窗口的 ANR 超时计时)中。

至此,事件分发完成,分发的事件保存在 waitQueue 中,mAnrTracker 中记录超时时间。

通过 EventHub 从内核设备读取原始的输入事件,加工封装后放入mInboundQueue中。

超时监控和ANR触发

InputDispatcherConnectionInputManagerService主事件循环dispatchOnce()ANR检测入口processAnrsLocked()processNoFocusedWindowAnrLocked()onAnrLocked(application)notifyNoFocusedWindowAnr()onAnrLocked(connection)notifyWindowUnresponsive()alt[焦点窗口无响应][特定Connection无响应]loop[dispatchOnce()]InputDispatcherConnectionInputManagerService
  1. processAnrsLocked()
    ANR 检测的核心方法,检查并决定触发哪种类型的 ANR。如果等待特定焦点窗口超时,进入processNoFocusedWindowAnrLocked()分支处理;否则如果ANR追踪器(mAnrTracker)发现有超时事件,调用onAnrLocked(connection)处理;以上情况都不是的时候,返回下次检查的时间点。
  2. processNoFocusedWindowAnrLocked()
    在触发 ANR 之前做最后的检查,比如 application 有没有改变,focused window 有没有得到。
  3. onAnrLocked(application)
    这里处理无焦点窗口的情况,记录日志并通过一系列调用到 java 层 IMS 的 notifyNoFocusedWindowAnr()。
  4. 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的处理 - 对话框的显示

  1. 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()
  1. 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超时时间

超时时间的获取

  1. 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;
}
  1. interface IInputConstants (frameworks/native/libs/input/android/os/IInputConstants.aidl)
const int UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds
  1. HwTimeoutMultiplier() (system/libbase/include/android-base/properties.h)
static inline int HwTimeoutMultiplier() {
  return android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
}
  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;
  }
  1. struct InputWindowInfo (frameworks/native/include/input/InputWindow.h)
std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);

超时时间的设定

  1. 可动态修改的 dispatchingTimeout

    上文中提到,除了默认值 DEFAULT_INPUT_DISPATCHING_TIMEOUT外,还有一个可以动态修改的值 mInfo.dispatchingTimeout,可以通过后者去针对窗口动态设置超时时间,而这个值的获取路线是:
    InputDispatcher::mWindowHandlesByDisplay->InputWindowHandle::mInfo->InputWindowInfo::dispatchingTimeout

所以想知道如何设定的就需要找到mWindowHandlesByDisplay在哪里被修改。

  1. 修改堆栈
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()函数

  1. 这一部分遍历SurfaceFlinger::State::layerssortedByZ并对每个Layer执行回调函数​​Visitor,用LayerState::inputInfoInputWindowInfo赋值:
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()​在哪被调用

  1. 这一部分将mPendingTransactionQueuestransaction的窗口信息取出来作为参数,这里面包含着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在哪被赋值

  1. 这一部分用mTransactionQueue赋值mPendingTransactionQueues
SurfaceFlinger::flushTransactionQueues() --- 这里也会将mTransactionQueue的事务收集到mPendingTransactionQueues中

下一步需要知道mTransactionQueue在哪里被赋值

  1. 这一部分用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();
  1. 被标记成@hide的SurfaceControl.Transaction.setInputWindowInfo()
/**
 * @hide
 */
public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
    checkPreconditions(sc);
    nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
    return this;
}

setInputwindowInfo()是修改超时时间的接口,标记成@hide意味着如果在应用中直接调用会报编译错误,只能由系统管理超时时间的修改。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。