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中同步处理Input事件。首先,我需要回忆一下Android的输入系统是怎么工作的。记得Input事件的处理涉及到多个层级,比如硬件驱动、InputReader、InputDispatcher,然后到应用层的View树处理。同步处理可能涉及到事件的分发机制,以及如何保证事件按顺序处理。 首先,应该解释一下Android的输入事件流程Input事件从硬件出发,被InputReader读取,然后通过InputDispatcher分发给对应的窗口。应用层通过主线程的Looper来接收这些事件,并在UI线程中处理。这个过程是同步的,因为事件必须按顺序处理,不能并发,否则可能导致界面状态不一致。 然后,可能需要提到同步处理的关键点,比如主线程的MessageQueue处理输入事件,View树的事件分发流程(dispatchTouchEvent,onTouchEvent等)。这里需要说明事件是如何从DecorView开始,经过层层ViewGroup传递到具体的子View的,并且在这个过程中,任何一个View都可以消费事件,阻止继续传递。 接着,用户可能想知道如何实现同步处理。比如,在自定义View时重写onTouchEvent,或者使用onTouchListener来拦截事件。这里要注意强调这些方法都是在主线程同步调用的,所以不能进行耗时操作,否则会导致ANR。 另外,可能还需要提到一些高级机制,比如使用同步屏障(Sync Barriers)来优先处理输入事件,或者Choreographer在VSYNC信号协调UI绘制和输入事件处理。这可以解释系统如何确保输入响应的及时性。 然后,根据用户提供的引用,特别是引用[4]中的方向传感器监听和线程模型改造,可能可以关联到输入事件处理中的性能优化,比如避免在UI线程做复杂计算,使用适当的线程模型来减少延迟。不过用户的问题是关于同步处理,所以重点还是在事件传递机制本身。 最后,用户可能需要解决方案,比如确保事件处理逻辑高效,避免阻塞主线程,或者使用Handler和Looper机制来确保事件按顺序处理。同时,可以提到在特定场景下如何同步更新UI状态,例如在游戏或实时应用中保持输入与界面反馈的一致性。 需要检查是否有相关的引用内容可以支持回答。比如引用[4]中的OrientationEventListener和线程模型优化,可能说明在处理输入事件时需要考虑设备方向变化带来的影响,但用户的问题更侧重于同步处理机制,所以可能引用[3]中的SettingsState同步更新,但不太相关。不过引用中提到的线程模型改造可能可以关联到输入事件处理的线程管理,比如确保事件在正确线程处理。 总结回答的结构应该是:先概述输入事件处理流程,然后详细说明同步处理机制的关键点,接着讨论解决方案和注意事项,最后给出相关的问题扩展。需要确保使用正确的中文术语,并且LaTeX格式符合要求,比如独立公式用$$...$$。</think>### Android Input事件同步处理机制解析 Android系统Input事件同步处理的核心在于**事件分发流水线**和**主线程消息循环机制**。系统通过多级流水线处理确保输入事件按正确时序传递到目标窗口,最终在UI线程完成同步处理。 #### 一、Input事件处理流程 1. **硬件层采集** 触摸屏/传感器通过Linux内核驱动生成原始事件,输入子系统以`/dev/input/eventX`节点形式暴露数据。 2. **系统服务处理** - `InputReader`:通过`EventHub`读取原始事件并解码为Android标准事件格式 - `InputDispatcher`:将事件分发到对应窗口的`InputChannel` $$ \text{事件传递路径} : \text{Driver} \rightarrow \text{InputReader} \rightarrow \text{InputDispatcher} \rightarrow \text{App} $$ 3. **应用层处理** 应用通过`ViewRootImpl$WindowInputEventReceiver`接收事件,最终进入主线程`MessageQueue`处理队列[^4]。 #### 二、同步处理关键机制 1. **主线程串行化** 所有UI操作(包括Input事件)通过`Handler/Looper`在主线程顺序执行,保证线程安全: ```java // 事件进入主线程消息队列 class ViewRootImpl { final class WindowInputEventReceiver extends InputEventReceiver { public void onInputEvent(InputEvent event) { enqueueInputEvent(event, this, 0, true); } } } ``` 2. **View树事件分发** 事件从`DecorView`开始逐级传递,通过`dispatchTouchEvent()`方法实现同步处理链: ``` Activity → Window → DecorView → ViewGroup → ... → Target View ``` 3. **同步屏障机制** 系统通过`MessageQueue.postSyncBarrier()`插入同步屏障,优先处理输入事件和绘制任务,确保16ms内的VSYNC周期完成响应。 #### 三、解决方案与最佳实践 1. **自定义事件处理** - 重写`View.onTouchEvent()`实现同步响应 - 使用`GestureDetector`处理复杂手势 ```java public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: // 立即响应按下事件 return true; } return super.onTouchEvent(event); } ``` 2. **性能优化要点** - 主线程事件处理逻辑需在**5ms内完成**,避免触发ANR - 耗时操作应移交工作线程,通过`Handler`同步更新UI状态 - 使用`Choreographer.postFrameCallback()`对齐VSYNC信号 3. **跨进程场景处理** 多窗口模式(如分屏)下,通过`InputMonitor`同步各窗口的Z-order,确保正确的事件目标窗口选择。 #### 四、典型问题排查 - **事件丢失**:检查`ViewGroup.onInterceptTouchEvent()`是否过早拦截 - **响应延迟**:使用`Systrace`分析主线程阻塞点 - **触摸坐标异常**:验证`View.getLocationOnScreen()`与事件坐标系的转换
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值