android 输入系统

06-01 1546阅读

一、输入系统的核心角色与分层架构

Android 输入系统的本质是桥梁:一端连接硬件驱动产生的原始事件,另一端将事件精准派发给应用窗口。整个过程涉及三层架构和多个关键组件,可类比为 “快递分拣系统”:

1. 硬件与内核层(源头)
  • 角色:当用户触摸屏幕或按下按键时,硬件驱动将事件写入设备节点(如/dev/input),生成原始的内核事件(类似 “快递包裹的原始数据”)。
  • 技术实现:通过EventHub(事件枢纽)监听设备路径,使用epoll和inotify机制高效检测事件变化和设备插拔。

    系统内容:

    驱动上报

    struct RawEvent{

    nsecs_t when;

    nsecs_t readtime;

    int32_t deviceId; 输入设备唯一标识符

    int32_t type;  事件类型 如EV_KEY, EV_ABS

    int32_t code;  事件码

    int32_t value; 事件值

    }

    frameworks/native/services/inputflinger/reader/include/EventHub.h

    android 输入系统
    (图片来源网络,侵删)

    2. Native 层(事件处理与分发)
    • InputReader(事件快递员) :

      android 输入系统
      (图片来源网络,侵删)
        • 从EventHub读取原始事件(如触摸坐标、按键码),按规则封装为标准事件(如MotionEvent、KeyEvent)。
        • 类比:将 “原始包裹数据” 解析为 “标准化快递单”。
        • InputDispatcher(事件分拣员) :

            • 接收InputReader处理后的事件,结合窗口信息(如焦点窗口),将事件派发给对应的应用窗口。
            • 类比:根据 “快递单地址” 将包裹分拣到正确的配送路线。
            • InputManager(调度中心) :

                • 管理InputReader和InputDispatcher,创建并启动它们的工作线程。

                  1. 按键事件类型

                  RawEvent的 type ==EV_KEY:

                  rawEvent 的code 对应android的scanCode,

                  scanCode  通过  Generic.kl 映射到android 的keycode。

                  frameworks/base/data/keyboards/Generic.kl

                  1. 触摸事件类型

                  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 先用于触摸点 A(ID=1),抬起后 ID 重置为 -1;
                          • 新触摸点 B 按下时,可能再次使用槽位 0,但分配新 ID=2。

                            通过 ID 可确保触摸点的移动轨迹不会因槽位重用而混淆。

                            3. ABS_MT_TOUCH_MAJOR

                            • 作用:表示触摸点接触面积的主轴长度(椭圆的长轴,单位为像素或设备特定单位)。

                              可粗略理解为触摸点的 “宽度” 或 “接触区域大小”,例如手指按下时的接触面积。

                            • 值范围:通常为正整数,值越大表示接触面积越大。
                            • 示例:手指轻轻触摸时值为 20,用力按下时值为 30

                              4. 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 轴坐标(垂直位置)。
                                  • 坐标原点:通常为屏幕左上角(X=0, Y=0),向右 / 向下递增。
                                  • 单位:设备特定的逻辑单位(如像素、毫米等),需通过输入子系统校准后映射到屏幕像素。

                                    6. ABS_MT_PRESSURE

                                    • 作用:表示触摸点的压力值,用于检测触摸力度(如手指按下的轻重)。
                                      • 值为 0 时表示无压力(触摸点抬起);
                                      • 值越大表示压力越大。
                                      • 值范围:通常为 0 到设备支持的最大值(如 255、1024 等)。
                                      • 用途:实现压感功能,例如绘图应用中根据压力调整笔触粗细。

                                        3.EV_SYN(同步事件)​​

                                        • ​​核心作用​​:标记事件数据包的边界,确保用户空间程序能完整处理一组事件

                                          ·  ​​子类型​​:

                                          • ​​SYN_REPORT​​:表示当前数据包结束,触发用户空间处理累积事件(如鼠标移动后必须发送该事件完成坐标更新)

                                            ·  ​​SYN_DROPPED​​:内核缓冲区溢出时通知用户丢弃数据包并重新查询设备状态

                                            ·  ​​SYN_MT_REPORT​​:多点触控协议中分隔不同触点的数据包(Type A协议使用)

                                            ·  ​​底层依赖​​:驱动必须正确发送该事件,否则用户空间无法识别事件边界

                                            4.EV_REL(相对坐标事件)​​

                                            • ​​功能​​:报告相对位移变化,适用于鼠标等设备

                                              5.EV_SW(开关事件)​​

                                              • ​​功能​​:报告二进制状态切换,如设备休眠/唤醒、盖子开合等

                                                6.EV_MSC(杂项事件)​​

                                                • ​​功能​​:处理无法归类到其他类型的事件,如硬件特定状态或补充信息

                                                  3. Java 层(系统服务与交互)
                                                  • InputManagerService(IMS,总控中心) :

                                                      • 作为 Android 系统服务(运行于system_server进程),通过 JNI 与 Native 层交互。
                                                      • 与窗口管理服务(WMS)同步窗口信息,为InputDispatcher提供派发依据(如哪个窗口当前可见)。
                                                      • 类比:“快递总控中心”,协调底层分拣与上层应用的对接。

                                                        二、启动流程详解:从 IMS 初始化到线程启动

                                                        IMS 的启动伴随system_server进程启动,整个过程可分为对象创建和线程启动两个阶段,涉及 Java 层、JNI 层和 Native 层的跨层调用。

                                                        1. 初始化阶段:搭建组件链路

                                                        / /Java层:IMS初始化(InputManagerService.java)inputManager = new InputManagerService(context);

                                                        • 步骤 1:创建 Java 层 IMS 对象

                                                          • 初始化mHandler,运行在 “android.display” 线程(负责处理 Java 层消息)。

                                                            通过nativeInit调用 JNI,进入 Native 层初始化。

                                                            // JNI层:nativeInit(com_android_server_input_InputManagerService.cpp)NativeInputManager* im = new NativeInputManager(...);

                                                            步骤 2:创建 NativeInputManager(JNI 桥梁)

                                                            • 持有 Java 层 IMS 对象的引用(mServiceObj),作为 Native 层与 Java 层交互的桥梁。

                                                              • 创建EventHub(监听设备事件)和InputManager(管理读写线程)。

                                                                • // Native层:InputManager构造(InputManager.cpp)

                                                                  mDispatcher = new InputDispatcher(...); // 分拣员

                                                                  mReader = new InputReader(...); // 快递员

                                                                  步骤 3:创建 InputDispatcher 和 InputReader

                                                                  • InputDispatcher关联NativeInputManager(获取派发策略,如超时参数)。
                                                                  • InputReader通过QueuedInputListener与InputDispatcher建立连接(事件传递的枢纽)。

                                                                    2. 启动阶段:激活工作线程

                                                                    inputManager.start(); // 调用nativeStart

                                                                    · 启动 Native 层线程

                                                                    通过InputManager.start()启动两个核心线程:

                                                                    • ·  InputReaderThread:循环调用EventHub.getEvents()读取事件,交由InputReader处理。
                                                                    • InputDispatcherThread:循环处理事件队列,将事件派发给目标窗口。

                                                                      ·  关键线程分工:

                                                                      • ·  android.display 线程(Java 层):处理 IMS 的消息(如配置变更、ANR 通知)。
                                                                      • InputReaderThread(Native 层):专注读取硬件事件,不阻塞其他操作。
                                                                      • InputDispatcherThread(Native 层):专注事件派发,确保实时性。

                                                                        三、事件如何从硬件传到应用?

                                                                        事件分发链:InputReader → InputDispatcher → 应用窗口

                                                                        InputReader → InputDispatcher:

                                                                          1. 通过QueuedInputListener将封装好的事件传递给InputDispatcher,存入mInboundQueue队列。

                                                                        InputDispatcher 派发事件:

                                                                          1. 从 WMS 获取焦点窗口信息(通过 IMS 同步),确定事件目标窗口。
                                                                          2. 通过InputChannel(跨进程通信通道)将事件发送给应用的InputConsumer,最终由ViewRootImpl处理并传递给界面组件(如按钮、文本框)。
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码