android 输入系统
一、输入系统的核心角色与分层架构Android 输入系统的本质是桥梁一端连接硬件驱动产生的原始事件另一端将事件精准派发给应用窗口。整个过程涉及三层架构和多个关键组件可类比为 “快递分拣系统”1. 硬件与内核层源头角色当用户触摸屏幕或按下按键时硬件驱动将事件写入设备节点如/dev/input生成原始的内核事件类似 “快递包裹的原始数据”。技术实现通过EventHub事件枢纽监听设备路径使用epoll和inotify机制高效检测事件变化和设备插拔。驱动上报struct RawEvent{nsecs_t when;nsecs_t readtime;int32_t deviceId; 输入设备唯一标识符int32_t type; 事件类型 如EV_KEY EV_ABSint32_t code; 事件码int32_t value; 事件值}RawEvent的定义位于 frameworks/native/services/inputflinger/reader/include/EventHub.h2. Native 层事件处理与分发InputReader事件快递员从EventHub读取原始事件如触摸坐标、按键码按规则封装为标准事件如MotionEvent、KeyEvent。类比将 “原始包裹数据” 解析为 “标准化快递单”。InputDispatcher事件分拣员接收InputReader处理后的事件结合窗口信息如焦点窗口将事件派发给对应的应用窗口。类比根据 “快递单地址” 将包裹分拣到正确的配送路线。InputManager调度中心管理InputReader和InputDispatcher创建并启动它们的工作线程。2.1 按键事件类型RawEvent的 type EV_KEY:rawEvent 的code 对应android的scanCode,scanCode 通过 Generic.kl 映射到android 的keycode。通常使用 frameworks/base/data/keyboards/Generic.kl 建立linux到android的按键映射关系。2.2 触摸事件类型RawEvent的type EV_ABS (绝对坐标事件)在 Linux 输入子系统Input Subsystem中多点触控Multi-Touch事件通过一系列以 ABS_MT_ 开头的绝对坐标类事件代码ABS 代表 Absolute Position来描述每个触摸点Slot的属性。以下是你列出的各个 ABS_MT_ 事件的详细说明1. ABS_MT_SLOT作用标识当前操作的触摸点槽位Slot。多点触控设备通过 “槽位” 机制管理多个触摸点类似数组索引每个槽位对应一个独立的触摸点。当设备报告某个触摸点的属性时需先通过 ABS_MT_SLOT 指明操作的是哪个槽位。值范围通常从 0 开始递增如 0、1、2...具体取决于设备支持的最大触摸点数如 5 点触控则槽位为 0~4。2. ABS_MT_TRACKING_ID作用为每个触摸点分配唯一的追踪 ID用于在触摸点生命周期内按下、移动、抬起标识其身份。当触摸点按下时系统分配一个非负整数 ID如 1、2...当触摸点抬起时ID 会被重置为 -1表示该槽位不再被占用。值范围有效触摸点 0如 1, 2无效 / 释放的槽位-1。用途区分不同触摸点即使槽位重用例如槽位 0 先用于触摸点 AID1抬起后 ID 重置为 -1新触摸点 B 按下时可能再次使用槽位 0但分配新 ID2。通过 ID 可确保触摸点的移动轨迹不会因槽位重用而混淆。3. ABS_MT_TOUCH_MAJOR作用表示触摸点接触面积的主轴长度椭圆的长轴单位为像素或设备特定单位。可粗略理解为触摸点的 “宽度” 或 “接触区域大小”例如手指按下时的接触面积。值范围通常为正整数值越大表示接触面积越大。示例手指轻轻触摸时值为 20用力按下时值为 304. ABS_MT_WIDTH_MAJOR作用表示触摸点接触面积的次轴长度椭圆的长轴单位与 ABS_MT_TOUCH_MAJOR 一致。在某些设备中TOUCH_MAJOR 和 WIDTH_MAJOR 可能分别对应椭圆的长轴和短轴用于描述触摸点的形状。值范围正整数通常与 ABS_MT_TOUCH_MAJOR 成比例。5. ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y作用ABS_MT_POSITION_X触摸点在屏幕坐标系中的 X 轴坐标水平位置。ABS_MT_POSITION_Y触摸点在屏幕坐标系中的 Y 轴坐标垂直位置。坐标原点通常为屏幕左上角X0, Y0向右 / 向下递增。单位设备特定的逻辑单位如像素、毫米等需通过输入子系统校准后映射到屏幕像素。6. ABS_MT_PRESSURE作用表示触摸点的压力值用于检测触摸力度如手指按下的轻重。值为 0 时表示无压力触摸点抬起值越大表示压力越大。值范围通常为 0 到设备支持的最大值如 255、1024 等。用途实现压感功能例如绘图应用中根据压力调整笔触粗细。2.3.EV_SYN同步事件核心作用标记事件数据包的边界确保用户空间程序能完整处理一组事件· 子类型SYN_REPORT表示当前数据包结束触发用户空间处理累积事件如鼠标移动后必须发送该事件完成坐标更新· SYN_DROPPED内核缓冲区溢出时通知用户丢弃数据包并重新查询设备状态· SYN_MT_REPORT多点触控协议中分隔不同触点的数据包Type A协议使用· 底层依赖驱动必须正确发送该事件否则用户空间无法识别事件边界2.4.EV_REL相对坐标事件功能报告相对位移变化适用于鼠标等设备2.5.EV_SW开关事件功能报告二进制状态切换如设备休眠/唤醒、盖子开合等2.6.EV_MSC杂项事件功能处理无法归类到其他类型的事件如硬件特定状态或补充信息3. Java 层系统服务与交互InputManagerServiceIMS总控中心作为 Android 系统服务运行于system_server进程通过 JNI 与 Native 层交互。与窗口管理服务WMS同步窗口信息为InputDispatcher提供派发依据如哪个窗口当前可见。类比“快递总控中心”协调底层分拣与上层应用的对接。二、启动流程详解从 IMS 初始化到线程启动IMS 的启动伴随system_server进程启动整个过程可分为对象创建和线程启动两个阶段涉及 Java 层、JNI 层和 Native 层的跨层调用。1. 初始化阶段搭建组件链路/ /Java层IMS初始化InputManagerService.javainputManager new InputManagerService(context);步骤 1创建 Java 层 IMS 对象初始化mHandler运行在 “android.display” 线程负责处理 Java 层消息。通过nativeInit调用 JNI进入 Native 层初始化。// JNI层nativeInitcom_android_server_input_InputManagerService.cppNativeInputManager* im new NativeInputManager(...);步骤 2创建 NativeInputManagerJNI 桥梁持有 Java 层 IMS 对象的引用mServiceObj作为 Native 层与 Java 层交互的桥梁。创建EventHub监听设备事件和InputManager管理读写线程。// Native层InputManager构造InputManager.cppmDispatcher new InputDispatcher(...); // 分拣员mReader new InputReader(...); // 快递员步骤 3创建 InputDispatcher 和 InputReaderInputDispatcher关联NativeInputManager获取派发策略如超时参数。InputReader通过QueuedInputListener与InputDispatcher建立连接事件传递的枢纽。2. 启动阶段激活工作线程inputManager.start(); // 调用nativeStart·启动 Native 层线程通过InputManager.start()启动两个核心线程InputReaderThread循环调用EventHub.getEvents()读取事件交由InputReader处理。InputDispatcherThread循环处理事件队列将事件派发给目标窗口。·关键线程分工android.display 线程Java 层处理 IMS 的消息如配置变更、ANR 通知。InputReaderThreadNative 层专注读取硬件事件不阻塞其他操作。InputDispatcherThreadNative 层专注事件派发确保实时性。三、事件如何从硬件传到应用事件分发链InputReader → InputDispatcher → 应用窗口InputReader → InputDispatcher通过QueuedInputListener将封装好的事件传递给InputDispatcher存入mInboundQueue队列。InputDispatcher 派发事件从 WMS 获取焦点窗口信息通过 IMS 同步确定事件目标窗口。通过InputChannel跨进程通信通道将事件发送给应用的InputConsumer最终由ViewRootImpl处理并传递给界面组件如按钮、文本框。四. 应用层的事件传递ViewRootImpl -DecorView 的dispatchTouchEventAndroid 系统ViewGroup的dispatchTouchEvent 是触摸事件分发核心方法整个 Android 触摸分发、拦截、子 View 投递、滑动冲突全部由这段逻辑驱动。全程分为以下步骤1.安全校验与初始化无障碍焦点、调试日志、安全过滤2.DOWN 事件重置状态每次新手势按下清空上一轮触摸缓存3.判断是否拦截事件intercepted onInterceptTouchEvent(ev)核心滑动判定入口RecyclerView 左右 / 上下滑动判断就在这里4.未拦截时遍历子 View寻找能接收触摸的子 View建立TouchTarget链表5.向所有有效子 TouchTarget 分发事件dispatchTransformedTouchEvent拦截时给子 View 发送 CANCEL6.UP/CANCEL 手势结束清空触摸状态7.返回handled标记当前 ViewGroup 是否消费本次触摸。其中 dispatchTransformedTouchEvent 是ViewGroup 的私有方法。负责将触摸事件分发给子view。三段触摸源码完整调用链路串联ViewGroup.dispatchTouchEvent总调度拦截判断、构建TouchTarget链表 ↓dispatchTransformedTouchEvent坐标转换、多指裁剪、下发CANCEL工具方法 ↓View.dispatchTouchEvent普通控件处理触摸OnTouchListener onTouchEvent手指按下 ACTION_DOWN│▼Activity.dispatchTouchEvent()│▼DecorView.dispatchTouchEvent()│▼LinearLayout.dispatchTouchEvent()│├── LinearLayout.onInterceptTouchEvent()│ ││ ├── true → LinearLayout.onTouchEvent()│ ││ └── false → 继续向子 View 分发▼RecyclerView.dispatchTouchEvent()│├── RecyclerView.onInterceptTouchEvent()│ ││ ├── true → RecyclerView.onTouchEvent()│ ││ └── false → 继续分发给 ItemView▼ItemView.dispatchTouchEvent()│▼Button.dispatchTouchEvent()│├── OnTouchListener.onTouch()│ ├── true → 事件到此结束│ └── false → 继续│▼Button.onTouchEvent()│├── true → Button 消费事件└── false → 事件逐层回传给父容器处理