之前在《Android4.4——InputManagerService启动》博客中通过InputManagerService.start函数->nativeStart->inputmanager.start->InputXXXThread.run函数,最终启动了InputReader线程和InputDispatcher线程这两个工作线程。这篇博客主要来分析一下InputReader相关的代码。
InputReader线程启动后,线程会一直在InputReaderThread.threadLoop函数中不断循环。
Step 1、InputReaderThread.threadLoop
该函数的代码位于frameworks\base\services\input\InputReader.cpp文件中。
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
其中mReader为InputReaderThread类中的一个接口。
/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp& reader);
virtual ~InputReaderThread();
private:
sp mReader;
virtual bool threadLoop();
};
InputReader类实现了InputReaderInterface接口,所以mReader->loopOnce()调用的是InputReader.loopOnce函数。
Step 2、InputReader.loopOnce
该函数的代码同样位于frameworks\base\services\input\InputReader.cpp文件中。
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//从EventHub获取输入事件
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);//Input事件处理函数
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
......
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();//将Input事件发送给Listener。
}
对于InputReader而言,Listener实际为InputDispatcher。
Step 3、EventHub.getEvents
该函数代码位于frameworks\base\services\input\EventHub.cpp文件中。这块代码涉及到了驱动部分,暂时不分析了,只需要知道EventHub.getEvents从底层上获取到Input事件即可。
Step 4、InputReader.ProcessEventsLocked
该函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {//rawEvents为从EventHub获取的事件;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;
}
……
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);//设备驱动程序上报事件的处理函数
} else {//EventsHub.getEvents函数所产生的事件
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;
}
}
从EventsHub中获取到Input事件及其事件数后,由InputReader.ProcessEventsLocked函数进行处理。根据获取的事件类型,可以大致分为两类,一类有设备驱动程序上报的事件,一类为EventsHub.getEvents函数产生的事件。EventsHub.getEvents产生的事件主要包括增加设备、移除设备和扫描设备三个事件。负责处理 Device 增加、删除事件。增加事件的流程为:为一个新增的 Device 创建一个InputDevice,并增加到 InputReader::mDevices 中;并根据新增加设备的 class 类别,创建对应的消息转换器(InputMapper),然后此消息转换器加入InputDevice::mMappers 中。消息转换器负责把读取的 RawEvent 转换成特定的事件,以供应用程序使用。
EventHub 与 InputReader 各自管理功能:
1)EventHub 管理一堆 Device,每一个 Device 与内核驱动中一个事件输入设备对应
2)InputReader 管理一堆 InputDevice,每一个 InputDevice 与 EventHub 中的 Device 对应
3)InputDevice 管理一些与之相关的 InputMapper,每一个 InputMapper 与一个特定的应用事件相对应,如:SingleTouchInputMapper。
但是在这里,只主要针对地分析设备驱动程序上报的事件的处理过程。
Step 5、InputReader. processEventsForDeviceLocked
该函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);//根据rawEvents.deviceID值获取设备索引值
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);//根据设备索引获取对应的输入设备
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
device->process(rawEvents, count);
}
根据deviceID获取对应的InputDevice,然后调用InputDevice::process函数对设备输入事件进行处理。
Step 6、InputDevice::process
本函数代码位于frameworks\base\services\input\ InputReader.cpp文件中。
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
size_t numMappers = mMappers.size();//获取InputMapper中各设备对应的Mapper对象总数
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
……
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
……
} else {
……
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (size_t i = 0; i < numMappers; i++) {//遍历InputDevice中的每一个InputMapper,并调用相应mapper的process函数处理事件
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}
}
上面说到本函数会遍历InputDevice的所有InputMapper并调用相应mapper的process函数。注意到,InputMapper::process函数是一个纯虚函数(参考frameworks\base\services\input\ InputReader.h中InputMapper类的声明处)。
class InputMapper {
public:
InputMapper(InputDevice* device);
virtual ~InputMapper();
……
virtual void process(const RawEvent* rawEvent) = 0;
……
protected:
InputDevice* mDevice;"code" class="java"> InputReaderContext* mContext;
……
};
因此,要实现其process函数,需要其它类继承并重写process函数。 下面以触摸触摸屏为例,来简单分析一下这段逻辑。
当我们在上面按下时驱动程序会上报触点的坐标,在InputDevice::process函数中会调用mapper->process(rawEvent)函数处理。之前我们提到InputMapper::process是一个纯虚函数。对于单点触摸屏而言,process函数是由SingleTouchInputMapper类的process函数实现。
在frameworks\base\services\input\InputReader.h文件中有以下代码:
class TouchInputMapper : public InputMapper{
……
virtual voidprocess(const RawEvent* rawEvent);
……
};
class SingleTouchInputMapper : publicTouchInputMapper {
……
virtual void process(const RawEvent* rawEvent);
……
private:
SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
};
另外,在frameworks\base\services\input\InputReader.cpp文件中,实现了SingleTouchInputMapper:: process函数和TouchInputMapper::process函数:
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
TouchInputMapper::process(rawEvent);
mSingleTouchMotionAccumulator.process(rawEvent);//将事件保存在SingleTouchMotionAccumulator中的成员变量中
}
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);//记录mouse和touch pad按键状态
mCursorScrollAccumulator.process(rawEvent);//cursor scroll motions
mTouchButtonAccumulator.process(rawEvent);//记录touch,stylus and toolbutton
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
通过调用TouchInputMapper::process函数,同步CursorButton、CursorScroll和TouchBotton的状态,将事件保存起来。
接下来,分析sync函数:
void TouchInputMapper::sync(nsecs_t when) {
// Sync button state.
mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
// Sync scroll state.
mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch state.
bool havePointerIds = true;
mCurrentRawPointerData.clear();
syncTouch(when, &havePointerIds);//调用SingleTouchInputMapper::syncTouch函数
……
// Reset state that we will compute below.
mCurrentFingerIdBits.clear();
mCurrentStylusIdBits.clear();
mCurrentMouseIdBits.clear();
mCurrentCookedPointerData.clear();
if (mDeviceMode == DEVICE_MODE_DISABLED) {
// Drop all input if the device is disabled.
mCurrentRawPointerData.clear();
mCurrentButtonState = 0;
} else {
// Preprocess pointer data.
if (!havePointerIds) {
assignPointerIds();
}
// Handle policy on initial down or hover events.
uint32_t policyFlags = 0;
bool initialDown = mLastRawPointerData.pointerCount == 0
&& mCurrentRawPointerData.pointerCount != 0;
bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
if (initialDown || buttonsPressed) {
// If this is a touch screen, hide the pointer on an initial down.
if (mDeviceMode == DEVICE_MODE_DIRECT) {
getContext()->fadePointer();
}
// Initial downs on external touch devices should wake the device.
// We don't do this for internal touch screens to prevent them from waking
// up in your pocket.
// TODO: Use the input device configuration to control this behavior more finely.
if (getDevice()->isExternal()) {
policyFlags |= POLICY_FLAG_WAKE_DROPPED;
}
}
// Synthesize key down from raw buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
policyFlags, mLastButtonState, mCurrentButtonState);//同步Key-down事件
// Consume raw off-screen touches before cooking pointer data.
// If touches are consumed, subsequent code will not receive any pointer data.
if (consumeRawTouches(when, policyFlags)) {
mCurrentRawPointerData.clear();
}
// Cook pointer data. This call populates the mCurrentCookedPointerData structure
// with cooked pointer data that has the same ids and indices as the raw data.
// The following code can use either the raw or cooked data, as needed.
cookPointerData();
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DEVICE_MODE_POINTER) {
for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentStylusIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
mCurrentFingerIdBits.markBit(id);
} else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
mCurrentMouseIdBits.markBit(id);
}
}
for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
|| pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
mCurrentStylusIdBits.markBit(id);
}
}
// Stylus takes precedence over all tools, then mouse, then finger.
PointerUsage pointerUsage = mPointerUsage;
if (!mCurrentStylusIdBits.isEmpty()) {
mCurrentMouseIdBits.clear();
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_STYLUS;
} else if (!mCurrentMouseIdBits.isEmpty()) {
mCurrentFingerIdBits.clear();
pointerUsage = POINTER_USAGE_MOUSE;
} else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
pointerUsage = POINTER_USAGE_GESTURES;
}
dispatchPointerUsage(when, policyFlags, pointerUsage);//分发Pointer事件---滑动
} else {
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != NULL) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentButtonState);
mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
mCurrentCookedPointerData.idToIndex,
mCurrentCookedPointerData.touchingIdBits);
}
dispatchHoverExit(when, policyFlags);
dispatchTouches(when, policyFlags);//分发touch事件
dispatchHoverEnterAndMove(when, policyFlags);
}
// Synthesize key up from raw buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
policyFlags, mLastButtonState, mCurrentButtonState);//同步Key-up事件
}
// Copy current touch to last touch in preparation for the next cycle.
mLastRawPointerData.copyFrom(mCurrentRawPointerData);
mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
mLastButtonState = mCurrentButtonState;
mLastFingerIdBits = mCurrentFingerIdBits;
mLastStylusIdBits = mCurrentStylusIdBits;
mLastMouseIdBits = mCurrentMouseIdBits;
// Clear some transient state.
mCurrentRawVScroll = 0;
mCurrentRawHScroll = 0;
}
首先着看syncTouch 函数。这里TouchInputMapper中未重写syncTouch 函数,故这里调用的是SingleTouchInputMapper::syncTouch函数(位于frameworks\base\services\input\InputReader.cpp):
void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
if (mTouchButtonAccumulator.isToolActive()) {
mCurrentRawPointerData.pointerCount = 1;
mCurrentRawPointerData.idToIndex[0] = 0;
bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
&& (mTouchButtonAccumulator.isHovering()
|| (mRawPointerAxes.pressure.valid
&& mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
mCurrentRawPointerData.markIdBit(0, isHovering);
RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];//同步和更新mCurrentRawPointerData.pointers值
outPointer.id = 0;
outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
outPointer.touchMajor = 0;
outPointer.touchMinor = 0;
outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth();
outPointer.orientation = 0;
outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance();
outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX();
outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY();
outPointer.toolType = mTouchButtonAccumulator.getToolType();
if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
}
outPointer.isHovering = isHovering;
}
}
接着分析SingleTouchInputMapper:: dispatchTouches函数:
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
……
if (currentIdBits == lastIdBits) {
if (!currentIdBits.isEmpty()) {
// No pointer id changes so this is a move event.
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedPointerData.pointerProperties,//经坐标转换后的坐标数据
mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
mCurrentCookedPointerData.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, metaState, buttonState, 0,
mLastCookedPointerData.pointerProperties,
mLastCookedPointerData.pointerCoords,
mLastCookedPointerData.idToIndex,
dispatchedIdBits, upId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
dispatchedIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
if (moveNeeded) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties, //经坐标转换后的坐标数据
mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
mCurrentCookedPointerData.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, metaState, buttonState, 0,
mCurrentCookedPointerData.pointerProperties, //经坐标转换后的坐标数据
mCurrentCookedPointerData.pointerCoords, //经坐标转换后的坐标数据
mCurrentCookedPointerData.idToIndex, //经坐标转换后的坐标数据
dispatchedIdBits, downId,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}
dispatchTouches函数中有多处都调用了TouchInputMapper::dispatchMotion函数,那就来分析一下呗。
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, //经坐标转换后的坐标数据
const PointerCoords* coords, //经坐标转换后的坐标数据
const uint32_t* idToIndex, //经坐标转换后的坐标数据
BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
PointerCoords pointerCoords[MAX_POINTERS];
PointerProperties pointerProperties[MAX_POINTERS];
uint32_t pointerCount = 0;
while (!idBits.isEmpty()) {
uint32_t id = idBits.clearFirstMarkedBit();
uint32_t index = idToIndex[id];
pointerProperties[pointerCount].copyFrom(properties[index]);
pointerCoords[pointerCount].copyFrom(coords[index]);
if (changedId >= 0 && id == uint32_t(changedId)) {
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
pointerCount += 1;
}
……
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
在dispatchMotion中,根据经坐标转换后的cooked数据创建NotifyMotionArg对象,它描述了一个移动事件,接着调用TouchInputMapper::getListener()->notifyMotion(&args)。
TouchInputMapper::getListener()调用mContext->getListener(),此mContext为InputReader::mContext,所以其getListener()返回的则为InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion函数。下面来围观一下:
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
把传递过来的NotifyMotionArg参数复制一份,然后加入QueuedInputListener::mArgsQueue列表中。
补充1)
InputReader::mContext在构造时用自己的指针初始化了mContext(见InputReader::InputReader函数),从而mContext::mReader则为此InputReader实例(见InputReader类声明处代码)。
补充2)
在InputReader::createDeviceLocked中创建InputDevice时,把自己的mContext作为参数传入,从而把它保存在InputDevice::mContext中;在创建InputMapper时,以InputDevice作为参数,且InputMapper把它保存在mDevice中,然后从把InputDevice中的mContext也保存在InputMapper的mContext中。
回到当初我们开始长途跋涉追寻代码的InputReader::loopOnce函数,在大致追踪完processEventsLocked后,继续分析loopOnce函数的最后一小段代码:
void InputReader::loopOnce() {
……
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);//在NativeInputManager对象创建InputReader对象时传入。(见new NativeInputManager-> new InputManager-> new InputReader)
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();//处理mArgsQueue中的所有NotifyArgs
}
来见识一下flush函数的庐山真面目,代码位于frameworks\base\services\input\ InputListener.cpp文件中。
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();
}
在new InputReader的时候,将mDispatcher作为参数传递给InputReader的构造函数最为构造函数的第三个参数。可以自行去看看InputReader构造函数和QueueInputListener构造函数的代码,就可以知道mInnerListener实际上是InputManager中的mDispatcher。
与之前分析InputMapper的时候类似。NofifyArgs这个结构体定义了一个纯虚函数notify。因此由其他结构体继承NotifyArgs并改写实现notify函数。
之前假设的触摸触摸屏的事件到达至此步时,调用的是NotifyMotionArgs中的notify函数(代码位于frameworks\base\services\input\ InputListener.cpp文件)。
void NotifyMotionArgs::notify(const sp& listener) const {
listener->notifyMotion(this);
}
这里调用的InputDispatcher::notifyMotion函数,这样就进入到InputDispatcher的工作职能中了。