这一节主要了解输入事件的获取,InputReaderThread继承自C++的Thread类,Thread类封装了pthread线程工具,提供了与Java层Thread类相似的API。C++的Thread类提供了一个名为threadLoop()的纯虚函数,当线程开始运行后,将会在内建的线程循环中不断地调用threadLoop(),直到此函数返回false,则退出线程循环,从而结束线程。
/frameworks/native/services/inputflinger/InputThread.cppclass InputThreadImpl : public Thread {
public:explicit InputThreadImpl(std::function<void()> loop): Thread(/* canCallJava */ true), mThreadLoop(loop) {}~InputThreadImpl() {}private:std::function<void()> mThreadLoop;bool threadLoop() override {mThreadLoop();return true;}
};
/frameworks/native/services/inputflinger/reader/InputReader.cppstatus_t InputReader::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });return OK;
}void InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;bool inputDevicesChanged = false;std::vector<InputDeviceInfo> inputDevices;{ // acquire lockAutoMutex _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// 通过EventHub获取事件列表 读取的结果存储在参数mEventBuffer中 表示事件的个数size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);{ // acquire lockAutoMutex _l(mLock);mReaderIsAliveCondition.broadcast();//如果获取到事件 对事件进行加工处理if (count) {processEventsLocked(mEventBuffer, count);}if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTSALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endifmNextTimeout = 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);}// 发布事件 将所有事件交给InputDispatchermQueuedListener->flush();
}
分析:首先从EventHub中抽取未处理的事件列表。这些事件分为两类,一类是从设备节点中读取的原始输入事件,另一类则是输入设备可用性变化事件,简称为设备事件。通过 processEventsLocke()对事件进行处理。对于设备事件,此函数对根据设备的可用性加载或移除设备对应的配置信息。对于原始输入事件,则在进行转译、封装与加工后将结果暂存到mQueuedListener 中。所有事件处理完毕后,调用mQueuedListener.flush()将所有暂存的输入事件一次性地交付给InputDispatcher。
/frameworks/native/services/inputflinger/reader/EventHub.cppsize_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {ALOG_ASSERT(bufferSize >= 1);AutoMutex _l(mLock);struct input_event readBuffer[bufferSize];//每存储一个事件 event指针会向后偏移一个元素RawEvent* event = buffer;size_t capacity = bufferSize;bool awoken = false;for (;;) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// 重新打开设备节点if (mNeedToReopenDevices) {mNeedToReopenDevices = false;ALOGI("Reopening all input devices due to a configuration change.");closeAllDevicesLocked();mNeedToScanDevices = true;break; // return to the caller before we actually rescan}...if (mNeedToScanDevices) {mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}while (mOpeningDevices != nullptr) {Device* device = mOpeningDevices;ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());mOpeningDevices = device->next;event->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;event->type = DEVICE_ADDED;event += 1;mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}}// Grab the next input event.bool deviceChanged = false;// 处理未被InputReader取走的输入事件与设备事件while (mPendingEventIndex < mPendingEventCount) {const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];if (eventItem.data.fd == mINotifyFd) {if (eventItem.events & EPOLLIN) {mPendingINotify = true;} else {ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);}continue;}if (eventItem.data.fd == mWakeReadPipeFd) {if (eventItem.events & EPOLLIN) {ALOGV("awoken after wake()");awoken = true;char buffer[16];ssize_t nRead;do {nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));} else {ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",eventItem.events);}continue;}Device* device = getDeviceByFdLocked(eventItem.data.fd);if (!device) {ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,eventItem.data.fd);ALOG_ASSERT(!DEBUG);continue;}if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {if (eventItem.events & EPOLLIN) {size_t numFrames = device->videoDevice->readAndQueueFrames();if (numFrames == 0) {ALOGE("Received epoll event for video device %s, but could not read frame",device->videoDevice->getName().c_str());}} else if (eventItem.events & EPOLLHUP) {// TODO(b/121395353) - consider adding EPOLLRDHUPALOGI("Removing video device %s due to epoll hang-up event.",device->videoDevice->getName().c_str());unregisterVideoDeviceFromEpollLocked(*device->videoDevice);device->videoDevice = nullptr;} else {ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,device->videoDevice->getName().c_str());ALOG_ASSERT(!DEBUG);}continue;}// This must be an input eventif (eventItem.events & EPOLLIN) {int32_t readSize =read(device->fd, readBuffer, sizeof(struct input_event) * capacity);...}// 设备节点发生增删操作if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {mPendingINotify = false;readNotifyLocked();deviceChanged = true;}// 等待新的事件int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);mLock.lock(); // reacquire lock after pollif (pollResult == 0) {// Timed out.mPendingEventCount = 0;break;}if (pollResult < 0) {// An error occurred.mPendingEventCount = 0;// Sleep after errors to avoid locking up the system.// Hopefully the error is transient.if (errno != EINTR) {ALOGW("poll failed (errno=%d)\n", errno);usleep(100000);}} else {// Some events occurred.mPendingEventCount = size_t(pollResult);}}// 获取所读取的事件数量return event - buffer;
}
分析: getEvent()函数使用Epoll的核心是mPendingEventItems数组,它是一个事件池。getEvents()函数会优先从这个事件池获取epoll 事件进行处理,并将读取相应的原始输入事件返回给调用者。当无法获得任何事件时,会调用epoll_wait()函数等待新事件到来,将事件池重新注满,然后再重新处理事件池中的Epoll事件。
EventHub的直译是事件集线器,它将所有的输入事件通过一个接口 getEvents()把从多个输人设备节点中读取的事件交给InputReader,它是输人系统最底层的一个组件。
/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) {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_EVENTSALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif// 处理属于某一设备的一批事件 batchSize表示属于此设备的输入事件的个数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 happenbreak;}}count -= batchSize;rawEvent += batchSize;}
}void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,size_t count) {auto deviceIt = mDevices.find(eventHubId);if (deviceIt == mDevices.end()) {ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);return;}std::shared_ptr<InputDevice>& device = deviceIt->second;if (device->isIgnored()) {// ALOGD("Discarding event for ignored deviceId %d.", deviceId);return;}// 调用InputDevice的process函数进行处理device->process(rawEvents, count);
}
/frameworks/native/services/inputflinger/reader/InputDevice.cppvoid InputDevice::process(const RawEvent* rawEvents, size_t count) {for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTSALOGD("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);
#endifif (mDropUntilNextSync) {if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTSALOGD("Recovered from input event buffer overrun.");
#endif} else {
#if DEBUG_RAW_EVENTSALOGD("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().c_str());mDropUntilNextSync = true;reset(rawEvent->when);} else {for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {mapper.process(rawEvent);});}--count;}
}
分析:InputDevice用来存储输入设备的信息,事件交给InputMapper的process()事件处理,它有很多子类 用于加工不同类型的原始输入事件,这里有点像责任连模式。