Android系统MotionEvent处理InputReader线程基本原理总结
基本原理
触摸事件数据的传递基本流程大致应该分为如下几个阶段
首先,当然是硬件感应 - - >
固件软件 - - >
Kernel驱动, 驱动将数据写入设备文件 - - >
用户空间进程, android中对应的当然是system进程, 首先input reader线程从设备文件读取数据 - - >
system进程input dispatcher线程拿到input reader线程转化后的数据,准备进行分发 - - >
app进程, native层receiver对象被回调, 接收数据 - - >
app进程, java层ViewRootImpl对象被回调, 接收数据 - - >
最后就是我们熟悉的decorview - > activity - > window - > decorview - > viewgroup
这次先分享一下input reader线程对触摸事件数据处理的大致原理。个人感觉逻辑细节还是相当复杂的,所以,不足之处还请高手们多多指点。
android将从设备文件中读取数据的操作封装在EventHub类, 当有数据到达设备文件后, input reader线程会被唤醒, 调用mEventHub→getEvents获取数据, 数据格式为RawEvent, input reader的主要工作就是将RawEvent转化为Motion Event交给input dispatcher进行分发.
设备文件目录在/dev/input
通过命令 adb shell getevent -p查看哪个设备文件是用于触摸事件的
adb shell getevent /dev/input/设备文件名, 可以打印数据
RawEvent
nsecs_t when;
int32_t deviceId;
int32_t type;
int32_t code;
int32_t value;
type和code用于区分数据类型
根据slot协议, 数据类型应该是分为两种EV_ABS和EV_SYN, 通过type来标识, 每种type对应若干个code, EV_SYN有SYN_REPORT, EV_ABS有
ABS_MT_SLOT
ABS_MT_TRACKING_ID
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_TOUCH_MAJOR
ABS_MT_TOUCH_MINOR
ABS_MT_WIDTH_MAJOR
ABS_MT_WIDTH_MINOR
ABS_MT_ORIENTATION
ABS_MT_PRESSURE
ABS_MT_DISTANCE
ABS_MT_TOOL_TYPE
Input Reader线程的启动
启动代码入口如下
InputManager::start
InputReaderThread→run
InputReaderThread->threadLoop
主要类结构
Input reader处理数据的主要逻辑封装在类InputMapper中, 主要的类结构如下
处理数据主要流程
InputReader::loopOnce
EventHub::getEvents
InputReader::processEventsLocked
InputReader::processEventsForDeviceLocked
InputDevice::process
InputMapper:: process
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
mMultiTouchMotionAccumulator.process(rawEvent);
}
关于 MultiTouchInputMapper::process的处理逻辑如下
Input Reader依据slot协议转化RawEvent数据
数据处理的主要流程InputReader - > InputDevice - > InputMapper
对于多点触摸,RawEvent数据转化的核心逻辑在 MultiTouchInputMapper
MultiTouchInputMapper对象持有MultiTouchMotionAccumulator, MultiTouchMotionAccumulator对象持有一个Slot对象数组,一个Slot对象对应一个手指的触摸数据.
MultiTouchMotionAccumulator负责将RawEvent数据对slot数组进行赋值,TouchInputMapper::process将slot数组转化成其他数据结构.
数据的转化流程大致如下:
RawEvent - > Slot - > RawPointerData - > CookedPointerData
RawPointerData持有一个Pointer对象数组, 每一个Pointer对应一个Slot
CookedPointerData持有一个PointerCoords数组和一个PointerProperties数组,分别记录不同类别的数据.
数据转为完成后,InputReader线程会将CookedPointerData数据插入到一个数据队列,InputDispatcher线程会从该队列读取数据,进行dispatcher阶段的处理.
一个简单的slot数据示例
EV_ABS ABS_MT_TRACKING_ID 0000000e
EV_ABS ABS_MT_POSITION_X 0000011c
EV_ABS ABS_MT_POSITION_Y 000002b7
EV_ABS ABS_MT_PRESSURE 0000009b
EV_SYN SYN_REPORT 00000000 //一个Slot数据收集完毕,由 ABS_MT_TRACKING_ID的值可以判断出这些数据为down事件数据
EV_ABS ABS_MT_POSITION_X 0000011b
EV_ABS ABS_MT_POSITION_Y 000002b8
EV_ABS ABS_MT_PRESSURE 0000008f
EV_SYN SYN_REPORT 00000000 //一个move事件数据收集完毕
EV_ABS ABS_MT_TRACKING_ID ffffffff
EV_SYN SYN_REPORT 00000000 //up事件完成
前后相邻的两个slot数据不会重复传递, 比如, 最后up事件的各个数据值和move事件是相同的,所以,只有 ABS_MT_TRACKING_ID上报.
这是一个单指滑动的示例,所以没有ABS_MT_SLOT 的数值上报.