前端好学还是后端好学宝鸡seo
概述
本文主要描述了Android Input框架中的InputReader的功能,InputReader模块的功能,总结成一句话就是InputReader获取输入设备的事件并将事件进行加工处理,然后传递给QueuedInputListener,最终QueuedInputListener将事件传递给InputDispatcher模块处理,事件处理的方向就是:
InputReader -> QueuedInputListener -> InputDispatcher
本文涉及的源码路径
frameworks/native/services/inputflinger/EventHub.cpp
frameworks/native/services/inputflinger/EventHub.h
frameworks/native/services/inputflinger/InputReader.cpp
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
InputReader的初始化
InputReader对象由InputManager创建如下所示:
InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {/* 创建事件分发对象 */mDispatcher = new InputDispatcher(dispatcherPolicy);/* 创建事件获取对象 */mReader = new InputReader(eventHub, readerPolicy, mDispatcher);initialize();
}
继续深入InputReader类的构造函数,如下所示:
InputReader::InputReader(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) :......mConfigurationChangesToRefresh(0) {// 初始化事件监听器mQueuedListener = new QueuedInputListener(listener);......
}
Inputreader的构造函数比较简单,在这里我们关注构造函数的第一个参数和第三个参数。
eventHub: 获取事件来源的对象,InputReader通过EventHub获取输入设备上报的事件;
listener: InputReader处理完事件后的传递目的地,后面的章节有描述处理流程;
InputReader的运行
在InputManager的初始化过程中,会创建一个InputReadThread线程,如下所示:
void InputManager::initialize() {/* 创建事件获取线程 */mReaderThread = new InputReaderThread(mReader);......
}
InputManager初始化完成开始运行的时候会调用线程的运行方法,对InputReader来说最终调用InputReader::loopOnce, 如下所示:
void InputReader::loopOnce() {......size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lock......// 处理获取到的intput事件if (count) {processEventsLocked(mEventBuffer, count);}......} // release lock......// 刷新监听队列,将InputReader的事件处理结果,传递给InputDispatcher处理mQueuedListener->flush();
}
InputReader的事件获取
InputReader在Thread线程中调用EventHub的getEvents方法获取输入事件,如下所示:
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
该方法将获取到input事件保存在mEventBuffer中,并返回获取到的事件个数
InputReader的事件处理
InputReader从EventHub获取到输入事件后,调用processEventsLocked方法,该方法的核心代码如下所示:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count;) {int32_t type = rawEvent->type;size_t batchSize = 1;if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {int32_t deviceId = rawEvent->deviceId;//统计同一个设备上报的事件数while (batchSize < count) {if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT|| rawEvent[batchSize].deviceId != deviceId) {break;}batchSize += 1;}
#if DEBUG_RAW_EVENTSALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif/*** 处理deviceID设备的上报的事件* @batchSize: 事件个数*/processEventsForDeviceLocked(deviceId, rawEvent, batchSize);} else {// 处理EventHub上报的输入设备增加和删除switch (rawEvent->type) {case EventHubInterface::DEVICE_ADDED:addDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::DEVICE_REMOVED:removeDeviceLocked(rawEvent->when, rawEvent->deviceId);break;case EventHubInterface::FINISHED_DEVICE_SCAN:handleConfigurationChangedLocked(rawEvent->when);break;default:ALOG_ASSERT(false); // can't happenbreak;}}count -= batchSize;rawEvent += batchSize;}
}
processEventsLocked:方法主要完成如下的功能:
1、处理系统已经存在的输入设备上报的事件;
2、处理系统输入设备的增加和删除事件;
设备添加和删除
本章节主要描述当系统增加一个输入设备时的InputReader处理流程,对于系统设备的删除和扫描的处理流程与增加处理流程类似,这里不再描述。下面我们从系统增加输入设备的处理流程进行描述。系统增加输入设备调用addDeviceLocked方法,addDeviceLocked的核心代码如下所示:
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {ssize_t deviceIndex = mDevices.indexOfKey(deviceId);// 设备已经增加进来了,直接返回if (deviceIndex >= 0) {ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);return;}......// 创建InputDevice设备管理对象// @deviceId: 设备ID// @classes: 输入设备类型InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);device->configure(when, &mConfig, 0);device->reset(when);......mDevices.add(deviceId, device);......
}
addDeviceLocked主要完成如下功能:
a、检测该设备是否已经增加过了,如果是,直接返回;
b、根据输入设备的类型,创建InputDevice设备;
c、将创建的InputDevice设备加入到InputReader设备管理容器中;
接着我们分析createDeviceLocked方法,后续我们主要分析多点触控设备的事件处理,因此我们只保留与多点触控相关的核心实现如下所示:
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,const InputDeviceIdentifier& identifier, uint32_t classes) {InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),controllerNumber, identifier, classes);......// 多点触控if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {device->addMapper(new MultiTouchInputMapper(device));} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {device->addMapper(new SingleTouchInputMapper(device));}return device;
}
createDeviceLocked方法的核心功能比较简单:
a、创建InputDevice设备;
b、根据输入设备的类型安装对应的事件处理器,Android系统可以处理的输入设备种类很多,对于每一类输入设备Android系统都抽象出了一个事件处理器处理该类设备上报的输入事件,对于多点触控设备来说,就是安装MultiTouchInputMapper事件处理器;
c、返回InputDevice设备;
d、这里没有描述InputMapper的实现机制,它的主要作用就是定义事件处理的接口,比如鼠标设备的处理使用CursorButtonAccumulator类,单点触控类设备使用SingleTouchInputMapper,多点触控设备使用MultiTouchInputMapper等,感兴趣的同学可以阅读Android源码去分析它们之间的关系;
设备上报事件
设备上报的输入事件处理函数是processEventsForDeviceLocked,该方法的核心实现,如下所示:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,const RawEvent* rawEvents, size_t count) {......device->process(rawEvents, count);
}
进一步调用InputDevice中的process方法,实现如下:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {......size_t numMappers = mMappers.size();for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {......} else {for (size_t i = 0; i < numMappers; i++) {InputMapper* mapper = mMappers[i];mapper->process(rawEvent);}}}
}
该方法的核心功能就是遍历每一个事件,调用设备自己注册的事件处理器进行处理,对于多点触控设备来说,调用如下的方法:
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {TouchInputMapper::process(rawEvent);/* 处理多点触控坐标信息 */mMultiTouchMotionAccumulator.process(rawEvent);
}
继续调用TouchInputMapper类中的process进行处理,该方法的核心实现,如下所示:
void TouchInputMapper::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);}
}
事件处理的具体细节,我们不再深入谈论,该方法当事件处理完成后,调用sync进行事件同步,核心如下所示:
void TouchInputMapper::sync(nsecs_t when) {......// Sync touch// 同步触摸坐标syncTouch(when, next);......processRawTouches(false /*timeout*/);
}
该方法会调用syncTouch这个虚拟方法,对于多点触控设备来说,最终调用MultiTouchInputMapper子类实现syncTouch, 这里不再详细展开描述。然后调用processRawTouches开始事件的处理,实现方法如下所示:
void TouchInputMapper::processRawTouches(bool timeout) {......const size_t N = mRawStatesPending.size();size_t count;// 遍历每一个上报的事件for(count = 0; count < N; count++) {const RawState& next = mRawStatesPending[count];......mCurrentRawState.copyFrom(next);if (mCurrentRawState.when < mLastRawState.when) {mCurrentRawState.when = mLastRawState.when;}cookAndDispatch(mCurrentRawState.when);}// 事件处理完成,清空mRawStatesPendingif (count != 0) {mRawStatesPending.removeItemsAt(0, count);}.......
}
接着调用cookAndDispatch方法,核心实现如下所示:
void TouchInputMapper::cookAndDispatch(nsecs_t when) {// Always start with a clean state.mCurrentCookedState.clear();......cookPointerData();......} else {// 触摸屏......if (!mCurrentMotionAborted) {dispatchButtonRelease(when, policyFlags);dispatchHoverExit(when, policyFlags);dispatchTouches(when, policyFlags);dispatchHoverEnterAndMove(when, policyFlags);dispatchButtonPress(when, policyFlags);}......}......
}
该方法中,我们为了叙述的简单,只保留了触摸屏幕相关的处理,cookPointerData方法的实现,这里不详细描述,主要就是处理坐标信息,对于触摸屏幕设备来说,就是调用dispatchTouches方法接着处理,核心实现如下所示:
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {......if (currentIdBits == lastIdBits) {if (!currentIdBits.isEmpty()) {......// 滑动dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,AMOTION_EVENT_EDGE_FLAG_NONE,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,currentIdBits, -1,mOrientedXPrecision, mOrientedYPrecision, mDownTime);}} else {......// Dispatch pointer up events.// 触点抬起while (!upIdBits.isEmpty()) {uint32_t upId = upIdBits.clearFirstMarkedBit();dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,mLastCookedState.cookedPointerData.pointerProperties,mLastCookedState.cookedPointerData.pointerCoords,mLastCookedState.cookedPointerData.idToIndex,dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);dispatchedIdBits.clearBit(upId);}......if (moveNeeded && !moveIdBits.isEmpty()) {ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}// Dispatch pointer down events using the new pointer locations.// 触点按下while (!downIdBits.isEmpty()) {......dispatchMotion(when, policyFlags, mSource,AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,mCurrentCookedState.cookedPointerData.pointerProperties,mCurrentCookedState.cookedPointerData.pointerCoords,mCurrentCookedState.cookedPointerData.idToIndex,dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);}}
}
该方法中会处理三种触摸动作,滑动,抬起和按下,最终调用dispatchMotion方法进行处理,核心实现如下所示:
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,......float xPrecision, float yPrecision, nsecs_t downTime) {......// 根据触摸屏幕的坐标事件,初始化NotifyMotionArgs对象NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,action, actionButton, flags, metaState, buttonState, edgeFlags,mViewport.displayId, pointerCount, pointerProperties, pointerCoords,xPrecision, yPrecision, downTime);// 找到InputReader的Listen,在初始时指定,最终指向是QueuedInputListenergetListener()->notifyMotion(&args);
}
该方法的核心,就是构造一个NotifyMotionArgs,然后调用InputReader自己的listen中的方法,最终调用QueuedInputListener中的notifyMotion,核心实现如下:
// 加入到内部mArgsQueue队列中
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {mArgsQueue.push(new NotifyMotionArgs(*args));
}
该方法的实现非常简单,构造一个NotifyMotionArgs,然后加入mArgsQueue队列中。
TouchInputMapper方法的process处理流程方法,讲述完成,然后我们回到MultiTouchInputMapper,接着调用了mMultiTouchMotionAccumulator中的process方法,这里不再展开叙述。
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {TouchInputMapper::process(rawEvent);/* 处理多点触控坐标信息 */mMultiTouchMotionAccumulator.process(rawEvent);
}
至此,一个输入设备的事件处理流程讲述完成,最后,我们回到InputReader线程执行函数的,如下所示:
void InputReader::loopOnce() {......size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lockAutoMutex _l(mLock);mReaderIsAliveCondition.broadcast();// 处理获取到的intput事件if (count) {processEventsLocked(mEventBuffer, count);}......} // release lock......// 刷新监听队列,将InputReader的事件处理结果,传递给InputDispatcher处理mQueuedListener->flush();
}
我们可以看到,设备上报的所有输入事件处理完成后,最后调用mQueuedListener的flush方法。这个方法的实现,下一个章节进行描述。
InputReader事件传递
上一个章节,我们描述了InputReader处理输入设备上报事件的处理流程,当InputReader处理完上报的事件后调用mQueuedListener的flush,该方法的实现如下所示:
void QueuedInputListener::flush() {size_t count = mArgsQueue.size();for (size_t i = 0; i < count; i++) {NotifyArgs* args = mArgsQueue[i];args->notify(mInnerListener);delete args;}mArgsQueue.clear();
}
该方法的实现比较简单,调用notify虚拟方法,对于触摸设备来说就是调用子类实现如下所示:
// 直接传递给InputDispatcher
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {listener->notifyMotion(this);
}
直接调用listener的notifyMotion进行处理,这里的listener其实就是InputDispatcher,这在InputReader初始化的时候进行传递的,如下所示:
InputManager::InputManager(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& readerPolicy,const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {/* 创建事件分发对象 */mDispatcher = new InputDispatcher(dispatcherPolicy);/* 创建事件获取对象 */mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
}InputReader::InputReader(const sp<EventHubInterface>& eventHub,const sp<InputReaderPolicyInterface>& policy,const sp<InputListenerInterface>& listener) :mContext(this), mEventHub(eventHub), mPolicy(policy),mGlobalMetaState(0), mGeneration(1),mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),mConfigurationChangesToRefresh(0) {// 初始化事件监听器mQueuedListener = new QueuedInputListener(listener);{ // acquire lockAutoMutex _l(mLock);refreshConfigurationLocked(0);updateGlobalMetaStateLocked();} // release lock
}
将InputDispatcher当做QueuedInputListener的listener。最终listener->notifyMotion(this)调用到,如下所示:
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
......
}
这里不再详解展开描述,在InputDispatcher模块进行详细描述。
总结
本文描述了InputReader对EventHub事件的处理,InputReader对于每一个不同类型的输入设备调用对应的事件处理器进行处理,当事件处理完成后最终将处理结果传递给InputDispatcher。下一章我们描述InputDispatcher的功能。