分析完事件的读取后,东忙西忙,不知不觉已过去了快五个月了…也不是说没有时间把这部分源码分析完,而是实在是分析不下去,因此转战到其他地方去了。然而这一块始终是心头那不舍的惦记,经过一段时间的沉淀,又参考了网上很多大神的文章,然后再来阅读源码,渐渐感觉到能看出点眉目了。因而事不宜迟,赶紧做个记录吧(注:分析使用的Android源码版本为6.0)。
前面两篇文章分析输入事件的读取,通过分析,发现时间的读取是在EventHub类中实现的,EventHub类的getEevent方法中使用epoll_wait来监听驱动程序上报的事件,而在InputReaderThread的threadLoop方法中调用InputReader的loopOnce方法来不断的调用EventHub的getEvent方法来一直监听事件的到来,getEvent是一个阻塞的方法,当没有事件的时候,epoll_wait方法就会是线程休眠,有事件了就会唤醒线程。
从事件读取线程到事件分发线程的转移过程
既然有个InputReaderThread线程,那么有个InputDispatcherThread就不奇怪了,一个用来读取,一个用来分发,分工合作,相互配合,这样才能高效的完成事件的读取与分发。
我们先梳理下思路:
从事件读取线程到事件分发线程的转移时序图:
从时序图中我们可以看到两个线程交互的过程。InputReaderThread会唤醒InputDispatcherThread来分发事件。
接下来,我们通过源码的追踪的方式,具体看看时序图中涉及的代码的具体实现。
跟着时序图,我们代码从InputReaderThread开始看起:
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
构造函数和析构函数都是空的,循环函数简单的就一句。mReader就是当前的InputReader对象,因此loopOnce如下:
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
...
//获取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//处理事件
processEventsLocked(mEventBuffer, count);
}
...
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);
}
...
mQueuedListener->flush();
}
只列出了比较重要的一些代码。这个函数作如下事情:
1.使用mEventHub->getEvents获取输入事件
2.使用processEventsLocked处理事件
getEvents方法之前也已经有介绍过,它就是使用epoll来监听驱动程序上报的事件的。所以我们从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
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
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;
}
}
这个方法会对事件类型进行判断。我们假定用户按了一下返回按键,所以输入的是一个按键事件。而这个函数判断的时间类型的定义如下:
enum {
// Sent when a device is added.
DEVICE_ADDED = 0x10000000,
// Sent when a device is removed.
DEVICE_REMOVED = 0x20000000,
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
可见我们的按键事件绝不是这几个,而应该是小于FIRST_SYNTHETIC_EVENT事件的,因此会执行第一个分支。进而调用 processEventsForDeviceLocked(deviceId, rawEvent, batchSize);方法进一步处理:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(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);
}
调用device->process因一部处理,device是InputDevice的实例,因此看看InputDevice下的process方法:
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();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
#endif
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
ALOGD("Recovered from input event buffer overrun.");
#endif
} else {
#if DEBUG_RAW_EVENTS
ALOGD("Dropped input event while waiting for next input sync.");
#endif
}
} 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++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}
}
为了更好的理解这段代码,我们列出事件类型的定义:
/* Events */
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
因此我们的按键时间应该是0x01,所以这段代码执行的下面这个for循环:
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
for循环遍历mMappers数组,分别调用每一个mapper的process方法。这个数组包含了所有的输入事件的类型。我们按下的按键,因此会调用按键类型的Mapper来处理。如果想搞清楚这一块,可以看下mMappers数组的构造过程,在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);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
device