AOSP15 Input专题InputReader源码分析

在 Android 15 中,InputReader 依然是输入系统(Input System)的核心组件,负责从内核读取原始事件并进行预处理。理解它的调用流程,需要将其放在 InputDispatcher 的上下文中观察。

一、 输入系统的宏观调用流向

输入系统的宏观调用流向 当用户操作屏幕时,事件在内核驱动和用户空间之间流转。

二、 详细调用链路分析 (从内核到 Mapper)

1. 第一步:驱动循环 (InputReader.cpp)

InputReader 运行在一个独立的线程中,其主循环 loopOnce() 不断地询问 EventHub 是否有新数据。

  • 文件: frameworks/native/services/inputflinger/reader/InputReader.cpp

  • 方法分析:

c++ 复制代码
void InputReader::loopOnce() {
    // 省略代码

    // 1. 获取内核事件
    std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);
    {
        // 省略代码

        if (!events.empty()) {
            // 2. 遍历事件并分发
            mPendingArgs += processEventsLocked(events.data(), events.size());
        }
    } 
    // 省略代码
}

2. 获取事件 (Get Events)

调用 EventHub::getEvents()。这是阻塞操作,直到内核有新输入(触控、按键等)

  • 文件: frameworks/native/services/inputflinger/reader/EventHub.cpp
c++ 复制代码
std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
    std::scoped_lock _l(mLock);

    std::array<input_event, EVENT_BUFFER_SIZE> readBuffer;

    std::vector<RawEvent> events;
    bool awoken = false;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        //省略部分

        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
        }

        //第一次一般遍历mOpeningDevices这个列表进行各个device获取变成DEVICE_ADDED
        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({
                    .when = now,
                    .deviceId = deviceId,
                    .type = DEVICE_ADDED,
            });

             //省略部分
        }

         //第一次扫描时候没有消息,指导后面有触摸消息才会进入这里,这里是会由下面epoll监听消息触发
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.fd == mINotifyFd) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

            if (eventItem.data.fd == mWakeReadPipeFd) {
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    awoken = true;
                    char 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 (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;
                    //获取真实读取到的inputevent数据真实个数
                    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];
                        device->trackInputEvent(iev);
                        events.push_back({
                                .when = processEventTimestamp(iev),
                                .readTime = systemTime(SYSTEM_TIME_MONOTONIC),
                                .deviceId = deviceId,
                                .type = iev.type,
                                .code = iev.code,
                                .value = iev.value,
                        });
                    }
                    //省略部分
                }
            } 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 {
                // 省略部分
            }
        }

        // 省略部分

        //这里epoll在等待消息产生,产生消息EventItem都会放到mPendingEventItems中
        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 {
            // 这里对mPendingEventCount进行赋值真正有多少个事件产生
            mPendingEventCount = size_t(pollResult);
        }
    }
    return events;
}

3. 设备查找 (InputReader.cpp)

processEventsLocked->processEventsForDeviceLocked 会根据 RawEvent 中的 deviceId 找到对应的 InputDevice 对象

  • 文件: frameworks/native/services/inputflinger/reader/InputReader.cpp
  • 方法分析:
c++ 复制代码
std::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId,
                                                                const RawEvent* rawEvents,
                                                                size_t count) {
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return {};
    }
    // 通过 deviceId 查找设备
    std::shared_ptr<InputDevice>& device = deviceIt->second;
    if (device->isIgnored()) {
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return {};
    }
    // 关键点:调用设备的 process 方法
    return device->process(rawEvents, count);
}

4. 分发至 Mapper (InputDevice.cpp)

InputDevice 充当了"管家"的角色。它内部维护了一组 InputMapper。当收到一个 RawEvent 时,它会将该事件广播给所有在该设备上注册的 Mapper(例如:TouchInputMapper、KeyboardInputMapper)

  • 文件: frameworks/native/services/inputflinger/reader/InputDevice.cpp
  • 方法分析:
c++ 复制代码
std::list<NotifyArgs> InputDevice::process(const RawEvent* rawEvents, size_t count) {
    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);
        }
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                out += reset(rawEvent->when);
                mDropUntilNextSync = false;
            } else {
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
        } else {
            // 调用每个 Mapper 的 process 方法
            for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {
                out += mapper.process(*rawEvent);
            });
        }
        --count;
    }
    postProcess(out);
    return out;
}

5. 具体 Mapper 处理 (TouchInputMapper.cpp)

这里就是你寻找的地方。TouchInputMapper 接收到原始事件后,会解析该事件并将其填充到 mCurrentRawState 结构体中。

  • 文件: frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp
  • 方法分析:
c++ 复制代码
std::list<NotifyArgs> TouchInputMapper::process(const RawEvent& rawEvent) {

    // 更新触摸坐标、压力值等
    mCursorButtonAccumulator.process(rawEvent);
    mCursorScrollAccumulator.process(rawEvent);
    mTouchButtonAccumulator.process(rawEvent);

    std::list<NotifyArgs> out;
    // 当遇到 SYN_REPORT 时,标志着一个完整事件帧的结束
    if (rawEvent.type == EV_SYN && rawEvent.code == SYN_REPORT) {
        out += sync(rawEvent.when, rawEvent.readTime);
    }
    return out;
}

6. 坐标转换与分发:TouchInputMapper::processRawTouches()

这里就是你寻找的地方。TouchInputMapper 接收到原始事件后,会解析该事件并将其填充到 mCurrentRawState 结构体中。

  • 文件: frameworks/native/services/inputflinger/reader/mapper/touch/TouchInputMapper.cpp
  • 详细步骤:
    1. Normalization: 将内核定义的逻辑坐标归一化。

    2. Transformation: 应用 SurfaceRotation 和 CalibrationMatrix(如坐标偏移、缩放)。

    3. Gesture Generation: 识别是"点按"、"拖动"还是"多指捏合"。

    4. Notify: 调用 getListener().notifyMotion(&args) 将处理好的数据发送给 InputDispatcher。

c++ 复制代码
bool InputReader::gDisable = false;
std::list<NotifyArgs> TouchInputMapper::processRawTouches(bool timeout) {
    std::list<NotifyArgs> out;
    // InputReader::gDisable 全局输入开关(调试/系统控制)
    // mDeviceMode == DISABLED 当前设备被逻辑禁用
    if (InputReader::gDisable || mDeviceMode == DeviceMode::DISABLED) {
        return out;
    }
    // Drain Raw 队列(真正的核心循环)
    const size_t N = mRawStatesPending.size();
    size_t count;
    for (count = 0; count < N; count++) {
        const RawState& next = mRawStatesPending[count];
        if (assignExternalStylusId(next, timeout)) {
            break;
        }

        // All ready to go.
        clearStylusDataPendingFlags();
        mCurrentRawState = next;
        if (mCurrentRawState.when < mLastRawState.when) {
            mCurrentRawState.when = mLastRawState.when;
            mCurrentRawState.readTime = mLastRawState.readTime;
        }
        // 真正的转换 + 分发
        out += cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
    }
    if (count != 0) {
        // 处理完成后清理队列
        mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
    }

    if (mExternalStylusDataPending) {
        if (timeout) {
            nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
            clearStylusDataPendingFlags();
            mCurrentRawState = mLastRawState;
            ALOGD_IF(DEBUG_STYLUS_FUSION,
                     "Timeout expired, synthesizing event with new stylus data");
            const nsecs_t readTime = when; 
            // 真正的转换 + 分发
            out += cookAndDispatch(when, readTime);
        } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
            mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
            getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
        }
    }
    return out;
}

三、总结

  1. EventHub (生产):利用 epoll 监听 /dev/input/,将内核信号封装为 RawEvent。

  2. InputReader (循环):在 loopOnce() 中轮询 EventHub,并将事件分发给对应的物理设备(InputDevice)。

  3. InputDevice (分发):将事件广播给关联的多个 InputMapper(如 TouchInputMapper 处理触控,KeyboardInputMapper 处理按键)。

  4. TouchInputMapper (变换):核心逻辑层。它通过 process() 收集 RawEvent,并在 SYN_REPORT 到达时调用 processRawTouches(),进行坐标归一化、矩阵变换及手势识别。

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui