1.InputReader启动
InputReader和InputDispatcher是IMS中的两个重要的线程,InputReader主要负责从Eventhub获取事件,然后将事件进行处理,并将封装好的EventEntry事件交给InputDispatcher的去进行分发;InputDispatcher主要负责将输入事件分发到对应的窗口。
这两个线程都是在IMS启动时创建并启动的,这里主要分析InputReader是如何工作的,代码基于Android 14:
IMS启动时会调用start方法去启动InputReader线程:
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;
}
创建一个名称为InputReader的线程,然后主要做了两件事情:执行loopOnce()方法、唤醒EventHub,主要看下loopOnce方法:
在这个线程中执行loopOnce()方法,用来读取输入设备生成的事件
frameworks/native/services/inputflinger/reader/InputReader.cppvoid InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;// Copy some state so that we can access it outside the lock later.bool inputDevicesChanged = false;std::vector<InputDeviceInfo> inputDevices;std::list<NotifyArgs> notifyArgs;{ // acquire lockstd::scoped_lock _l(mLock);//申请mLock锁,确保线程安全oldGeneration = mGeneration;timeoutMillis = -1;auto changes = mConfigurationChangesToRefresh;//InputReader的各种配置(输入设备的增删、信息)是否有变化if (changes.any()) {//如果配置变化,更新超时时间和配置mConfigurationChangesToRefresh.clear();timeoutMillis = 0;refreshConfigurationLocked(changes);} else if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);}} // release lockstd::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);//1.从EventHub中获取输入事件,getEvents方法会阻塞直到超时或者有事件到达{ // acquire lockstd::scoped_lock _l(mLock);mReaderIsAliveCondition.notify_all();if (!events.empty()) {//如果从EventHub中获取到了事件notifyArgs += processEventsLocked(events.data(), events.size());//2.processEventsLocked方法处理事件}if (mNextTimeout != LLONG_MAX) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (now >= mNextTimeout) {if (debugRawEvents()) {ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);}mNextTimeout = LLONG_MAX;notifyArgs += timeoutExpiredLocked(now);//3.处理超时事件}}if (oldGeneration != mGeneration) {//输入设备是否发生变化inputDevicesChanged = true;inputDevices = getInputDevicesLocked();notifyArgs.emplace_back(NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices});}} // release lock// Send out a message that the describes the changed input devices.if (inputDevicesChanged) {mPolicy->notifyInputDevicesChanged(inputDevices);}// Notify the policy of the start of every new stylus gesture outside the lock.for (const auto& args : notifyArgs) {const auto* motionArgs = std::get_if<NotifyMotionArgs>(&args);if (motionArgs != nullptr && isStylusPointerGestureStart(*motionArgs)) {mPolicy->notifyStylusGestureStarted(motionArgs->deviceId, motionArgs->eventTime);}}notifyAll(std::move(notifyArgs));// Flush queued events out to the listener.// This must happen outside of the lock because the listener could potentially call// back into the InputReader's methods, such as getScanCodeState, or become blocked// on another thread similarly waiting to acquire the InputReader lock thereby// resulting in a deadlock. This situation is actually quite plausible because the// listener is actually the input dispatcher, which calls into the window manager,// which occasionally calls into the input reader.mQueuedListener.flush();//4.将事件交给InputDispatcher
}
首先是从从EventHub.getEvents方法中获取输入事件,然后调用processEventsLocked()来继续处理输入事件,最后调用 mQueuedListener.flush(.将事件交给InputDispatcher分发。
先来看下EventHub是什么。
2.EventHub
EventHub可以通过getEvents()方法读取的输入事件交给InputReader,它是基于INotify与Epoll机制工作的,先来介绍下INotify与Epoll
2.1 INotify
INotify是Linux系统提供的可以用来监听文件系统变化的一种机制,它可以监控文件系统的变化,如文件的新建、删除、读写等。
如果有新的设备插入,那么在/dev/input/目录下会生成event*文件,INotify可以用来监听/dev/input/是否有设备文件的增删。
Inotify的主要方法有三个:
(1)inotify_init:用来创建inotify描述符。
(2)inotify_add_watch(参数1,参数2,参数3):将一个或者多个事件添加监听,参数1表示描述符、参数2表示监听路径、参数3表示监听事件(如创建、删除等) 。
(3)read():完成事件添加后,当被监听的事件发生时(比如:对应路径下发生创建或者删除文件操作时)会将相应的事件信息写入到描述符中,此时可以通过read()函数从inotify描述符中将事件信息读取出来。
Inotify并不是通过回调的方法通知事件发生,那么如何确认读取事件的时机呢?这就需要Linux的另外一个机制了:Epoll
2.2 Epoll
无论是硬件设备产生输入事件,还是出现设备节点的创建、删除(inotify监听),都不是随时随地发生的,为了避免资源的浪费,Epoll机制可以很好的监听输入事件的产生。
Epoll是 Linux 内核提供的一种高效的 I/O 事件通知机制,可以高效地等待多个文件描述符的事件并处理它们,适用于处理大量并发连接的应用程序。它负责监听是否有可读事件出现,即是否有输入事件产生。
Epoll的主要方法有三个:
(1)epoll_create(int size):创建一个epoll对象的描述符,之后对epoll的操作均使用这个描述符完成。size参数表示可以监听的描述符的最大数量。
(2)epoll_ctl (int epfd, int op,int fd, struct epoll_event *event):用于管理注册事件的函数。这个函数可以增加/删除/修改事件的注册。
(3)int epoll_wait(int epfd, structepoll_event * events, int maxevents, int timeout):用于等待事件的到来。会使调用者陷入等待状态,直到其注册的事件之一发生之后才会返回。
INotify与Epoll的这些主要方法是在EventHub.cpp的构造方法里进行使用的
frameworks/native/services/inputflinger/reader/EventHub.cppstatic const char* DEVICE_INPUT_PATH = "/dev/input";EventHub::EventHub(void)......mEpollFd = epoll_create1(EPOLL_CLOEXEC);//创建epoll对象的描述符,监听设备节点是否出现事件LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));mINotifyFd = inotify_init1(IN_CLOEXEC);创建inotify对象的描述符,用于监听/dev/input/设备节点的变化LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno));if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {addDeviceInputInotify();//inotify监听/dev/input目录下设备节点的删除和创建.} .....struct epoll_event eventItem = {};//创建epoll结构体eventItem.events = EPOLLIN | EPOLLWAKEUP;//epoll监听可读eventItem.data.fd = mINotifyFd;int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);//添加事件监听LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);int wakeFds[2];//创建管道,将读端交给Epoll,写端交给InputReader,用来唤醒Epoll,避免阻塞在epoll_wait里result = pipe2(wakeFds, O_CLOEXEC);LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);mWakeReadPipeFd = wakeFds[0];mWakeWritePipeFd = wakeFds[1];result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",errno);result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",errno);eventItem.data.fd = mWakeReadPipeFd;result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);//将管道读取端的描述符注册到epoll中,用于监听读取端的可读事件,当写入端有事件写入时,读取端就有数据可以读,epoll_wait有返回值,从而唤醒InputReader,避免一直阻塞
}void EventHub::addDeviceInputInotify() {mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);//监听/dev/input目录下设备节点的删除和创建,当/dev/input/下的设备节点发生创建与删除操作时,会将相应的事件信息写入到inotifyFd所描述的inotify对象中LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",DEVICE_INPUT_PATH, strerror(errno));
}
3.getEvents
接着来继续看getEvents()方法是如何从EventHub中获取事件的
frameworks/native/services/inputflinger/reader/EventHub.cpp
std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {std::scoped_lock _l(mLock);//加锁,确保线程安全std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;//存储原始输入事件的bufferstd::vector<RawEvent> events;//获取到的事件bool awoken = false;//是否唤醒线程来处理事件for (;;) {//循环体,如果有可用事件,将事件放入到events中并返回;如果没有可用事件,则进入epoll_wait()等待事件的到来,epoll_wait()返回后会重新循环将可用将新事件放入events nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// Reopen input devices if needed.if (mNeedToReopenDevices) {//是否需要重新打开设备,InputReader的构造方法里会将这个值设置为truemNeedToReopenDevices = false;ALOGI("Reopening all input devices due to a configuration change.");closeAllDevicesLocked();//关闭所有设备mNeedToScanDevices = true;//是否扫描设备标识break; // return to the caller before we actually rescan}// Report any devices that had last been added/removed.for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {//遍历mClosingDevices,为已卸载的设备生成DEVICE_REMOVED事件std::unique_ptr<Device> device = std::move(*it);ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());const int32_t deviceId = (device->id == mBuiltInKeyboardId)? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID: device->id;events.push_back({//向events队列的尾部加入DEVICE_REMOVED数据.when = now,.deviceId = deviceId,.type = DEVICE_REMOVED,});it = mClosingDevices.erase(it);mNeedToSendFinishedDeviceScan = true;if (events.size() == EVENT_BUFFER_SIZE) {break;}}if (mNeedToScanDevices) {//扫描设备mNeedToScanDevices = false;scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}while (!mOpeningDevices.empty()) {std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());mOpeningDevices.pop_back();ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;events.push_back({//向events队列的尾部加入DEVICE_ADDED数据.when = now,.deviceId = deviceId,.type = DEVICE_ADDED,});// Try to find a matching video device by comparing device namesfor (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();it++) {std::unique_ptr<TouchVideoDevice>& videoDevice = *it;if (tryAddVideoDeviceLocked(*device, videoDevice)) {// videoDevice was transferred to 'device'it = mUnattachedVideoDevices.erase(it);break;}}auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));if (!inserted) {ALOGW("Device id %d exists, replaced.", device->id);}mNeedToSendFinishedDeviceScan = true;if (events.size() == EVENT_BUFFER_SIZE) {break;}}if (mNeedToSendFinishedDeviceScan) {//设备扫描结束mNeedToSendFinishedDeviceScan = false;events.push_back({//向events队列的尾部加入FINISHED_DEVICE_SCAN数据.when = now,.type = FINISHED_DEVICE_SCAN,});if (events.size() == EVENT_BUFFER_SIZE) {break;}}// Grab the next input event.bool deviceChanged = false;while (mPendingEventIndex < mPendingEventCount) {//mPendingEventIndex当前处理的事件,mPendingEventCount需要处理的事件数量const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];//从mPendingEventItems中读取事件if (eventItem.data.fd == mINotifyFd) {//如果获取到的epoll_event是mINotifyFd监听的事件,即设备节点删减事件if (eventItem.events & EPOLLIN) {//事件可读mPendingINotify = true;// 标记INotify事件待处理} else {ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);}continue;// 继续处理下一条epoll_event事件,直到不是mINotifyFd为止}if (eventItem.data.fd == mWakeReadPipeFd) {//如果获取到的是注册监听mWakeReadPipeFd事件,表示有事件可以读取if (eventItem.events & EPOLLIN) {//事件可读ALOGV("awoken after wake()");awoken = true;//设置awoken为truechar wakeReadBuffer[16];ssize_t nRead;do {//循环调用read方法读取管道中的数据nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));} else {ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",eventItem.events);}continue;// 继续处理下一条epoll_event事件,直到不是mWakeReadPipeFd为止}Device* device = getDeviceByFdLocked(eventItem.data.fd);//根据事件的文件描述符获取设备deviceif (device == nullptr) {//设备为空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()) {//TouchVideoDevice相关,这里不做分析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.data(),sizeof(decltype(readBuffer)::value_type) * readBuffer.size());if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {// Device was removed before INotify noticed.ALOGW("could not get event, removed? (fd: %d size: %" PRId32" capacity: %zu errno: %d)\n",device->fd, readSize, readBuffer.size(), errno);deviceChanged = true;closeDeviceLocked(*device);} else if (readSize < 0) {if (errno != EAGAIN && errno != EINTR) {ALOGW("could not get event (errno=%d)", errno);}} else if ((readSize % sizeof(struct input_event)) != 0) {ALOGE("could not get event (wrong size: %d)", readSize);} else {const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;const size_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) {struct input_event& iev = readBuffer[i];events.push_back({//将读取到输入事件存入events中.when = processEventTimestamp(iev),.readTime = systemTime(SYSTEM_TIME_MONOTONIC),.deviceId = deviceId,.type = iev.type,.code = iev.code,.value = iev.value,});}if (events.size() >= EVENT_BUFFER_SIZE) {// The result buffer is full. Reset the pending event index// so we will try to read the device again on the next iteration.mPendingEventIndex -= 1;break;}}} else if (eventItem.events & EPOLLHUP) {//挂起事件ALOGI("Removing device %s due to epoll hang-up event.",device->identifier.name.c_str());deviceChanged = true;closeDeviceLocked(*device);//关闭设备节点} else {ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,device->identifier.name.c_str());}}// readNotify() will modify the list of devices so this must be done after// processing all other events to ensure that we read all remaining events// before closing the devices.if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {//mINotifyFd有数据可读,说明设备节点发生了增删操作mPendingINotify = false;const auto res = readNotifyLocked();//读取mINotifyFd中的事件,同时对输入设备进行相应的加载与卸载操作if (!res.ok()) {ALOGW("Failed to read from inotify: %s", res.error().message().c_str());}deviceChanged = true;}// Report added or removed devices immediately.if (deviceChanged) {continue;// 设备节点增删操作发生时,则重新执行循环体}// Return now if we have collected any events or if we were explicitly awoken.if (!events.empty() || awoken) {//如果收集到事件或者要求唤醒InputReader,退出循环。break;}// Poll for events.// When a device driver has pending (unread) events, it acquires// a kernel wake lock. Once the last pending event has been read, the device// driver will release the kernel wake lock, but the epoll will hold the wakelock,// since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait// is called again for the same fd that produced the event.// Thus the system can only sleep if there are no events pending or// currently being processed.//// The timeout is advisory only. If the device is asleep, it will not wake just to// service the timeout.mPendingEventIndex = 0;mLock.unlock(); // release lock before pollint pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);//如果getevents没能获取事件,等待新事件到来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);//epoll_wait等到新的事件,重新循环,对新事件进行处理}}// All done, return the number of events we read.return events;//返回读取到的事件给InputReader
}
getEvents方法用来读取设备增删事件与原始输入事件,并将它们封装为RawEvent结构体,RawEvent结构体在 Android 系统中用于表示原始事件数据,定义如下:
frameworks/native/services/inputflinger/reader/include/EventHub.h
struct RawEvent {// Time when the event happenednsecs_t when;//事件发生的时间// Time when the event was read by EventHub. Only populated for input events.// For other events (device added/removed/etc), this value is undefined and should not be read.nsecs_t readTime;//EventHub 读取事件的时间int32_t deviceId;//发生事件的设备idint32_t type;//事件的类型,比如按键事件、触摸事件int32_t code;//事件的codeint32_t value;//事件的值
};
方法的重点是一个死循环,如果有可用事件,将事件放入到events中并返回;如果没有可用事件,则进入epoll_wait()等待事件的到来,epoll_wait()返回后会重新循环将可用将新事件放入events。
(1)getEvents方法首先判断是否需要重新打开设备,如果需要重新打开设备,后面会对设备进行扫描。mNeedToReopenDevices变量在InputReader的构造方法里会将被设置为true,一般是第一次用来记录设备信息;
(2)接着分别遍历mClosingDevices、mOpeningDevices来检查是否有设备添加/删除/扫描,用以生成DEVICE_REMOVED、DEVICE_ADDED、FINISHED_DEVICE_SCAN事件,push_back()方法向events队列的尾部加入DEVICE_REMOVED、DEVICE_ADDED、FINISHED_DEVICE_SCAN数据;
(3)while循环处理待处理的epoll_event事件,mPendingEventCount是需要处理的事件数量,只要mPendingEventCount有值(表示有输入事件产生),它就会一直循环。从mPendingEventItems中取出事件,对每一个eventItem事件进行读取:
如果获取到的epoll_event是mINotifyFd监听的事件并且可读,即设备节点删减事件,将mPendingINotify设置为true,标记INotify事件待处理,然后继续处理下一条epoll_event事件,直到不是mINotifyFd为止;
如果获取到的epoll_event是mWakeReadPipeFd事件,表示管道有事件可以读取,read方法循环调用read方法读取管道中的数据,直到mWakeReadPipeFd事件读取完为止;
如果获取到的rpoll_event是输入事件,即当前事件是输入设备节点产生的输入事件,那么将事件添加到events中;
如果mPendingINotify为true(前面读取mINotifyFd监听的事件会设置这个标识为true),说明设备节点发生了增删操作,对mINotifyFd里的事件进行读取;
(4)如果getEvents()方法获取到事件,或者需要唤醒InputReader,那么退出循环,结束本次调用,以便InputReader可以立刻处理这些事件;
(5)如果getevents没能获取事件,epoll_wait等待新事件到来,并将结果存储在mPendingEventItems里
(6)返回读取到的事件events给InputReader处理
4.processEventsLocked
getEvents获取到输入事件之后,processEventsLocked()继续处理输入事件:
frameworks/native/services/inputflinger/reader/InputReader.cppstd::list<NotifyArgs> InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {//参数表示读取的事件数据、事件个数std::list<NotifyArgs> out;//用于存储处理后的事件for (const RawEvent* rawEvent = rawEvents; count;) {//遍历每一个RawEvent事件int32_t type = rawEvent->type;//当前事件类型size_t batchSize = 1;if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {//输入设备产生的事件int32_t deviceId = rawEvent->deviceId;//设备节点Idwhile (batchSize < count) {if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||rawEvent[batchSize].deviceId != deviceId) {break;}batchSize += 1;}if (debugRawEvents()) {ALOGD("BatchSize: %zu Count: %zu", batchSize, count);}out += 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;}return out;
}
processEventsLocked方法会遍历getEvents()方法获取到的事件,如果是输入事件,那么调用processEventsForDeviceLocked()方法继续处理,并将处理好的事件结果添加到out列表中,这个out列表后面会交给InputDisapatch处理;
如果发生设备的增加、删除、扫描事件,那么调用addDeviceLocked、removeDeviceLocked、handleConfigurationChangedLocked方法分别处理。
这里主要看下processEventsForDeviceLocked()方法是如何处理设备输入事件的
frameworks/native/services/inputflinger/reader/InputReader.cppstd::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId,const RawEvent* rawEvents,size_t count) {auto deviceIt = mDevices.find(eventHubId);//根据eventHubId获取deviceItif (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 {};}return device->process(rawEvents, count);//继续调用InputDevice.cpp的process方法
}
调用InputDevice.cpp里的process方法
frameworks/native/services/inputflinger/reader/InputDevice.cppstd::list<NotifyArgs> 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.std::list<NotifyArgs> out;for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {//遍历每个事件if (debugRawEvents()) {const auto [type, code, value] =InputEventLookup::getLinuxEvdevLabel(rawEvent->type, rawEvent->code,rawEvent->value);ALOGD("Input event: eventHubDevice=%d type=%s code=%s value=%s when=%" PRId64,rawEvent->deviceId, type.c_str(), code.c_str(), value.c_str(), rawEvent->when);}if (mDropUntilNextSync) {if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {out += reset(rawEvent->when);mDropUntilNextSync = false;ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun.");} else {ALOGD_IF(debugRawEvents(),"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;} else {for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {out += mapper.process(rawEvent);//重点:调用每个子设备的InputMapper.process方法处理事件});}--count;}postProcess(out);return out;
}
主要逻辑是调用每个子设备对应的InputMapper.process方法处理事件,通过 InputMapper可以将原始输入事件转换为处理过的输入数据,单个输入设备可以有多个关联的InputMapper。
InputMapper是一个抽象类,它有很多子类:

比如处理键盘输入事件的KeyboardInputMapper、比如处理触摸输入事件的TouchInputMapper、处理鼠标输入事件的MouseInputMapper、处理光标输入事件的CursorInputMapper。
这里来看下键盘输入事件KeyboardInputMapper的process方法:
frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
std::list<NotifyArgs> KeyboardInputMapper::process(const RawEvent* rawEvent) {std::list<NotifyArgs> out;mHidUsageAccumulator.process(*rawEvent);switch (rawEvent->type) {case EV_KEY: {//如果是键盘码int32_t scanCode = rawEvent->code;//获取scan codeif (isSupportedScanCode(scanCode)) {//如果是支持的scan codeout += processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0,scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());//调用processKey方法处理按键}break;}}return out;
}std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,int32_t scanCode, int32_t usageCode) {std::list<NotifyArgs> out;int32_t keyCode;int32_t keyMetaState;uint32_t policyFlags;int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,&policyFlags)) {//扫描码映射失败keyCode = AKEYCODE_UNKNOWN;keyMetaState = mMetaState;policyFlags = 0;}nsecs_t downTime = when;std::optional<size_t> keyDownIndex = findKeyDownIndex(scanCode);if (down) {//按键被按下// Rotate key codes according to orientation if needed.if (mParameters.orientationAware) {//如果设备支持方向感知,根据设备的方向旋转按键代码keyCode = rotateKeyCode(keyCode, getOrientation());}// Add key down.if (keyDownIndex) {// key repeat, be sure to use same keycode as before in case of rotationkeyCode = mKeyDowns[*keyDownIndex].keyCode;downTime = mKeyDowns[*keyDownIndex].downTime;flags = mKeyDowns[*keyDownIndex].flags;} else {// key downif ((policyFlags & POLICY_FLAG_VIRTUAL) &&getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {return out;}if (policyFlags & POLICY_FLAG_GESTURE) {out += getDeviceContext().cancelTouch(when, readTime);flags |= AKEY_EVENT_FLAG_KEEP_TOUCH_MODE;}KeyDown keyDown;keyDown.keyCode = keyCode;keyDown.scanCode = scanCode;keyDown.downTime = when;keyDown.flags = flags;mKeyDowns.push_back(keyDown);}onKeyDownProcessed(downTime);} else {//按键up事件// Remove key down.if (keyDownIndex) {// key up, be sure to use same keycode as before in case of rotationkeyCode = mKeyDowns[*keyDownIndex].keyCode;downTime = mKeyDowns[*keyDownIndex].downTime;flags = mKeyDowns[*keyDownIndex].flags;mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex);} else {// key was not actually downALOGI("Dropping key up from device %s because the key was not down. ""keyCode=%d, scanCode=%d",getDeviceName().c_str(), keyCode, scanCode);return out;}}if (updateMetaStateIfNeeded(keyCode, down)) {// If global meta state changed send it along with the key.// If it has not changed then we'll use what keymap gave us,// since key replacement logic might temporarily reset a few// meta bits for given key.keyMetaState = mMetaState;}// Any key down on an external keyboard should wake the device.// We don't do this for internal keyboards to prevent them from waking up in your pocket.// For internal keyboards and devices for which the default wake behavior is explicitly// prevented (e.g. TV remotes), the key layout file should specify the policy flags for each// wake key individually.if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&!(mKeyboardType != AINPUT_KEYBOARD_TYPE_ALPHABETIC && isMediaKey(keyCode))) {policyFlags |= POLICY_FLAG_WAKE;}if (mParameters.handlesKeyRepeat) {policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;}//创建一个 NotifyKeyArgs 对象,包含按键事件的详细信息,例如事件 ID、时间戳、设备信息、按键代码等,并将其添加到 out 列表中out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(),mSource, getDisplayId(), policyFlags,down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags,keyCode, scanCode, keyMetaState, downTime));return out;//返回一个 NotifyArgs 对象的列表,包含按键事件的详细信息
}
分别对按键的按下和抬起事件进行处理 ,将按键事件的详细信息,例如事件 ID、时间戳、设备信息、按键代码等封装成一个NotifyKeyArgs对象,并将其添加到 out 列表中返回。
从上面过程可以看出原始输入事件经过getEvents()之后被封装成RawEvent,经过processEventsLocked方法之后被封装成NotifyKeyArgs对象。
最后,mQueuedListener.flush()方法将封装好的事件传递给InputDispatcher。
5.flush()
frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::flush() {for (const NotifyArgs& args : mArgsQueue) {mInnerListener.notify(args);//遍历每个事件,调用mInnerListener.notify()方法}mArgsQueue.clear();
}
这里的args就是上文各个mapper生成的NotifyKeyArgs。主要是调用InputListener.cpp里的notify方法
frameworks/native/services/inputflinger/InputListener.cpp
void InputListenerInterface::notify(const NotifyArgs& generalArgs) {Visitor v{[&](const NotifyInputDevicesChangedArgs& args) { notifyInputDevicesChanged(args); },[&](const NotifyConfigurationChangedArgs& args) { notifyConfigurationChanged(args); },[&](const NotifyKeyArgs& args) { notifyKey(args); },[&](const NotifyMotionArgs& args) { notifyMotion(args); },[&](const NotifySwitchArgs& args) { notifySwitch(args); },[&](const NotifySensorArgs& args) { notifySensor(args); },[&](const NotifyVibratorStateArgs& args) { notifyVibratorState(args); },[&](const NotifyDeviceResetArgs& args) { notifyDeviceReset(args); },[&](const NotifyPointerCaptureChangedArgs& args) { notifyPointerCaptureChanged(args); },};std::visit(v, generalArgs);
}
根据传入的args类型,调用不同的方法,这里调用的是notifyKey(args)方法。
InputDispatcher继承了InputListenerInterface,所以这个方法实际上是在InputDispatcher里实现的
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {ALOGD_IF(debugInboundEventDetails(),"notifyKey - id=%" PRIx32 ", eventTime=%" PRId64", deviceId=%d, source=%s, displayId=%" PRId32"policyFlags=0x%x, action=%s, flags=0x%x, keyCode=%s, scanCode=0x%x, metaState=0x%x, ""downTime=%" PRId64,args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags,KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime);Result<void> keyCheck = validateKeyEvent(args.action);//检查是否是可用的keyeventif (!keyCheck.ok()) {LOG(ERROR) << "invalid key event: " << keyCheck.error();return;}uint32_t policyFlags = args.policyFlags;int32_t flags = args.flags;int32_t metaState = args.metaState;// InputDispatcher tracks and generates key repeats on behalf of// whatever notifies it, so repeatCount should always be set to 0constexpr int32_t repeatCount = 0;if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {policyFlags |= POLICY_FLAG_VIRTUAL;flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;}if (policyFlags & POLICY_FLAG_FUNCTION) {metaState |= AMETA_FUNCTION_ON;}policyFlags |= POLICY_FLAG_TRUSTED;int32_t keyCode = args.keyCode;KeyEvent event;event.initialize(args.id, args.deviceId, args.source, args.displayId, INVALID_HMAC, args.action,flags, keyCode, args.scanCode, metaState, repeatCount, args.downTime,args.eventTime);//初始化eventandroid::base::Timer t;mPolicy.interceptKeyBeforeQueueing(event, /*byref*/ policyFlags);//调用PhoneWindowManager里的interceptKeyBeforeQueueing方法if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",std::to_string(t.duration().count()).c_str());}bool needWake = false;{ // acquire lockmLock.lock();if (shouldSendKeyToInputFilterLocked(args)) {mLock.unlock();policyFlags |= POLICY_FLAG_FILTERED;if (!mPolicy.filterInputEvent(event, policyFlags)) {return; // event was consumed by the filter}mLock.lock();}std::unique_ptr<KeyEntry> newEntry =std::make_unique<KeyEntry>(args.id, /*injectionState=*/nullptr, args.eventTime,args.deviceId, args.source, args.displayId, policyFlags,args.action, flags, keyCode, args.scanCode, metaState,repeatCount, args.downTime);//封装成KeyEntryif (mTracer) {newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);}needWake = enqueueInboundEventLocked(std::move(newEntry));//入队mLock.unlock();} // release lockif (needWake) {mLooper->wake();//如果有必要,唤醒线程。}
}
这里有一个很熟悉的方法mPolicy.interceptKeyBeforeQueueing,最终调用的是PhoneWindowManager里的interceptKeyBeforeQueueing,在入队之前判断是否需要对事件进行拦截。
然后将事件封装成KeyEntry,接着调用enqueueInboundEventLocked将事件入队。
bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newEntry) {bool needWake = mInboundQueue.empty();//mInboundQueue为空则需要唤醒mInboundQueue.push_back(std::move(newEntry));//将封装好的EventEntry事件加入mInboundQueue队列const EventEntry& entry = *(mInboundQueue.back());traceInboundQueueLengthLocked();switch (entry.type) {case EventEntry::Type::KEY: {LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,"Unexpected untrusted event.");const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);if (mTracer) {ensureEventTraced(keyEntry);}// If a new up event comes in, and the pending event with same key code has been asked// to try again later because of the policy. We have to reset the intercept key wake up// time for it may have been handled in the policy and could be dropped.if (keyEntry.action == AKEY_EVENT_ACTION_UP && mPendingEvent &&mPendingEvent->type == EventEntry::Type::KEY) {const KeyEntry& pendingKey = static_cast<const KeyEntry&>(*mPendingEvent);if (pendingKey.keyCode == keyEntry.keyCode &&pendingKey.interceptKeyResult ==KeyEntry::InterceptKeyResult::TRY_AGAIN_LATER) {pendingKey.interceptKeyResult = KeyEntry::InterceptKeyResult::UNKNOWN;pendingKey.interceptKeyWakeupTime = 0;needWake = true;}}break;}case EventEntry::Type::MOTION: {LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,"Unexpected untrusted event.");const auto& motionEntry = static_cast<const MotionEntry&>(entry);if (mTracer) {ensureEventTraced(motionEntry);}if (shouldPruneInboundQueueLocked(motionEntry)) {mNextUnblockedEvent = mInboundQueue.back();needWake = true;}const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN &&isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER);if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) {// Prevent waiting too long for unprocessed events: if we have a pending key event,// and some other events have not yet been processed, the dispatcher will wait for// these events to be processed before dispatching the key event. This is because// the unprocessed events may cause the focus to change (for example, by launching a// new window or tapping a different window). To prevent waiting too long, we force// the key to be sent to the currently focused window when a new tap comes in.ALOGD("Received a new pointer down event, stop waiting for events to process and ""just send the pending key event to the currently focused window.");mKeyIsWaitingForEventsTimeout = now();needWake = true;}break;}case EventEntry::Type::FOCUS: {LOG_ALWAYS_FATAL("Focus events should be inserted using enqueueFocusEventLocked");break;}case EventEntry::Type::TOUCH_MODE_CHANGED:case EventEntry::Type::CONFIGURATION_CHANGED:case EventEntry::Type::DEVICE_RESET:case EventEntry::Type::SENSOR:case EventEntry::Type::POINTER_CAPTURE_CHANGED:case EventEntry::Type::DRAG: {// nothing to dobreak;}}return needWake;
}
主要是将封装好的EventEntry事件加入mInboundQueue队列。
6.总结
可以看出InputReader处理事件的流程为:
(1)调用EventHub的getEvents方法获取输入事件
(2)调用processEventsLocked()方法处理获取到的输入事件
(3)调用flush()方法将已经封装好的EventEntry事件交给给InputDispatcher分发
