Android U Input 系统:InputReader 的创建与启动

1,627 阅读9分钟

根据前面文章的分析,InputReader 创建的代码如下

// InputManager.cpp

InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy,
                           InputDispatcherPolicyInterface& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mProcessor = std::make_unique<InputProcessor>(*mDispatcher);
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mProcessor);

    // 创建 InputReader
    mReader = createInputReader(readerPolicy, *mBlocker);
}
// InputReaderFactory.cpp

std::unique_ptr<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {
    // 先创建 EventHub,再创建 InputReader
    return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);
}

InputReader 需要从 EventHub 中获取事件,因此需要先创建 EventHub。

创建 EventHub

// EventHub.cpp

EventHub::EventHub(void)
      : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
        mNextDeviceId(1),
        mControllerNumbers(),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false),
        // mNeedToScanDevices 被初始化为 true,表示需要扫描设备
        mNeedToScanDevices(true),
        mPendingEventCount(0),
        mPendingEventIndex(0),
        mPendingINotify(false) {
    ensureProcessCanBlockSuspend();

    // 创建 epoll
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    
    // 创建 inotify
    mINotifyFd = inotify_init1(IN_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno));

    std::error_code errorCode;
    bool isDeviceInotifyAdded = false;

    // 存在 /dev/input 目录
    if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
        // inotify 监听 /dev/input 目录,也就是监听输入设备的增删
        addDeviceInputInotify();
    } else {
        // ...
    }

    if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
        addDeviceInotify();
    } else {
        ALOGI("Video device scanning disabled");
    }

    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = mINotifyFd;
    // epoll 监听 inotify 事件
    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];
    // 创建用户唤醒的 pipe
    result = pipe2(wakeFds, O_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);

    // 保存 pipe 的两端
    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;
    // epoll 监听 pipe 的读端
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
                        errno);
}

EventHub 创建时,主要做了两件事情

  1. 通过 inotify ,监听 /dev/input 目录,也就是监听输入设备的增删。然后用 epoll 监听 inotify 事件。那么,当发生设备增删的时候,epoll 就会收到事件,然后通知 InputReader 处理。
  2. 创建一个 pipe(管道),epoll 只监听管道的读端。写端被其他模块使用,例如,当输入设备配置改变时,通过管道的写端写入数据,然后可以唤醒 InputReader 处理配置改变。

epoll, inotify, pipe,它们的作用和使用方式,请读者自行查阅 Unix/Linux 资料。

创建 InputReader

// InputReader.cpp

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         InputListenerInterface& listener)
      : mContext(this),
        mEventHub(eventHub),
        mPolicy(policy), // 指向 NativeInputManager
        // 初始化 QueuedInputListener mQueuedListener
        // listener 指向 UnwantedInteractionBlocker
        mQueuedListener(listener), 
        mGlobalMetaState(AMETA_NONE),
        mLedMetaState(AMETA_NONE),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN),
        mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {

    // 刷新配置
    refreshConfigurationLocked(/*changes=*/{});

    // 此时还没有扫描输入设备,因此没有 global meta state
    updateGlobalMetaStateLocked();
}

void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) {
    // 获取配置,保存到 InputReader::mConfig
    mPolicy->getReaderConfiguration(&mConfig);
    // EventHub::mExcludedDevices 保存排除的输入设备
    mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);

    using Change = InputReaderConfiguration::Change;
    if (!changes.any()) return;

    // ...
}

InputReader 的构造函数,做了一些变量初始化,然后最主要的是刷新配置,如下

// com_android_server_input_InputManagerService.cpp

void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
    ATRACE_CALL();
    JNIEnv* env = jniEnv();

    jint virtualKeyQuietTime = env->CallIntMethod(mServiceObj,
            gServiceClassInfo.getVirtualKeyQuietTimeMillis);
    if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
        outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime);
    }

    outConfig->excludedDeviceNames.clear();
    jobjectArray excludedDeviceNames = jobjectArray(env->CallStaticObjectMethod(
            gServiceClassInfo.clazz, gServiceClassInfo.getExcludedDeviceNames));
    if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) {
        jsize length = env->GetArrayLength(excludedDeviceNames);
        for (jsize i = 0; i < length; i++) {
            std::string deviceName = getStringElementFromJavaArray(env, excludedDeviceNames, i);
            outConfig->excludedDeviceNames.push_back(deviceName);
        }
        env->DeleteLocalRef(excludedDeviceNames);
    }

    // Associations between input ports and display ports
    // The java method packs the information in the following manner:
    // Original data: [{'inputPort1': '1'}, {'inputPort2': '2'}]
    // Received data: ['inputPort1', '1', 'inputPort2', '2']
    // So we unpack accordingly here.
    outConfig->portAssociations.clear();
    jobjectArray portAssociations = jobjectArray(env->CallObjectMethod(mServiceObj,
            gServiceClassInfo.getInputPortAssociations));
    if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) {
        jsize length = env->GetArrayLength(portAssociations);
        for (jsize i = 0; i < length / 2; i++) {
            std::string inputPort = getStringElementFromJavaArray(env, portAssociations, 2 * i);
            std::string displayPortStr =
                    getStringElementFromJavaArray(env, portAssociations, 2 * i + 1);
            uint8_t displayPort;
            // Should already have been validated earlier, but do it here for safety.
            bool success = ParseUint(displayPortStr, &displayPort);
            if (!success) {
                ALOGE("Could not parse entry in port configuration file, received: %s",
                    displayPortStr.c_str());
                continue;
            }
            outConfig->portAssociations.insert({inputPort, displayPort});
        }
        env->DeleteLocalRef(portAssociations);
    }

    outConfig->uniqueIdAssociations =
            readMapFromInterleavedJavaArray<std::string>(gServiceClassInfo
                                                                 .getInputUniqueIdAssociations,
                                                         "getInputUniqueIdAssociations");

    outConfig->deviceTypeAssociations =
            readMapFromInterleavedJavaArray<std::string>(gServiceClassInfo
                                                                 .getDeviceTypeAssociations,
                                                         "getDeviceTypeAssociations");
    
    outConfig->keyboardLayoutAssociations = readMapFromInterleavedJavaArray<
            KeyboardLayoutInfo>(gServiceClassInfo.getKeyboardLayoutAssociations,
                                "getKeyboardLayoutAssociations", [](auto&& layoutIdentifier) {
                                    size_t commaPos = layoutIdentifier.find(',');
                                    std::string languageTag = layoutIdentifier.substr(0, commaPos);
                                    std::string layoutType = layoutIdentifier.substr(commaPos + 1);
                                    return KeyboardLayoutInfo(std::move(languageTag),
                                                              std::move(layoutType));
                                });

    jint hoverTapTimeout = env->CallIntMethod(mServiceObj,
            gServiceClassInfo.getHoverTapTimeout);
    if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
        jint doubleTapTimeout = env->CallIntMethod(mServiceObj,
                gServiceClassInfo.getDoubleTapTimeout);
        if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
            jint longPressTimeout = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.getLongPressTimeout);
            if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
                outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);

                // We must ensure that the tap-drag interval is significantly shorter than
                // the long-press timeout because the tap is held down for the entire duration
                // of the double-tap timeout.
                jint tapDragInterval = max(min(longPressTimeout - 100,
                        doubleTapTimeout), hoverTapTimeout);
                outConfig->pointerGestureTapDragInterval =
                        milliseconds_to_nanoseconds(tapDragInterval);
            }
        }
    }

    jint hoverTapSlop = env->CallIntMethod(mServiceObj,
            gServiceClassInfo.getHoverTapSlop);
    if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
        outConfig->pointerGestureTapSlop = hoverTapSlop;
    }

    { // acquire lock
        std::scoped_lock _l(mLock);

        outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
                * POINTER_SPEED_EXPONENT);
        outConfig->pointerVelocityControlParameters.acceleration = mLocked.pointerAcceleration;
        outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;

        outConfig->showTouches = mLocked.showTouches;

        outConfig->pointerCaptureRequest = mLocked.pointerCaptureRequest;

        outConfig->setDisplayViewports(mLocked.viewports);

        outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId;

        outConfig->touchpadPointerSpeed = mLocked.touchpadPointerSpeed;
        outConfig->touchpadNaturalScrollingEnabled = mLocked.touchpadNaturalScrollingEnabled;
        outConfig->touchpadTapToClickEnabled = mLocked.touchpadTapToClickEnabled;
        outConfig->touchpadRightClickZoneEnabled = mLocked.touchpadRightClickZoneEnabled;

        outConfig->disabledDevices = mLocked.disabledInputDevices;

        outConfig->stylusButtonMotionEventsEnabled = mLocked.stylusButtonMotionEventsEnabled;

        outConfig->stylusPointerIconEnabled = mLocked.stylusPointerIconEnabled;
    } // release lock
}

InputReader 的配置 mConfig,大部分来自于上层,我们可以通过 dumpsys input 来观测到大部分的配置数据,如下

Input Reader State (Nums of device: 9):

  ...

  Configuration:
    ExcludedDeviceNames: [qti-haptics, qcom-hv-haptics]
    VirtualKeyQuietTime: 0.0ms
    PointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000
    WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000
    PointerGesture:
      Enabled: true
      QuietInterval: 100.0ms
      DragMinSwitchSpeed: 50.0px/s
      TapInterval: 150.0ms
      TapDragInterval: 300.0ms
      TapSlop: 20.0px
      MultitouchSettleInterval: 100.0ms
      MultitouchMinDistance: 15.0px
      SwipeTransitionAngleCosine: 0.3
      SwipeMaxWidthRatio: 0.2
      MovementSpeedRatio: 0.8
      ZoomSpeedRatio: 0.3
      Viewports:
        Viewport INTERNAL: displayId=0, uniqueId=local:4630946650788219010, port=130, orientation=0, logicalFrame=[0, 0, 1080, 2400], physicalFrame=[0, 0, 1260, 2800], deviceSize=[1260, 2800], isActive=[1]

InputReder 线程循环

根据前面一篇文章的分析可知,InputReader 在启动时,是创建一个线程,然后循环执行 loopOnce()

// 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);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        auto changes = mConfigurationChangesToRefresh;
        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

    // 1. 从 EventHub 读取事件
    std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);

    { // acquire lock
        std::scoped_lock _l(mLock);
        mReaderIsAliveCondition.notify_all();

        // 2. 处理读取到的事件
        if (!events.empty()) {
            notifyArgs += processEventsLocked(events.data(), events.size());
        }

        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);
            }
        }

        // 处理设备改变
        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            inputDevices = getInputDevicesLocked();
            notifyArgs.emplace_back(
                    NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices});
        }
    } // release lock

    // 如果设备改变了,那么把这些数据数据发送给上层 InputManagerService
    // InputManagerService 使用 mInputDevices 保存这些数据
    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);
        }
    }

    // 3. 把所有事件加入到  mQueuedListener 的队列中
    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.
    // 4. 刷新 mQueuedListener,把所有事件分发给下一环
    mQueuedListener.flush();
}

InputReader 在每一次线程循环中,会从 EventHub 获取事件,当然,如果输入设备并没有产生事件,那么 InputReader 线程就阻塞了。

当 InputReader 从 EventHub 获取到事件之后,就处理事件。 EventHub 的输入设备的事件,来自于驱动上报,它们称之为 raw event(元事件)。InputReader 处理 raw event 后,会把事件重新包装成 NotifyArgs,然后加入到 mQueuedListener 的队列中。

最后,mQueuedListener 刷新队列,把队列中所有事件,逐个发送给下一环。根据前面的文章分析可知,下一环是 UnwantedInteractionBlocker 。

从 Eventhub 获取事件

// EventHub.cpp

std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
    std::scoped_lock _l(mLock);

    std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;

    // events 保存的是返回给 InputReader 的事件
    std::vector<RawEvent> events;
    bool awoken = false;

    // 通过一个无限循环,不断获取数据,直到有数据才跳出循环
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // Reopen input devices if needed.
        if (mNeedToReopenDevices) {
            // ...
            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();) {
            // ...
        }

        // mNeedToScanDevices 初始值为 true
        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;

            // 为每一个输入设备填充一个 DEVICE_ADDED 事件
            events.push_back({
                    .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;
                }
            }

            // mDevices 以 id 为 KEY 保存输入设备数据
            // mDevices : id -> Device
            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;
            }
        }

        // 设备扫描完成后,补充一个 FINISHED_DEVICE_SCAN 事件
        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            events.push_back({
                    .when = now,
                    .type = FINISHED_DEVICE_SCAN,
            });
            if (events.size() == EVENT_BUFFER_SIZE) {
                break;
            }
        }

        // 处理从 epoll 获取的数据
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            // 注意,mPendingEventIndex 加 1 了
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];

            // 数据来自于 inotify ,表明有设备增删
            if (eventItem.data.fd == mINotifyFd) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

            // 数组来自于管道
            if (eventItem.data.fd == mWakeReadPipeFd) {
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    // 需要唤醒 InputReader 线程处理事件
                    awoken = true;
                    char wakeReadBuffer[16];
                    ssize_t nRead;
                    do {
                        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;
            }

            Device* device = getDeviceByFdLocked(eventItem.data.fd);
            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()) {
                // ...
                continue;
            }

            // This must be an input event
            // 处理输入设备的事件,例如 motion event,key 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)) {
                    // ...
                } else if (readSize < 0) {
                    // ...
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    // ...
                } 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({
                                .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) {
                // ...
            } else {
                // ...
            }
        }

        // 处理 inotify 事件
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            // 处理输入设备的增删
            // 如果是增加了设备,会保存到 mOpeningDevices ,如果是删除设备,会保存到 mClosingDevices
            const auto res = readNotifyLocked();
            if (!res.ok()) {
                ALOGW("Failed to read from inotify: %s", res.error().message().c_str());
            }
            // 有 inotify 数据,表明输入设备改变了,例如增删
            deviceChanged = true;
        }

        // 在下一次的循环中,处理 mOpeningDevices 或 mClosingDevices ,会返回事件给 InputReader
        if (deviceChanged) {
            continue;
        }

        // 如果有事件,或者被管道唤醒,立即退出无限循环,让 InputReader 处理事件或者处理被唤醒的原因
        if (!events.empty() || awoken) {
            break;
        }

        // 重置索引
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll

        // 以阻塞的方式,从 epoll 中等待事件
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        mLock.lock(); // reacquire lock after poll

        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }

        if (pollResult < 0) {
            // 异常 ...
        } else {
            // 保存从 epoll 读取到事件的数量
            mPendingEventCount = size_t(pollResult);
        }
    }

    // All done, return the number of events we read.
    return events;
}

EventHub 提供数据的方式,是先从 epoll 阻塞等待获取事件,然后把事件返回给 InputReader。根据 EventHub 构造函数的分析可知,epoll 监听了 inotify,从而监听了输入设备的增删事件,epoll 还监听了管道的读端,用于唤醒 InputReader 线程来处理一些事情,例如,处理配置更新。

但是,InputReader 首次从 EventHub 获取数据时,EventHub 会扫描输入设备。这个过程很重要,因为会为输入设备建立数据。当输入设备产生事件,例如,key event 或 motion event,需要根据输入设备的参数,来决定如何处理事件。因此,接下来一篇文章,需要先分析输入设备的扫描过程。