InputReader线程获取输入事件-Android12

InputReader线程获取输入事件-Android12

android12-release

InputManagerService启动-Android12


在这里插入图片描述

1、InputReader线程启动轮询threadLoop


1.1、threadLoop

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;
}
frameworks\native\services\inputflinger\InputThread.cpp

在这里插入图片描述

1.2 InputReader::loopOnce()

  • mEventHub->getEvents 从EventHub读取事件
  • processEventsLocked 处理事件
  • mQueuedListener->flush() 发送Event到InputDispatcher
    InputReader::loopOnce

2、EventHub::getEvents读取事件/dev/input


frameworks\native\services\inputflinger\reader\EventHub.cpp
  • scanDevicesLocked() 扫描/dev/input节点设备
  • read 从设备不断读取事件 input_event 信息到 readBuffer
  • RawEvent* event 将 input_event 信息, 封装成 RawEvent
  • pollResult = epoll_wait 等待input事件
  • event - buffer 返回我们读取的事件数

EventHub 采用 epoll 机制监听 /dev/input 下的设备节点,将 input_event + deviceId 转换成 RawEvent 结构体,如下:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        // ... ...
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }
        // ... ...
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            // ... ...
            // This must be an input event
            if (eventItem.events & EPOLLIN) {
                int32_t readSize =
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // ... ...
                } else if (readSize < 0) {
                    // ... ...
                } else if ((readSize % sizeof(struct input_event)) != 0) {
                    // ... ...
                } else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        event->when = processEventTimestamp(iev);
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
                        // 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 {
                // ... ...
            }
        }
        // ... ...
        mLock.unlock(); // release lock before poll

        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        mLock.lock(); // reacquire lock after poll
        // ... ...
        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);
        }
    }

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

2.1、设备扫描scanDevicesLocked

/dev/input/目录下所有的设备节点
static const char* DEVICE_PATH = "/dev/input";
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";

void EventHub::scanDevicesLocked() {
    status_t result = scanDirLocked(DEVICE_PATH);
    if (result < 0) {
        ALOGE("scan dir failed for %s", DEVICE_PATH);
    }
    if (isV4lScanningEnabled()) {
        result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
        if (result != OK) {
            ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
        }
    }
    if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
        createVirtualKeyboardLocked();
    }
}

2.2、RawEvent 结构体

frameworks\native\services\inputflinger\reader\include\EventHub.h
struct RawEvent {
    nsecs_t when;       //事件发生的时间点
    int32_t deviceId;   //产生事件的设备Id
    int32_t type;       //事件类型
    int32_t code;       //事件 code:input-event-codes.h
    int32_t value;      //事件值 value
};

3、事件处理processEventsLocked


在这里插入图片描述

3.1、addDeviceLocked 添加设备

frameworks\native\services\inputflinger\reader\InputDevice.cpp

在这里插入图片描述
最终调用InputDevice::addEventHubDevice;Input设备类型有很多种,其中常见的设备 InputMapper:

  • 键盘类设备:KeyboardInputMapper
  • 触摸屏设备:MultiTouchInputMapperSingleTouchInputMapper
  • 鼠标类设备:CursorInputMapper

3.2、事件处理processEventsForDeviceLocked

frameworks\native\services\inputflinger\reader\include\InputDevice.h
frameworks\native\services\inputflinger\reader\InputDevice.cpp

在这里插入图片描述
最终调用InputDevice::process,再交由对应的InputMapper处理,就是上面3.1中提到的,如KeyboardInputMapper
在这里插入图片描述

4、mQueuedListener->flush()

frameworks\native\services\inputflinger\include\InputListener.h
frameworks\native\services\inputflinger\InputListener.cpp

在这里插入图片描述
这个sp<InputListenerInterface> mInnerListener是啥玩意呢,一下想不到,回头看到InputReader初始化就是InputDispatcher
在这里插入图片描述

4.1、NotifyArgs对用多种

NotifyArgs在InputMapper初始化,对用不同的输入,如KeyboardInputMapper
在这里插入图片描述

frameworks\native\services\inputflinger\include\InputListener.h
frameworks\native\services\inputflinger\InputListener.cpp
  • NotifyKeyArgs
  • NotifyMotionArgs
  • NotifySwitchArgs
  • NotifyDeviceResetArgs
    在这里插入图片描述

4.2、NotifyArgs.notify通知到InputDispatcher

mLooper->wake()唤醒InputDispatcher中InputThread线程

frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp

  • InputDispatcher::notifyKey
  • InputDispatcher::notifyMotion
  • InputDispatcher::notifySwitch
  • InputDispatcher::notifyDeviceReset
    在这里插入图片描述

时序图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值