news 2026/8/17 21:27:36

Android InputDispatcher 跨 Display 触摸事件丢失分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android InputDispatcher 跨 Display 触摸事件丢失分析

每个 Display 都拥有自己独立且完整的生态,具体表现为各自管理着一组 Window。

1. 引子:从一个拖拽 Bug 说起

用户在 Launcher 中进行拖拽操作时,如果发生了 Display 焦点切换,拖拽的 View 会卡在屏幕上无法消失。

2. Android Input 管道全景

网上已有大量关于此主题的文章可供参考,本文仅作简要概述。

Android 输入事件的处理管道可分为五个层次:

  1. 硬件层:负责接收原始的触摸、按键等输入信号(例如,手指触摸屏幕产生一个触摸事件)。
  2. Linux 内核层:接收硬件信号,并将其封装成input_event结构,写入到如/dev/input/eventX之类的设备节点。
  3. Android Native 层:负责从设备节点(如/dev/input/eventX)读取原始的输入事件。
  4. Android Service 层:进行事件的解析、分发,并将其派发给上层的应用。
  5. 应用层:最终接收并消费处理输入事件。

3. TouchState:每个 Display 独立记账

3.1 mTouchStatesByDisplay 数据结构

mTouchStatesByDisplay是一个std::unordered_map,其键(key)为displayId。这意味着:

每个显示屏拥有自己独立的触摸状态,彼此互不干扰。

std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);

3.2 TouchState 结构体

struct TouchState { bool down; // 是否有手指按下? bool split; // 是否开启了分屏触摸? int32_t deviceId; // 是哪个输入设备的触摸?(防止多设备冲突) uint32_t source; // 输入源(触摸屏?鼠标?) int32_t displayId; // 是哪个显示屏的触摸? std::vector<TouchedWindow> windows; // 当前触摸了哪些窗口? std::vector<sp<InputWindowHandle>> portalWindows; // 穿过了哪些 portal window? std::vector<TouchedMonitor> gestureMonitors; // 手势监听器 };

4. 根因分析:findTouchedWindowTargetsLocked

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // ... done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); } int32_t InputDispatcher::dispatchMotionLocked(...) { injectionResult = findTouchedWindowTargetsLocked(...); }

当后续事件携带的displayIdmTouchStatesByDisplay中不存在对应的TouchState时,find(displayId)会返回end(),此时oldState不会从该 Display 获取到已有触摸状态

Step 1:拷贝旧状态

const TouchState* oldState = nullptr; TouchState tempTouchState; auto oldStateIt = mTouchStatesByDisplay.find(displayId); // 使用 displayId 查询 map if (oldStateIt != mTouchStatesByDisplay.end()) { oldState = &(oldStateIt->second); tempTouchState.copyFrom(*oldState); }

Step 2:判断是否是新手势

bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);

Step 3:设备切换检测

bool switchedDevice = tempTouchState.deviceId >= 0 && tempTouchState.displayId >= 0 && (tempTouchState.deviceId != entry.deviceId || tempTouchState.source != entry.source || tempTouchState.displayId != displayId); // ← 此处 displayId 不同会触发!

如果switchedDevice == true且当前有手指按下(tempTouchState.down == true),则会执行以下逻辑:

if (switchedDevice && tempTouchState.down && !down && !isHoverAction) { ALOGI("Dropping event because a pointer for a different device is already down " "in display %" PRId32, displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; // ← 直接丢弃事件! } Failed: // 1. 检查权限 if (injectionPermission != INJECTION_PERMISSION_GRANTED) { return injectionResult; // ← 直接返回,什么都不做 } // 2. 更新状态(但 wrongDevice 时不更新) if (!wrongDevice) { // 更新 mTouchStatesByDisplay // 但没有发送 CANCEL 事件! } return injectionResult;

问题所在:当后续事件的displayId与当前TouchState中记录的displayId不一致时,会使switchedDevicetrue。如果此时tempTouchState.down仍为true,且当前事件不是新的DOWN、也不是 Hover 事件,则该事件会进入Failed路径,并以INPUT_EVENT_INJECTION_FAILED结束处理。

进一步影响:该路径不会按照正常的触摸事件分发流程继续处理当前事件,因此原有拖拽手势无法正常完成后续的事件状态转换。如果拖拽 View 依赖后续的CANCEL事件清理自身状态,而该CANCEL又没有在后续流程中产生或送达应用层,就可能出现拖拽 View 残留在屏幕上的现象。

5. 调试方法

  • dumpsys input
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/17 21:23:48

Bitwarden:开源免费的跨平台密码管理器,端到端加密

Bitwarden&#xff1a;开源免费的跨平台密码管理器&#xff0c;端到端加密一款开源的跨平台密码管理器&#xff0c;代码完全开源&#xff08;AGPL-3.0&#xff09;&#xff0c;支持端到端加密&#xff0c;跨平台覆盖 Windows、macOS、Linux、Android、iOS 和浏览器扩展。&#…

作者头像 李华
网站建设 2026/8/17 21:23:32

热门八股-JUC

线程基础1.进程和线程的区别进程可以理解为一个正在运行的程序&#xff0c;比如启动一个JVM就是一个进程。线程是进程里面的执行单元&#xff0c;一个进程可以有多个线程。常见的区别&#xff1a;进程是资源分配最小单位&#xff0c;线程是CPU调度最小单位&#xff0c;属于进程…

作者头像 李华
网站建设 2026/8/17 21:22:50

特斯拉Model 3如何以鲶鱼效应重塑中国新能源汽车产业格局

1. 一个搅局者的入场&#xff1a;Model 3入华前的中国车市格局2019年初&#xff0c;当第一批贴着“中国制造”标签的特斯拉Model 3标准续航升级版从上海超级工厂的生产线上缓缓驶下时&#xff0c;可能没有多少人能完全预料到&#xff0c;这辆起售价定在35.58万元的纯电动轿车&a…

作者头像 李华
网站建设 2026/8/17 21:22:20

江西五十铃新款D-MAX谍照解析:中期改款设计、动力与市场前瞻

1. 从谍照到上市&#xff1a;一次关于新款D-MAX的深度推演最近&#xff0c;网络上流传出一组江西五十铃新款D-MAX的测试谍照&#xff0c;结合“或上半年上市”这个关键时间点&#xff0c;这无疑在皮卡圈和越野爱好者中投下了一颗石子。作为一款在国内市场耕耘多年、拥有坚实口碑…

作者头像 李华
网站建设 2026/8/17 21:20:49

网盘直链下载怎么玩才不折腾?我的两年亲测与避坑记录

网盘直链下载怎么玩才不折腾&#xff1f;我的两年亲测与避坑记录 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…

作者头像 李华