Android IMS原理解析之InputReader

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原理解析之事件派发

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值