input系统之InputReader

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分发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值