1.InputReader启动
InputReader和InputDispatcher是IMS中的两个重要的线程,InputReader主要负责从Eventhub获取事件,然后将事件进行处理,并将封装好的EventEntry事件交给InputDispatcher的去进行分发;InputDispatcher主要负责将输入事件分发到对应的窗口。
这两个线程都是在IMS启动时创建并启动的,这里主要分析InputReader是如何工作的,代码基于Android 14:
IMS启动时会调用start方法去启动InputReader线程:
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;
}
创建一个名称为InputReader的线程,然后主要做了两件事情:执行loopOnce()方法、唤醒EventHub,主要看下loopOnce方法:
在这个线程中执行loopOnce()方法,用来读取输入设备生成的事件
frameworks/native/services/inputflinger/reader/InputReader.cpp
void 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 lock
std::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 lock
std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);//1.从EventHub中获取输入事件,getEvents方法会阻塞直到超时或者有事件到达
{ // acquire lock
std::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.cpp
static 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;//存储原始输入事件的buffer
std::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的构造方法里会将这个值设置为true
mNeedToReopenDevices = 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 names
for (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为true
char 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);//根据事件的文件描述符获取设备device
if (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 EPOLLRDHUP
ALOGI("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 event
if (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 poll
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);//如果getevents没能获取事件,等待新事件到来
mLock.lock(); // reacquire lock after poll
if (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 happened
nsecs_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;//发生事件的设备id
int32_t type;//事件的类型,比如按键事件、触摸事件
int32_t code;//事件的code
int32_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.cpp
std::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;//设备节点Id
while (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 happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
return out;
}
processEventsLocked方法会遍历getEvents()方法获取到的事件,如果是输入事件,那么调用processEventsForDeviceLocked()方法继续处理,并将处理好的事件结果添加到out列表中,这个out列表后面会交给InputDisapatch处理;
如果发生设备的增加、删除、扫描事件,那么调用addDeviceLocked、removeDeviceLocked、handleConfigurationChangedLocked方法分别处理。
这里主要看下processEventsForDeviceLocked()方法是如何处理设备输入事件的
frameworks/native/services/inputflinger/reader/InputReader.cpp
std::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId,
const RawEvent* rawEvents,
size_t count) {
auto deviceIt = mDevices.find(eventHubId);//根据eventHubId获取deviceIt
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 {};
}
return device->process(rawEvents, count);//继续调用InputDevice.cpp的process方法
}
调用InputDevice.cpp里的process方法
frameworks/native/services/inputflinger/reader/InputDevice.cpp
std::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 code
if (isSupportedScanCode(scanCode)) {//如果是支持的scan code
out += 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 rotation
keyCode = mKeyDowns[*keyDownIndex].keyCode;
downTime = mKeyDowns[*keyDownIndex].downTime;
flags = mKeyDowns[*keyDownIndex].flags;
} else {
// key down
if ((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 rotation
keyCode = mKeyDowns[*keyDownIndex].keyCode;
downTime = mKeyDowns[*keyDownIndex].downTime;
flags = mKeyDowns[*keyDownIndex].flags;
mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex);
} else {
// key was not actually down
ALOGI("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);//检查是否是可用的keyevent
if (!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 0
constexpr 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);//初始化event
android::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 lock
mLock.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);//封装成KeyEntry
if (mTracer) {
newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
}
needWake = enqueueInboundEventLocked(std::move(newEntry));//入队
mLock.unlock();
} // release lock
if (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 do
break;
}
}
return needWake;
}
主要是将封装好的EventEntry事件加入mInboundQueue队列。
6.总结
可以看出InputReader处理事件的流程为:
(1)调用EventHub的getEvents方法获取输入事件
(2)调用processEventsLocked()方法处理获取到的输入事件
(3)调用flush()方法将已经封装好的EventEntry事件交给给InputDispatcher分发