目录
1.EventHub->getEvents()
2.processEventsLocked()
3.mQueuedListener->flush()
前面讲到,在start()后会启动InputThread线程不断的从EventHub中抽取原始输入事件并进行加工处理,代码如下:
frameworks/native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
return OK;
}
threadLoop中执行的是loopOnce函数 frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {
...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //1
{ // acquire lock
std::scoped_lock _l(mLock);
mReaderIsAliveCondition.notify_all();
if (count) {
processEventsLocked(mEventBuffer, count); //2
}
...
mQueuedListener->flush();//3
}
InputReader一次线程循环,即执行一次loopOnce(),主要执行了三项工作:
注释一:从EventHub中获取未处理的事件列表,读取的结果存储在参数mEventBuffer中,返回值表示事件的个数;当EventHub中无事件可抽取时,此函数的调用将会阻塞直到事件到来或者超时;事件信息主要有两种,一种是设备节点的增删事件:如添加/移除设备的事件,一种是原始输入事件:如触摸屏幕或者按物理按键触发的事件。
注释二:通过processEventsLocked()对事件进行处理(两种事件都处理),对于原始输入事件,进行转译、封装与加工后将结果暂存到mQueuedListener中;
注释三:发布事件,所有事件处理完毕后,调用mQueuedListener.flush()将所有暂存的输入事件一次性地交付给InputDispatcher;
接下来对这三件事逐一分析:
1.EventHub->getEvents()
调用EventHub的getEvents()方法来获取事件列表,EventHub是如何工作的呢?
EventHub的直译是事件集线器,它将所有的输入事件通过一个接口getEvents()把从多个输入设备节点中读取的事件交给InputReader,它是输入系统最底层的一个组件,使用了INotify与Epoll两套机制,通过构造方法就可以看到:
/frameworks/native/services/inputflinger/reader/EventHub.cpp
283 EventHub::EventHub(void)
284 : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
285 mNextDeviceId(1),
286 mControllerNumbers(),
287 mOpeningDevices(nullptr),
288 mClosingDevices(nullptr),
289 mNeedToSendFinishedDeviceScan(false),
290 mNeedToReopenDevices(false),
291 mNeedToScanDevices(true),
292 mPendingEventCount(0),
293 mPendingEventIndex(0),
294 mPendingINotify(false) {
295 ensureProcessCanBlockSuspend();
296 //1.使用epoll_create()函数创建一个epoll对象。EPOLL_SIZE_HINT指定最大监听个数为8,这个
// epoll对象将用来监听设备节点是否有数据可读(有无事件)
297 mEpollFd = epoll_create1(EPOLL_CLOEXEC);
298 LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
299
//2.创建一个inotify对象。这个inotify对象将被用来监听设备节点的增删事件
300 mINotifyFd = inotify_init();
//将存储设备节点的路径/dev/input作为监听对象添加到inotify对象中。当此文件夹下的设备节点
//发生创建与删除事件时,
//都可以通过mINotifyFd读取事件的详细信息
301 mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
302 LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
303 strerror(errno));
304 if (isV4lScanningEnabled()) {
305 mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
306 LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
307 VIDEO_DEVICE_PATH, strerror(errno));
308 } else {
309 mVideoWd = -1;
310 ALOGI("Video device scanning disabled");
311 }
//3.将mINotifyFd作为epoll的一个监控对象。当inotify事件到来时,epoll_wait()将立即返回,
//EventHub便可以从mINotifyFd中读取设备节点的增删信息,并进行相应处理
313 struct epoll_event eventItem = {};
314 eventItem.events = EPOLLIN | EPOLLWAKEUP;
315 eventItem.data.fd = mINotifyFd;
//将对mINotifyFd的监听注册到epoll对象中
316 int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
317 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
318 //创建一个名为wakeFds的匿名管道
319 int wakeFds[2];
320 result = pipe(wakeFds);
321 LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
322
323 mWakeReadPipeFd = wakeFds[0];
324 mWakeWritePipeFd = wakeFds[1];
325
326 result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
327 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
328 errno);
329
330 result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
331 LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
332 errno);
333
334 eventItem.data.fd = mWakeReadPipeFd;
//将管道读取端的描述符的可读事件注册到epoll对象中。因为InputReader在执行getEvents()时会因无事件而导致其线程阻塞在
//epoll_wait()的调用里,然而有时希望能够立刻唤醒InputReader线程使其处理一些请求。此时只需向wakeFds管道的写入端写入任意数据,
//此时读取端有数据可读,使得epoll_wait()得以返回,从而达到唤醒InputReader线程的目的
335 result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
336 LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
337 errno);
338 }
在上面的构造方法内,对Epoll和INotify进行处理,后续有事件到来时就可以获取了,反正知道会监视目录文件? /dev/input就可以了。接下来看一下getEvents()的逻辑处理:
/frameworks/native/services/inputflinger/reader/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
.......
for (;;) {
.......
//处理未被InputReader取走的输入事件与设备事件。epoll_wait()所取出的epoll_event存储在mPendingEventItems中,
//mPendingEventCount指定mPendingEventItems数组所存储的事件个数。而mPendingEventIndex指定尚未处理的epoll_event的索引
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
//在这里分析每一个epoll_event 如果表示设备节点可读,则读取原始事件并放置到buffer中。
//如果表示mINotifyEd可读,则设置mPendingINotify为true,当InputReader将现有的输入事件都取出后读取mINotifyEd中的事件,并加装与卸载相应的设备。
//另外,如果此epoll_event表示wakeFds的读取端有数据可读,则设置awake标志为true,
//此时无论此次getEvents()调用是否取到事件,都不会调用epoll_wait()进行事件等待。
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
}
}
}
.....
//如果此次getEvents()调用成功获取了一些事件,或者要求唤醒InputReader,则退出循环并结束getEvents()的调用,
//使InputReader可以立刻处理事件
if (event != buffer || awoken) {
break;
}
//如果此次getEvents()调用没能获取事件,说明mPendingEventItems中没有事件可用。
//于是执行epoll_wait()函数等待新的事件到来,将结果存储到mPendingEventItems里,并重置mPendingEventIndex为0
mPendingEventIndex = 0;
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
mPendingEventCount = 0;
if (errno != EINTR) {
ALOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
} else {
//从epoll_wait()中得到新的事件后,重新循环,对新事件进行处理
mPendingEventCount = size_t(pollResult);
}
}
//返回本次getEvents()调用所读取的事件数量
return event - buffer;
}
?getEvents()函数的本质就是读取并处理Epoll事件与INotify事件:包括设备插拔及各种触摸、按钮事件等,可以看做是一个不同设备的集线器,主要面向的是/dev/input目录下的设备节点,比如说/dev/in,通过EventHubput/event0上的事件就是输入事件的getEvents()就可以监听并获取该事件,getEvents()将它们封装为RawEvent结构体,并放入mEventBuffer中供InputReader进行处理。如果没有输入事件将调用epoll_wait()函数阻塞等待。
2.processEventsLocked()
?当通过EventHub获取到事件即count>0时,对事件进行加工处理,此时调用到processEventsLocked()方法:
frameworks/native/services/inputflinger/reader/InputReader.cpp
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) { //1
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: %zu Count: %zu", batchSize, count);
}
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) { //2
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()函数中会遍历mEventBuffer中存储的输入事件,处理rawEvent分成两类:注释1处理原始输入事件,注释2处理设备事件。
1.先看处理设备事件:
对于添加、删除设备的event事件处理比较简单,只需要增加和删除mDevices列表中Device对象就完成了,而对于扫描设备结束的Event还需调用handleConfigurationChangedLocked()函数来处理设备的配置文件。mDevices的定义,是一个map集合,保存着eventHubId和InputDevice对象。
2.对于原始输入事件:
调用processEventsForDeviceLocked函数进行处理代码如下:
frameworks/native/services/inputflinger/reader/InputReader.cpp
269 void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
270 size_t count) {
271 auto deviceIt = mDevices.find(eventHubId);
272 if (deviceIt == mDevices.end()) {
273 ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
274 return;
275 }
276
277 std::shared_ptr<InputDevice>& device = deviceIt->second;
278 if (device->isIgnored()) {
279 // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
280 return;
281 }
282
283 device->process(rawEvents, count);
284 }
注释1处根据eventHubId查询map集合中是否有该key,如果没有则返回,有则在注释2处将value值取出,是InputDevice类型的。在注释3处调用它的process函数执行处理
frameworks/native/services/inputflinger/reader/InputDevice.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.
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
if (DEBUG_RAW_EVENTS) {
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
}
if (mDropUntilNextSync) { //1
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
if (DEBUG_RAW_EVENTS) {
ALOGD("Recovered from input event buffer overrun.");
}
} else {
if (DEBUG_RAW_EVENTS) {
ALOGD("Dropped input event while waiting for next input sync.");
}
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
mapper.process(rawEvent); //2
});
}
--count;
}
}
注释1处的mDropUntilNextSync的值默认为false,如果设备的输入缓冲区溢出,该值会被设置为true,如果恢复,会重新置为false。原始输入事件类型有很多,如键盘输入事件、触摸输入事件等,这些类别都会由单独的InputMapper的子类来进行处理。

?注释2处遍历所有的Mapper类型,选择合适的Mapper处理事件,for_each_mapper_in_subdevice是一个内联函数,用于遍历所有的Mapper,InputReader将输入事件交由合适的InputMapper处理,至于是哪个InputMapper,InputReader并不关心。这里以键盘输入事件为例,执行的是KeyboardInputMapper的process函数:
frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: { //1按键事件的处理
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0, scanCode,
usageCode); //2
}
break;
}
case EV_MSC: { //3其他事件的处理
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: { //4同步事件的处理
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
注释3处为其他事件的处理,注释4处为同步事件的处理。主要还是关注注释1处,按键类型事件,调用注释2处processKey函数进行处理。
frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,
int32_t usageCode) {
...
NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
getDisplayId(), policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener().notifyKey(&args);
}
这里会对键盘输入事件进行加工,并将加工后的数据封装到NotifyKeyArgs类型的对象中。然后调用getListener()函数得到InputListenerInterface类型的对象。InputDispatcherListener继承了InputListenerInterface,而InputDispatcher继承了InputDispatcherListener,所以这里调用的实际是InputDispatcher的notifyKey函数。此处先不分析notifyxx()逻辑,稍后一起分析:
3.mQueuedListener->flush()
???在porceeEventsLocked()后,接下来会执行mQueuedListener->flush()来结束loopOnce()这个方法,mQueuedListener是QueuedInputListener实例,看看里面的逻辑:
/frameworks/native/services/inputflinger/InputListener.cpp
326 void QueuedInputListener::notifyConfigurationChanged(
327 const NotifyConfigurationChangedArgs* args) {
328 traceEvent(__func__, args->id);
329 mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args));
330 }
331
332 void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
333 traceEvent(__func__, args->id);
334 mArgsQueue.push_back(new NotifyKeyArgs(*args));
335 }
336
337 void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
338 traceEvent(__func__, args->id);
339 mArgsQueue.push_back(new NotifyMotionArgs(*args));
340 }
341
342 void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
343 traceEvent(__func__, args->id);
344 mArgsQueue.push_back(new NotifySwitchArgs(*args));
345 }
346
347 void QueuedInputListener::notifySensor(const NotifySensorArgs* args) {
348 traceEvent(__func__, args->id);
349 mArgsQueue.push_back(new NotifySensorArgs(*args));
350 }
351
352 void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
353 traceEvent(__func__, args->id);
354 mArgsQueue.push_back(new NotifyVibratorStateArgs(*args));
355 }
356
357 void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
358 traceEvent(__func__, args->id);
359 mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
360 }
361
362 void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
363 traceEvent(__func__, args->id);
364 mArgsQueue.push_back(new NotifyPointerCaptureChangedArgs(*args));
365 }
366
367 void QueuedInputListener::flush() {
368 size_t count = mArgsQueue.size();
369 for (size_t i = 0; i < count; i++) {
370 NotifyArgs* args = mArgsQueue[i];
371 args->notify(mInnerListener);
372 delete args;
373 }
374 mArgsQueue.clear();
375 }
376
377 }
可以看到,在第二项工作中调用notifyKey()后,执行了队列的push,只是将该事件args压入队列中;最后通过flush()来遍历队列,执行对应args的notify()方法.........(省略一万字)。
?????????QueuedInputListener避免了在原始事件的加工过程中向InputDispatcher进行事件提交,而是将事件信息缓存起来,在InputReader::loopOnce()函数的末尾,也就是InputReader处理完抽取自EventHub的所有原始输入事件之后,QueuedInputListener::flush()函数的调用将缓存的事件信息取出,并提交给InputDispatcher,事件派发就由此开始了。
|