Android Input系统之 InputMonitor 更新流程

分析源码为 android 12

一、InputMonitor层面分析

在 WMS 添加,更新和删除Window 的时候都会调用 InputMonitor 的 updateInputWindowsLw 更新 window 信息。如下是删除window 时候的调用函数:

WMS.java

void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
            int displayId) {
   
   
        synchronized (mGlobalLock) {
   
   
            final DisplayContent dc = mRoot.getDisplayContent(displayId);

            if (dc == null) {
   
   
                ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
                        + " for non-exiting displayId=%d", binder, displayId);
                return;
            }
            final WindowToken token = dc.removeWindowToken(binder, animateExit);
            if (token == null) {
   
   
                ProtoLog.w(WM_ERROR,
                        "removeWindowToken: Attempted to remove non-existing token: %s",
                        binder);
                return;
            }

            if (removeWindows) {
   
   
                token.removeAllWindowsIfPossible();
            }
            // 调用 updateInputWindowsLw
            dc.getInputMonitor().updateInputWindowsLw(true /* force */);
        }
    }

updateInputWindowsLw 属于经常被外部调用的方法,它会最后触发到UpdateInputWindows 的 run 方法执行。

private class UpdateInputWindows implements Runnable {
   
   
        @Override
        public void run() {
   
   
            synchronized (mService.mGlobalLock) {
   
   
                mUpdateInputWindowsPending = false;
                mUpdateInputWindowsNeeded = false;

                if (mDisplayRemoved) {
   
   
                    return;
                }

                // Populate the input window list with information about all of the windows that
                // could potentially receive input.
                // As an optimization, we could try to prune the list of windows but this turns
                // out to be difficult because only the native code knows for sure which window
                // currently has touch focus.

                // If there's a drag in flight, provide a pseudo-window to catch drag input
                final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();

                // Add all windows on the default display.
                mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
            }
        }
    }

最后会调用到mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);这个关键方法:

private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
   
   
        InputConsumerImpl mPipInputConsumer;
        InputConsumerImpl mWallpaperInputConsumer;
        InputConsumerImpl mRecentsAnimationInputConsumer;

        private boolean mAddPipInputConsumerHandle;
        private boolean mAddWallpaperInputConsumerHandle;
        private boolean mAddRecentsAnimationInputConsumerHandle;

        boolean mInDrag;

        private void updateInputWindows(boolean inDrag) {
   
   
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");

            ......
            mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
            updateInputFocusRequest(mRecentsAnimationInputConsumer);

            ......
            }

            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }

.
<think> 我们之前讨论的是Android系统服务相关的内容,特别是关于InputMonitor的调用机制。根据用户当前的需求,用户希望了解com.android.server.wm.InputMonitor的相关信息,包括调用机制。因此,我们需要围绕这个类在Android窗口管理中的作用、它的主要方法以及调用流程进行解释。 首先,com.android.server.wm.InputMonitorAndroid窗口管理系统中的一个重要类,它属于WindowManagerService(WMS)模块。它的主要职责是监控输入事件(如触摸、按键等)的分发过程,并协调窗口之间的输入事件传递。 接下来,我们将详细说明InputMonitor的调用机制: 1. **InputMonitor的创建**:InputMonitor实例通常在WindowManagerService的初始化过程中创建。WindowManagerService会为每个显示(Display)创建一个InputMonitor对象。这是因为不同的显示设备可能有不同的输入配置。 2. **与InputManagerService的关联**:InputMonitor通过InputManagerService(IMS)来接收输入事件。IMS是Android输入系统的核心服务,它负责从设备驱动读取输入事件,并将事件分发给相应的窗口。 3. **事件分发过程**: - 当IMS有输入事件时,它会调用InputMonitor的方法(如`dispatchInputEvent`)来通知窗口管理系统。 - InputMonitor会根据当前窗口的布局和状态(如焦点窗口、触摸窗口等)决定将事件分发给哪个窗口。 - 在分发之前,InputMonitor可能会进行一些处理,例如检查是否存在系统覆盖层(如状态栏)需要优先处理事件,或者根据窗口的触摸区域(TouchRegion)过滤事件。 4. **与InputChannel的关联**:每个窗口在添加到WMS时,都会创建一个InputChannel,用于接收输入事件。InputMonitor负责管理这些InputChannel,并将事件发送到正确的InputChannel。 5. **输入事件的处理流程**: - InputMonitor将事件传递给目标窗口的InputChannel。 - 目标窗口的ViewRootImpl会通过其InputEventReceiver(通常是WindowInputEventReceiver)接收事件,然后交给DecorView进行事件分发,最终传递给具体的View。 6. **输入事件拦截**:InputMonitor还负责处理一些系统级的输入事件拦截。例如,当系统处于某些状态(如屏幕关闭、键盘弹出)时,InputMonitor可能会拦截事件,不将其分发给应用窗口。 7. **同步屏障(Synchronization Barrier)**:在Android系统中,输入事件的分发需要与UI线程同步。InputMonitor会确保在正确的时机将事件插入到目标窗口的消息队列中,避免在窗口正在处理其他消息(如布局、绘制)时插入事件。 8. **ANR(Application Not Responding)监控**:InputMonitor还参与ANR的检测。如果某个窗口在一定时间内没有处理完输入事件,InputMonitor会触发ANR报告流程。 下面我们用一个简化的序列图来描述输入事件的分发流程: ```mermaid sequenceDiagram participant IMS as InputManagerService participant IM as InputMonitor participant WMS as WindowManagerService participant InputChannel as 目标窗口的InputChannel participant ViewRootImpl IMS->>IM: dispatchInputEvent(event) IM->>WMS: 查询当前焦点窗口和触摸区域 WMS-->>IM: 返回目标窗口信息 IM->>InputChannel: 发送事件 InputChannel->>ViewRootImpl: 通过InputEventReceiver接收事件 ViewRootImpl->>DecorView: 分发事件 DecorView->>View: 事件传递 ``` 注意:上述序列图是一个简化的流程,实际过程更为复杂,涉及多个模块和状态判断。 最后,我们生成几个相关问题: §§相关问题§§ 1. InputMonitorAndroid输入系统中如何与InputManagerService交互? 2. InputMonitor如何处理多个触摸事件的分发? 3. 在Android系统中,InputMonitor在ANR检测中扮演什么角色? </think> ### com.android.server.wm.InputMonitor 解析 `com.android.server.wm.InputMonitor` 是 Android 窗口管理系统(WindowManagerService)的核心组件之一,主要负责协调输入事件(触摸、按键等)与窗口显示的关系。其核心功能包括: #### 1. **核心职责** - **输入事件分发**:监控并转发输入事件到正确的窗口 - **焦点管理**:跟踪当前获得焦点的窗口(如`mFocusedWindow`) - **输入通道管理**:维护窗口的`InputChannel`(与`InputDispatcher`通信的管道) - **同步屏障**:确保输入事件与VSync信号同步,避免画面撕裂 #### 2. **关键调用机制** ```mermaid graph LR A[InputDispatcher] --> B(InputMonitor.updateInputWindows) B --> C{遍历WindowState列表} C --> D[计算输入区域] D --> E[更新InputChannel] E --> F[通过Socket发送事件] F --> G[App进程处理事件] ``` 1. **输入事件入口**: - `InputDispatcher` 通过 `InputMonitor.updateInputWindows()` 触发事件分发流程 - 示例代码段: ```java // WindowManagerService.java void updateInputWindows() { mInputMonitor.updateInputWindows(true /*force*/); } ``` 2. **窗口状态同步**: - 遍历所有`WindowState`对象,调用`populateInputWindowHandle()`更新: - 窗口层级(`mInputWindowHandle.layer`) - 触摸区域(`touchableRegion`) - 焦点状态(`focusable`标志) - 关键判断逻辑: ```java if (win.canReceiveKeys()) { mInputWindowHandle.focusable = true; mInputWindowHandle.hasFocus = (win == mFocusedWindow); } ``` 3. **输入通道操作**: - 通过`InputChannel`与客户端进程通信: ```java InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.setInputChannel(inputChannels[0]); // 服务端保留 clientChannel = inputChannels[1]; // 发送到应用进程 ``` 4. **异常处理机制**: - ANR检测:5秒内未处理事件触发`notifyWindowUnresponsive()` - 输入丢失保护:通过`batchTimeout`机制合并连续事件 #### 3. **与其他模块交互** | 模块 | 交互方式 | 关键接口 | |------|----------|----------| | `InputManagerService` | Binder调用 | `IInputManager` | | `SurfaceFlinger` | 同步屏障 | `setInputWindows()` | | `ViewRootImpl` | Socket通信 | `InputEventReceiver` | | `ActivityManager` | ANR上报 | `appNotResponding()` | #### 4. **典型工作流** 1. 用户触摸屏幕 2. `InputReader` 读取事件 → `InputDispatcher` 分发 3. `InputMonitor` 确定目标窗口(基于`Z-order`和`touchableRegion`) 4. 通过`InputChannel`将事件传递到`ViewRootImpl` 5. 应用消费事件后返回`FINISHED`信号 > 注:输入事件延迟需控制在 **16ms** 内(60Hz刷新率要求)[^1] #### 5. **调试技巧** - 查看当前输入状态: ```shell adb shell dumpsys input ``` - 监控事件分发: ```shell adb shell getevent -lt ``` - 强制刷新输入窗口: ```java mInputMonitor.updateInputWindowsImmediately(); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值