接着上篇文章Android IMS原理解析的分析,本文主要分析Input事件获取:
Input事件获取
前面讲到,在start()后会启动InputReaderThread线程不断的从EventHub中抽取原始输入事件并进行加工处理,InputReaderThread继承自C的Thread类,Thread类封装了pthread线程工具,提供了与java层Thread类相似的API。
C的Thread类提供了一个名为threadLoop()的纯虚函数,当线程开始运行后,将会在内建的线程循环中不断地调用threadLoop(),直到此函数返回false,则退出线程循环,从而结束线程,看一下InputReaderThread的逻辑实现:
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
threadLoop()内部执行了mReader->loopOnce(),然后返回true,即:InputReaderThread启动后,其线程循环不断地执行InputReader.loopOnce()方法。这个loopOnce()函数作为线程循环的循环体包含了InputReader的所有工作。
注意:C层的Thread类与java层的Thread类有一个显著的区别:
C层Thread类内建了线程循环,threadLoop()就是一次循环而已,只要返回值为true,threadLoop()将会不断地被内建的循环调用。
Java层Thread类的run()函数则是整个线程的全部,一旦执行完退出,线程便结束了。
接下来看一下loopOnce()具体做了什么工作:
void InputReader::loopOnce() {
.....
.....
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
.....
if (count) {
processEventsLocked(mEventBuffer, count);
}
......
mQueuedListener->flush();
}
InputReader一次线程循环,即执行一次loopOnce(),主要执行了三项工作:
1.从EventHub中获取未处理的事件列表,读取的结果存储在参数mEventBuffer中,返回值表示事件的个数;当EventHub中无事件可抽取时,此函数的调用将会阻塞直到事件到来或者超时;
2.通过processEventsLocked()对事件进行处理,对于原始输入事件,进行转译、封装与加工后将结果暂存到mQueuedListener中;
3.发布事件,所有事件处理完毕后,调用mQueuedListener.flush()将所有暂存的输入事件一次性地交付给InputDispatcher;
接下来对三项工作进行逐一分析:
1.EventHub->getEvents()
调用EventHub的getEvents()方法来获取事件列表,EventHub是如何工作的呢?
EventHub的直译是事件集线器,它将所有的输入事件通过一个接口getEvents()把从多个输入设备节点中读取的事件交给InputReader,它是输入系统最底层的一个组件,使用了INotify与Epoll两套机制,通过构造方法就可以看到:
static const char *DEVICE_PATH = "/dev/input"
EventHub::EventHub(void) : xxxx {
.......
//1.使用epoll_create()函数创建一个epoll对象。EPOLL_SIZE_HINT指定最大监听个数为8,
//这个epoll对象将用来监听设备节点是否有数据可读(有无事件)
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
//2.创建一个inotify对象。这个inotify对象将被用来监听设备节点的增删事件
mINotifyFd = inotify_init();
//将存储设备节点的路径/dev/input作为监听对象添加到inotify对象中。当此文件夹下的设备节点发生创建与删除事件时,
//都可以通过mINotifyFd读取事件的详细信息
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
//3.将mINotifyFd作为epoll的一个监控对象。当inotify事件到来时,epoll_wait()将立即返回,
//EventHub便可以从mINotifyFd中读取设备节点的增删信息,并进行相应处理
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//将对mINotifyFd的监听注册到epoll对象中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
//创建一个名为wakeFds的匿名管道
int wakeFds[2];
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
//将管道读取端的描述符的可读事件注册到epoll对象中。因为InputReader在执行getEvents()时会因无事件而导致其线程阻塞在
//epoll_wait()的调用里,然而有时希望能够立刻唤醒InputReader线程使其处理一些请求。此时只需向wakeFds管道的写入端写入任意数据,
//此时读取端有数据可读,使得epoll_wait()得以返回,从而达到唤醒InputReader线程的目的
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
}
在上面的构造方法内,对Epoll和INotify进行处理,后续有事件到来时就可以获取了,接下来看一下getEvents()的逻辑处理:
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/input/event0上的事件就是输入事件,通过EventHub的getEvents()就可以监听并获取该事件,getEvents()将它们封装为RawEvent结构体,并放入buffer中供InputReader进行处理。
2.processEventsLocked()
当通过EventHub获取到事件即count>0时,对事件进行加工处理,此时调用到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;
}
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;
}
}
在方法内部调用了processEventsForDeviceLocked()处理来自同一输入设备的一批事件:
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);
}
processEventsForDeviceLocked()再将事件列表交给InputDevice::process()处理:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
size_t numMappers = mMappers.size();
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++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}
}
可以看到,InputDevice::process()将事件逐个交给每一个InputMapper的process()事件处理。此处就不展开分析了,在调用对应InputMapper实现的process()方法后,会最终调用到getListener()->notifyMotion(&releaseArgs)、getListener()->notifyKey(&args)等等,看一下getListener():
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
返回的就是mQueuedListener,是QueuedInputListener实例,此处先不分析notifyxx()逻辑,稍后一起分析:
3.mQueuedListener->flush()
在porceeEventsLocked()后,接下来会执行mQueuedListener->flush()来结束loopOnce()这个方法,mQueuedListener是QueuedInputListener实例,QueuedInputListener位于进入InputListener.cpp里面,一起看一下具体实现逻辑:
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
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();
}
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
可以看到,在第二项工作中调用notifyMotion()后,执行了队列的push,只是将该事件args压入队列中;最后通过flush()来遍历队列,执行对应args的notify()方法,在notify()方法内部执行listener->notifyXX(),该listener是mInnerListener,而mInnerListener是InputListenerInterface,是在创建QueuedInputListener对象时传入的。
通过前面的代码分析可以知道,QueuedInputListener是在创建InputReader时就创建了,而传入的参数是mInputDispatcher,通过Android IMS原理解析IMS成员关系图可以看到,InputDispatcher继承了InputListenerInterface,所以mInnerListener就是mInputDispatcher,因此在执行flush()后,最终调用到InputDispatcher的逻辑。
QueuedInputListener避免了在原始事件的加工过程中向InputDispatcher进行事件提交,而是将事件信息缓存起来,在InputReader::loopOnce()函数的末尾,也就是InputReader处理完抽取自EventHub的所有原始输入事件之后,QueuedInputListener::flush()函数的调用将缓存的事件信息取出,并提交给InputDispatcher,事件派发就由此开始了。
接下来请看Android IMS原理解析之事件派发
网友评论