Android7 Input(四)InputReader
概述
本文主要描述了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_EVENTS
ALOGD("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 happen
break;
}
}
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);
}
// 事件处理完成,清空mRawStatesPending
if (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,在初始时指定,最终指向是QueuedInputListener
getListener()->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 lock
AutoMutex _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 lock
AutoMutex _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的功能。