在InputReaderThread继承于Thread中,读取RawEvent数据流程如下:
1) Thread::_threadLoop()
2) InputReaderThread::threadLoop()
3) InputReader::loopOnce()
4) EventHub::getEvents()
在InputReader::loopOnce中,当调用EventHub->getEvents获取Input事件,当没有Input事件的时候,线程回阻塞,直到有输入事件,读取到到RawEvent之后,调用InputReader::processEventsLocked来处理这些事件,然后调用mQueuedListener->flush()把这些队列中的事件发送到InputDispatcher。下面看处理processEventsLocked(const RawEvent* rawEvents, size_tcount)方法,在该方法中处理两种事件:
n 处理设备增加、删除和修改事件
n 处理来自于事件驱动设备的事件(processEventsForDeviceLocked)
RawEvent结构体中有一个type变量,用这个变量来识别到底是什么事件:
n EventHubInterface::DEVICE_ADDED 添加设备事件
n EventHubInterface::DEVICE_REMOVED 删除设备事件
n EventHubInterface::FINISHED_DEVICE_SCAN 完成设备扫面事件
n 小于EventHubInterface::DEVICE_ADDED 设备输入事件,包括按键、触摸等
代码如下:
voidInputReader::processEventsLocked(const RawEvent* rawEvents, size_tcount) { for(const RawEvent* rawEvent = rawEvents; count;) { int32_ttype = rawEvent->type; size_tbatchSize = 1; if(type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_tdeviceId = rawEvent->deviceId; while(batchSize < count) { if(rawEvent[batchSize].type >=EventHubInterface::FIRST_SYNTHETIC_EVENT ||rawEvent[batchSize].deviceId != deviceId) { break; } batchSize+= 1; } processEventsForDeviceLocked(deviceId,rawEvent, batchSize); }else { switch(rawEvent->type) { caseEventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when,rawEvent->deviceId); break; caseEventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when,rawEvent->deviceId); break; caseEventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false);// can't happen break; } } count-= batchSize; rawEvent+= batchSize; } } |
voidInputReader::addDeviceLocked(nsecs_t when, int32_t deviceId){ ssize_tdeviceIndex = mDevices.indexOfKey(deviceId); InputDeviceIdentifieridentifier =mEventHub->getDeviceIdentifier(deviceId); uint32_tclasses = mEventHub->getDeviceClasses(deviceId); InputDevice*device = createDeviceLocked(deviceId, identifier,classes); mDevices.add(deviceId,device); bumpGenerationLocked(); } |
调用createDeviceLocked()创建了一个InputDevice对象,并添加到mDevices列表中。下面看看createDeviceLocked是如何创建设备的。
先根据mContext, deviceId, name, classes创建一个InputDevice对象,它用于表示单个输入设备的状态。其中的classes为对应Device的classes成员,它用于表示设备类型,定义如下:
enum{
INPUT_DEVICE_CLASS_KEYBOARD =0x00000001,
INPUT_DEVICE_CLASS_ALPHAKEY =0x00000002,
INPUT_DEVICE_CLASS_TOUCH =0x00000004,
INPUT_DEVICE_CLASS_CURSOR =0x00000008,
INPUT_DEVICE_CLASS_TOUCH_MT =0x00000010,
INPUT_DEVICE_CLASS_DPAD =0x00000020,
INPUT_DEVICE_CLASS_GAMEPAD =0x00000040,
INPUT_DEVICE_CLASS_SWITCH =0x00000080,
INPUT_DEVICE_CLASS_JOYSTICK =0x00000100,
INPUT_DEVICE_CLASS_VIBRATOR =0x00000200,
INPUT_DEVICE_CLASS_VIRTUAL =0x40000000,
INPUT_DEVICE_CLASS_EXTERNAL =0x80000000, }; |
创建InputDevice对象之后,会根据classs类型,创建对应的InputManager对象,InputMapper对象主要负责将输入的原始数据进行处理,使其转换成标准的输入事件,每一个InputDevice至少有一个InputMapper,类图关系如下:
这张图,我们关注下mContext变量,InputReader::mContext在构造时用自己的指针初始化了mContext,从而mContext::mReader则为此InputReader实例。在InputReader::createDeviceLocked中创建InputDevice时,把自己的mContext作为参数传入,从而把它保存在InputDevice::mContext中;在创建InputMapper时,以InputDevice作为参数,且InputMapper把它保存在mDevice中,然后从把InputDevice中的mContext也保存在InputMapper的mContext中。
这里我们主要关注的是触摸屏消息:
INPUT_DEVICE_CLASS_TOUCH_MT 多点触摸屏
INPUT_DEVICE_CLASS_TOUCH 单点触摸屏
//Touchscreens and touchpad devices. if(classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(newMultiTouchInputMapper(device)); }else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(newSingleTouchInputMapper(device)); } |
关注下两个变量:
n mContext变量
InputReader::mContext在构造时用自己的指针初始化了mContext,从而mContext::mReader则为此InputReader实例。在InputReader::createDeviceLocked中创建InputDevice时,把自己的mContext作为参数传入,从而把它保存在InputDevice::mContext中;在创建InputMapper时,以InputDevice作为参数,且InputMapper把它保存在mDevice中,然后从把InputDevice中的mContext也保存在InputMapper的mContext中。
n mQueuedListener变量
该变量是在InputReader构造函数中创建的QueuedListener对象,在QueuedListener的构造函数中,将InputDispatcher的实例作为参数赋给内部变量mInnerListener。
mContext->getListener()返回的就是mQueuedListener。
分析RawEvent结构体数据,
n RawEvent->type表示输入事件类型:
#define EV_SYN 0x00 //为结束标志 #define EV_REL 0x02 //相对坐标,如光标移动,报告的是相对最后一次位置的偏移
|
n RawEvent->code表示数据类型:
#define ABS_MT_POSITION_X 0x35 //表示x坐标 #define ABS_MT_POSITION_Y 0x36 //表示y坐标 #define ABS_MT_TOUCH_MAJOR 0x30 //接触面的长轴。 #define ABS_MT_TOUCH_MINOR 0x31 //接触面的短轴, #define ABS_MT_WIDTH_MAJOR 0x32 //接触工具的长轴 #define ABS_MT_WIDTH_MINOR 0x33 //接触工具的切面的短轴 #define ABS_MT_PRESSURE 0x 3a //接触工具对接触面的压力大小,可以用来代替上面的四个参数。 #define ABS_MT_ORIENTATION 0x34 #define ABS_MT_TRACKING_ID 0x39 //表示当前多少个手指触摸 |
n RawEvent->value 表示数据的值
对于多点触摸,消息发送方式如下:
ABS_MT_POSITION_X |
ABS_MT_POSITION_Y |
ABS_MT_TRACKING_ID |
ABS_MT_TOUCH_MAJOR |
ABS_MT_WIDTH_MAJOR |
SYN_MT_REPORT |
…… |
…… |
ABS_MT_POSITION_X |
ABS_MT_POSITION_Y |
ABS_MT_TRACKING_ID |
ABS_MT_TOUCH_MAJOR |
ABS_MT_WIDTH_MAJOR |
SYN_MT_REPORT |
SYN_REPORT |
其中ABS_MT_POSITION_X\Y表示触摸消息的坐标值,ABS_MT_TRACKING_ID表示目前数据是几个手指触摸,SYN_MT_REPORT表示某个触摸信息已经上报完,SYN_REPORT表示一笔完整的多点触摸消息已经上报完成。
对于多点触摸消息,将在MultiTouchInputMapper对消息处理,看看process方法:
voidMultiTouchInputMapper::process(const RawEvent* rawEvent){ TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); } voidTouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); //一个事件结束的标志 if(rawEvent->type == EV_SYN && rawEvent->code ==SYN_REPORT) { sync(rawEvent->when); } } |
mCursorButtonAccumulator处理EV_KEY类型输入事件
mCursorScrollAccumulator处理EV_REL类型输入事件
mTouchButtonAccumulator处理EV_KEY类型输入事件
mMultiTouchMotionAccumulator处理EV_ABS类型输入事件,也就是触摸输入事件,当满足rawEvent->type == EV_SYN &&rawEvent->code == SYN_REPORT条件时,说明一个事件已经完成上报,开始同步。
n sync(rawEvent->when)
处理EV_SYN:SYN_REPORT,我们的EV_SYN就在这儿被处理了,当然它是Touch Down时,所发事件的最后一个事件。这儿才是处理的重点。TouchInputMapper::sync将调用MultiTouchInputMapper::syncTouch函数。
n MultiTouchInputMapper::syncTouch
把mMultiTouchMotionAccumulator读取的数据存在mCurrentRawPointerData.pointers中,单点触摸的syncTouch一次处理一个RawEvent,在pointers中只有一个值;而多点触摸的syncTouch一次处理多个RawEvent,在pointers中有多个值,最多16个。
n TouchInputMapper::cookPointerData
根据TouchInputMapper::mCurrentRawPointerData->pointers中的数据,通过计算,最后生成TouchInputMapper::mCurrentCookedPointerData.pointerCoords,mCurrentCookedPointerData.pointerProperties和mCurrentCookedPointerData.idToIndex的数据。把Raw进行cook,之后生成了cooked数据。
n TouchInputMapper::dispatchTouches
调用dispatchMotion
n TouchInputMapper::dispatchMotion
根据cooked数据创建NotifyMotionArg对象,它描述了一个移动事件。
n 调用TouchInputMapper::getListener()->notifyMotion(&args)
TouchInputMapper::getListener()调用mContext->getListener(),此mContext为InputReader::mContext,所以其getListener()返回的则为InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion。
n mArgsQueue.push(newNotifyMotionArgs(*args))
把传递过来的NotifyMotionArg参数复制一份,然后加入QueuedInputListener::mArgsQueue例表中。
此时触摸事件的数据已经都放在了mArgsQueue列表中,在InputReader::LoopOnce中,调用mQueuedListener->flush()开始把数据分发到InputDispatcher中,mInnerListener就是InputDispatcher的实例。
voidQueuedInputListener::flush() { size_tcount = mArgsQueue.size(); for(size_t i = 0; i < count; i++) { NotifyArgs*args = mArgsQueue[i]; args->notify(mInnerListener); deleteargs; } mArgsQueue.clear(); } |
调用链表中每个NotifyArgs的notify函数这么多类NotifyArgs,为描述方便,下面以NotifyMotionArgs为例,其代码为:
voidNotifyMotionArgs::notify(const sp& listener) const { listener->notifyMotion(this); } |
InputDispatcherThread开启了一个线程来接收InputReader发送过来的消息,当没有消息的时候,线程进行了休眠,当有消息的时候,mLooer->wake()唤醒线程。InputDispatcherThread主循环如下:
1) Thread::_threadLoop()
2) InputDispatcherThread::threadLoop()
3) InputDispatcher::dispatchOnce()
4) dispatchOnceInnerLocked()
分发消息
5) mLooper->pollOnce()
其功能为等待超时或被pipe唤醒(InputReader线程调用InputDispatcher::notifyMotion时, InputDispatcher::notifyMotion根据情况调用mLooper->wake)。
经过第4节的介绍,以触摸消息为例,InputReader将NotifyMotionArgs结构体分发到了InputDispatcher。
voidInputDispatcher::notifyMotion(const NotifyMotionArgs* args){ …… //Just enqueue a new motion event. MotionEntry*newEntry = newMotionEntry(args->eventTime, args->deviceId,args->source, policyFlags, args->action,args->flags, args->metaState,args->buttonState, args->edgeFlags,args->xPrecision, args->yPrecision,args->downTime, args->pointerCount,args->pointerProperties, args->pointerCoords);
needWake= enqueueInboundEventLocked(newEntry); …… if(needWake) { mLooper->wake(); } } |
n 根据NotifyMotionArgs提供的信息,构造一个MotionEvent
n 调用InputDispatcher::enqueueInboundEventLocked把新构造的MotionEntry添加到InputDispatcher::mInboundQueue中,并返回是否需要唤醒mLooper<向pipe中写入数据>的标识。
以上操作都是在InputReader线程中完成的,现在应该InputDispatcher线程开始工作了。
在5.1中,调用了mLooper->wake()唤醒InputDispatcher线程,分发工作主要是在dispatchOnceInnerLocked方法中。
n 从mInboundQueue从中依次取出EventEntry的基类>
n 调用InputDispatcher::dispatchMotionLocked处理此MotionEntry
n 调用InputDispatcher::dispatchEventLocked
获取窗口对应的InputTarget,并获取对应的Connection,调用InputDispatcher::prepareDispatchCycleLocked()
n InputDispatcher::prepareDispatchCycleLocked
n 调用enqueueDispatchEntryLocked创建DispatchEntry对象,并把它增加到Connection::outboundQueue队列中。
n 调用InputDispatcher::startDispatchCycleLocked,接着它调用Connection::inputPublisher.publishMotionEvent来发布事件到ashmem buffer中,调用Connection::inputPublisher.sendDispatchSignal发送一个dispatch信号到InputConsumer通知它有一个新的消息到了,快来取消息吧