Android R input (二) 之 InputReader 工作流程

文章托管在gitee上 Android Notes , 同步csdn

InputReader 的创建

如前所述,InputReader是在 InputManager 构造方法中通过工厂方法createInputReader创建,在此方法中,还创建了EventHub作为构造参数. 此处的policy即NativeInputManager对象,listener的值实际上是mDispatcher的封装.

/// @frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
                                           const sp<InputListenerInterface>& listener) {
    // 直接new了对象, 注意参数                                         
    return new InputReader(std::make_unique<EventHub>(), policy, listener);
}

InputReader 构造

/// @frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         const sp<InputListenerInterface>& listener)
      : mContext(this),  // 注意到mContext的值即InputReader this指针
        mEventHub(eventHub), // 初始化eventHub
        mPolicy(policy),   // 初始化策略
        mGlobalMetaState(0),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN), // #define LLONG_MIN  (-__LONG_LONG_MAX__-1LL)
        mNextTimeout(LLONG_MAX),               // #define LLONG_MAX  __LONG_LONG_MAX__
        mConfigurationChangesToRefresh(0) {
    //queues up and defers dispatch of decoded events until flushed.
    // 创建 QueuedInputListener
    mQueuedListener = new QueuedInputListener(listener); // 间接持有InputDispatcher的引用

    { // acquire lock
        AutoMutex _l(mLock);

        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

QueuedInputListener 构造

这个类是辅助派发事件的. 当有事件时先入QueuedInputListener的mArgsQueue队列,之后调用QueuedInputListener的flush方法时才进行真正的派发.

QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
        mInnerListener(innerListener) {
}

注意参数是 InputListenerInterface 指针, 它实际上指向的是InputClassifier对象, 而InputClassifier是对InputDispatcher的封装.因此,事件实际上是派发给了InputDispatcher.

InputListenerInterface 定义

下面看一下InputListenerInterface定义:

/// @frameworks/native/services/inputflinger/include/InputListener.h
/*
 * The interface used by the InputReader to notify the InputListener about input events.
 */
class InputListenerInterface : public virtual RefBase {
protected:
    InputListenerInterface() { }
    virtual ~InputListenerInterface() { }

public:
    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
    virtual void notifyKey(const NotifyKeyArgs* args) = 0;
    virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
    virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
};

它的实现者有:

  • InputClassifierInterface , 此接口的实现类是InputClassifier
/**
 * Base interface for an InputListener stage.
 * Provides classification to events.
 */
class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
  • InputDispatcherInterface , 此接口的实现类是 InputDispatcher
/* Notifies the system about input events generated by the input reader.
 * The dispatcher is expected to be mostly asynchronous. */
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {

而QueuedInputListener同样实现了InputListenerInterface,并且持有InputClassifier, 此处使用的是装饰者模式. 因此派发流程是 QueuedInputListener -> InputClassifier -> InputDispatcher

这个流程我画了一张图,如下:
在这里插入图片描述

创建 EventHub

EventHub 是原始input的处理类,功能包括处理input设备的添加移除,获取input事件等

class EventHub : public EventHubInterface {
public:
    EventHub();
...
}

EventHubInterface

它继承自EventHubInterface,这个接口定义了input处理的相关方法,如 getEvents 方法.

/// @frameworks/native/services/inputflinger/reader/include/EventHub.h

/*
 * Grand Central Station for events.
 *
 * The event hub aggregates input events received across all known input
 * devices on the system, including devices that may be emulated by the simulator
 * environment.  In addition, the event hub generates fake input events to indicate
 * when devices are added or removed.
 *
 * The event hub provides a stream of input events (via the getEvent function).
 * It also supports querying the current actual state of input devices such as identifying
 * which keys are currently down.  Finally, the event hub keeps track of the capabilities of
 * individual input devices, such as their class and the set of key codes that they support.
 */
class EventHubInterface {
public:
    EventHubInterface() {}
    virtual ~EventHubInterface() {}

    // Synthetic raw event type codes produced when devices are added or removed.
    enum {
        // Sent when a device is added.
        DEVICE_ADDED = 0x10000000,
        // Sent when a device is removed.
        DEVICE_REMOVED = 0x20000000,
        // Sent when all added/removed devices from the most recent scan have been reported.
        // This event is always sent at least once.
        FINISHED_DEVICE_SCAN = 0x30000000,

        FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
    };

    virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;

    virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;

    ...
    /*
     * Wait for events to become available and returns them.
     * After returning, the EventHub holds onto a wake lock until the next call to getEvent.
     * This ensures that the device will not go to sleep while the event is being processed.
     * If the device needs to remain awake longer than that, then the caller is responsible
     * for taking care of it (say, by poking the power manager user activity timer).
     *
     * The timeout is advisory only.  If the device is asleep, it will not wake just to
     * service the timeout.
     *
     * Returns the number of events obtained, or 0 if the timeout expired.
     */
    virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
    virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0;
...
}

EventHub 构造

这个构造方法的工作如下:

  • 初始化一些成员变量,赋值默认值
  • 确保能block suspend, 确保事件能被正常处理
  • 创建 epoll , 记录mEpollFd
  • 初始化inotify, 并将/dev/input 目录下添加IN_DELETE | IN_CREATE监听
  • 如果ro.input.video_enabled为true,即需要扫描V4L devices, 则添加VIDEO_DEVICE_PATH到inotify监听
  • 添加mINotifyFd到epoll监听列表
  • 创建用于wake的管道, 并将读端添加到epoll监听列表
EventHub::EventHub(void)
      : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
        mNextDeviceId(1),
        mControllerNumbers(),
        mOpeningDevices(nullptr),
        mClosingDevices(nullptr),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false),
        mNeedToScanDevices(true),  // 此处默认为true,需要扫描所有设备
        mPendingEventCount(0),
        mPendingEventIndex(0),
        mPendingINotify(false) {
    ensureProcessCanBlockSuspend(); // 确保能block suspend
    // 创建 epoll
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
    // 初始化 inotify , 用于监听文件系统的变化
    mINotifyFd = inotify_init();
    // 添加监听DEVICE_PATH = "/dev/input" 下的创建与删除,
    // 当有变化时将相关改变写入到mINotifyFd对应的文件,通过read读取相关notify
    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
                        strerror(errno));
    if (isV4lScanningEnabled()) {
        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
                            VIDEO_DEVICE_PATH, strerror(errno));
    } else {
        mVideoWd = -1;
        ALOGI("Video device scanning disabled");
    }

    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = mINotifyFd;
    // 将mINotifyFd添加到 epoll监听, 当有设备节点增删时,会因mINotifyFd有新数据的到来而触发epoll相关事件
    // 通过相关epoll事件,可知有相关设备改变,读取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];
    // 创建wake 管道 , 主要用于唤醒 EventHub::getEvents, 可能阻塞在read
    result = pipe(wakeFds);
    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); // 设置读 non-blocking
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
                        errno);

    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); // 设置写 non-blocking
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
                        errno);

    eventItem.data.fd = mWakeReadPipeFd;
    // 将mWakeReadPipeFd 添加到 epoll 监听. 当调用wake()向mWakeWritePipeFd写入数据,将导致读端收到数据而被唤醒
    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);
}

InputReader::start

IMS#start方法会调用nativeStart, 之后在native会进一步调用InputReader::start. 在这个方法中,会创建其InputThread任务线程. 如前所述,InputThread构造方法内部会创建一个线程,并启动此线程.

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    // 创建InputThread, 它是一个线程包装类, 内部会创建线程并启动
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

注意到创建InputThread时有三个参数,第一个是线程的名称,第二个是线程执行threadLoop时回调的函数,此处写法是C++11的lambda表达式,第三个参数是线程销毁前调用来唤醒线程的回调.

InputReader::loopOnce

InputReader线程执行会不断的调用 loopOnce 方法,此方法的工作大致如下:

  • 如果配置改变,则更新配置. 否则重新计算timeoutMillis
  • 调用EventHub::getEvents获取事件,此处可能会阻塞到事件到来或者超时返回. 获取到的事件放在mEventBuffer, 一次最大可以读取EVENT_BUFFER_SIZE=256 件.
  • 当获取到事件,则调用 processEventsLocked 来处理事件. 相关事件会通过notifyXXX添加到QueuedInputListener的mArgsQueue中
  • 通过mGeneration判断设备变更. 当有变化时,通过getInputDevicesLocked来获取设备信息,然后通过mPolicy->notifyInputDevicesChanged通知设备变化,此处的mPolicy实际上是NativeInputManager对象,它最终会回调IMS的notifyInputDevicesChanged通知设备改变
  • 最后mQueuedListener->flush 将mArgsQueue中的所有相关事件投递到InputDispatcher的队列中
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) { // 执行配置改变
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0; // 不需等待
            refreshConfigurationLocked(changes); // 更新配置
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // 获取系统时间
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); // 计算超时时间
        }
    } // release lock

    // 从EventHub 获取事件.  event queue 定义如下
    // static const int EVENT_BUFFER_SIZE = 256;
    // RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        // 通知reader还处于活跃状态. InputReader::monitor方法检测reader线程是否发生死锁
        mReaderIsAliveCondition.broadcast();

        if (count) { // 大于0则有事件需要处理
            processEventsLocked(mEventBuffer, count); // 处理events
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) { // now比mNextTimeout大,则此timeout过期
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;  // timeout过期则设置mNextTimeout为最大LLONG_MAX
                timeoutExpiredLocked(now); // 通知 devices timeoutExpired
            }
        }

        if (oldGeneration != mGeneration) { // 有设备改变
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) { // 通知设备改变
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // 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(); // 执行分发事件到listener
}

RawEvent

RawEvent 是EventHub中对事件的描述. 具体可以分为两类:

  • 设备改变事件, 如添加/移除设备的事件
  • 原始事件, 比如触摸屏幕或者按物理按键触发的事件
/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
 * A raw event as retrieved from the EventHub.
 */
struct RawEvent {
    nsecs_t when;  // 事件发生时的时间戳
    int32_t deviceId;  //  产生事件的设备id
    int32_t type;  // 事件类型
    int32_t code;   // 事件码值
    int32_t value;  // 事件值
};

对于事件类型,也做了相关定义. 对于设备相关事件,定义了特定的值, 如添加设备的事件类型是DEVICE_ADDED

/// @frameworks/native/services/inputflinger/reader/include/EventHub.h
class EventHubInterface {...
// Synthetic raw event type codes produced when devices are added or removed.
enum {
    // Sent when a device is added.
    DEVICE_ADDED = 0x10000000,
    // Sent when a device is removed.
    DEVICE_REMOVED = 0x20000000,
    // Sent when all added/removed devices from the most recent scan have been reported.
    // This event is always sent at least once.
    FINISHED_DEVICE_SCAN = 0x30000000,

    FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};

超时计算

下面看一下如何计算系统时间与超时延时

/// @system/core/libutils/Timers.cpp
// host linux support requires Linux 2.6.39+
#if defined(__linux__)
// 获取系统时间
nsecs_t systemTime(int clock)
{
    static const clockid_t clocks[] = {
            CLOCK_REALTIME,
            CLOCK_MONOTONIC,
            CLOCK_PROCESS_CPUTIME_ID,
            CLOCK_THREAD_CPUTIME_ID,
            CLOCK_BOOTTIME
    };
    struct timespec t;
    t.tv_sec = t.tv_nsec = 0;
    clock_gettime(clocks[clock], &t);  // 获取时间
    return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; // 转换成纳秒
}
#else ...

// 获取延迟时间
int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
{
    nsecs_t timeoutDelayMillis;
    if (timeoutTime > referenceTime) { // 大于参考时间,说明需要延时,则计算差值
        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { // delay极大
            timeoutDelayMillis = -1;  // 则设置为-1, 表示无限等待
        } else {
            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; // 转换成ms,且确保有至少有1ms
        }
    } else { // 否则, 超时延时为0
        timeoutDelayMillis = 0;
    }
    return (int)timeoutDelayMillis;
}

EventHub#getEvents

这个函数是处理原始的输入事件,如设备添加移除,输入事件等. 这个函数的工作大致如下:

  • 循环处理,直到break
  • 处理devices变化,及合成相关的设备事件, 如重新打开/添加/关闭设备, 某些情况会break
  • 处理pending 的events , 如有新事件,则会break
    • 处理 mINotifyFd , 有设备状态变化,调用readNotifyLocked处理处理变更
    • 处理 mWakeReadPipeFd 操作, 通常是wake()操作
    • 处理 input 事件
  • epoll_wait 等待新事件的到来
  • 有新事件到来,更新mPendingEventCount,进行下一轮的处理

以上有新事件的地方,会转换为RawEvent, 然后返回给InputReader进一步处理

/// @frameworks/native/services/inputflinger/reader/EventHub.cpp
//   bufferSize : EVENT_BUFFER_SIZE = 256;
//   buffer :     RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
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);

        // Reopen input devices if needed.
        // 调用 requestReopenDevices() 会导致 mNeedToReopenDevices = true
        if (mNeedToReopenDevices) { // 处理需要重新打开设备的情况
            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.
        while (mClosingDevices) { // 处理移除设备的事件
            Device* device = mClosingDevices;
            ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
            mClosingDevices = device->next; // 指向下一个device,在下一次循环继续处理。可以发现多个事件是串行处理的
            event->when = now;
            event->deviceId = (device->id == mBuiltInKeyboardId)
                    ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
                    : device->id;
            event->type = DEVICE_REMOVED; // 事件类型是 DEVICE_REMOVED
            event += 1;  // 移动buffer指针到event的下一个RawEvent地址
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) { // 每增加一个event,则capacity-1, capacity为0时结束循环
                break;
            }
        }

        // mNeedToScanDevices 默认为true
        if (mNeedToScanDevices) { // 处理需要扫描设备的情况
            mNeedToScanDevices = false;
            scanDevicesLocked();  // 扫描设备
            mNeedToSendFinishedDeviceScan = true;
        }

        while (mOpeningDevices != nullptr) { // 处理新设备添加事件
            Device* device = mOpeningDevices;
            ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED; // 事件类型是 DEVICE_ADDED
            event += 1;
            mNeedToSendFinishedDeviceScan = true; // 设置需要结束扫描
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) { // 添加设备扫描完成的事件
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;  // 事件类型是 FINISHED_DEVICE_SCAN
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) { // 处理 pending 事件
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.fd == mINotifyFd) { // 处理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) { // 处理mWakeReadPipeFd, 通常是调用wake()的原因
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    awoken = true;  // 当收到唤醒的消息,会导致getEvents 从阻塞状态返回
                    char buffer[16];
                    ssize_t nRead;
                    do {
                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                          eventItem.events);
                }
                continue;
            }

            Device* device = getDeviceByFdLocked(eventItem.data.fd); // 获取fd对应的device
            if (!device) { // 判断fd 对应的设备是否存在
                ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
                      eventItem.data.fd);
                ALOG_ASSERT(!DEBUG);
                continue;
            }
            // 处理 videoDevice
            if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
                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) {  // 开始处理输入事件
                // 使用read函数从fd读取事件,存储到readBuffer.  读取capacity个input_event
                int32_t readSize =
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
                // 有事件通知但未读取到事件,设备可能INotify通知之前在被移除了        
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // Device was removed before INotify noticed.
                    ALOGW("could not get event, removed? (fd: %d size: %" PRId32
                          " bufferSize: %zu capacity: %zu errno: %d)\n",
                          device->fd, readSize, bufferSize, capacity, 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) { // 不是input_event结构体大小的整数倍
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else { // 下面处理纯粹的输入事件, 将 input_event 转换为 RawEvent
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event); // 计算input_event的个数
                    for (size_t i = 0; i < count; i++) { // 将 input_event 转换成 RawEvent
                        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) { // 为0,说明上面读取了capacity个input_event,
                        // 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) { // 处理 EPOLLHUP
                ALOGI("Removing device %s due to epoll hang-up event.",
                      device->identifier.name.c_str());
                deviceChanged = true;
                closeDeviceLocked(device);
            } else {  // 其他未知 events
                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) { // 在读取完所有屏pending事件后才通知设备改变
            mPendingINotify = false;
            readNotifyLocked();
            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 (event != buffer || awoken) { // 已经读取到了事件或是被唤醒, 则退出循环
          // 为什么此处awoken为true时,需要break? 因为当调用wake()函数时向管道写端写入数据,会导致读端有新数据到来,
          // 而导致epoll_wait从等待中返回,此时有新事件发生,在下一轮循环中读取mWakeReadPipeFd的事件,
          // 从而给awoken赋值为true. 此处应该break从而使getEvents函数返回,这正是wake()的目的,
          // 否则继续将陷入epoll_wait等待,不符合预期.
            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
        // 到此处说明pending的事件已经处理完毕,需要获取新的事件. epoll_wait 会等待新事件到来或者到了超时事件返回
        // 等待事件的到来, 读取的 epoll_event 事件被存储在mPendingEventItems数组,大小是EPOLL_MAX_EVENTS = 16
        // 即每次最多读取16个 epoll_event 事件, 这些事件包含设备节点的增删,设备节点有新输入事件可读等
        // timeoutMillis 是等待的超时时间
        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) { // 出错
            // 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; // 与数组初始位置的偏移,计算RawEvent的个数
}

在EventHub的构造函数中,给mNeedToScanDevices赋值是true,因此第一次调用EventHub::getEvents时会首先扫描所有设备,具体的实现函数是scanDevicesLocked

EventHub::scanDevicesLocked
void EventHub::scanDevicesLocked() {
    status_t result = scanDirLocked(DEVICE_PATH); // 扫描 DEVICE_PATH  /dev/input
    if (result < 0) {
        ALOGE("scan dir failed for %s", DEVICE_PATH);
    }
    if (isV4lScanningEnabled()) { // 支持 v4l ,则扫描 VIDEO_DEVICE_PATH
        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();
    }
}

scanDirLocked
这个函数扫描设备目录(如 /dev/input)下的所有节点, 分别对其执行openDeviceLocked完成打开设备操作. 如下是以 dirname 是 /dev/input 为例:

status_t EventHub::scanDirLocked(const char* dirname) {
    char devname[PATH_MAX];
    char* filename;
    DIR* dir;
    struct dirent* de;
    dir = opendir(dirname);  // 打开  /dev/input
    if (dir == nullptr) return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';  // /dev/input/
    while ((de = readdir(dir))) { // 读取dir,直到返回 NULL
        // 跳过 . 和 .. 目录
        if (de->d_name[0] == '.' &&
            (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name); // 拼接 /dev/input/ 和 d_name , 如 /dev/input/event0
        openDeviceLocked(devname); // 打开设备
    }
    closedir(dir);
    return 0;
}
EventHub::openDeviceLocked

此函数是用来完成设备的打开操作,此方法的工作大致如下:

  • 打开指定设备节点
  • 获取设备信息, 创建 Device
  • 设备类型, keyMap 处理等
  • 注册 Device 的 epoll 事件监听
  • 保存device到mDevices, 并添加device到mOpeningDevices列表以通知设备添加
status_t EventHub::openDeviceLocked(const char* devicePath) {
    char buffer[80];

    ALOGV("Opening device: %s", devicePath);
    // 打开此设备
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
    if (fd < 0) {
        ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
        return -1;
    }
    // 获取设备信息
    InputDeviceIdentifier identifier;

    // Get device name.
    // Check to see if the device is on our excluded list  在此列表会关闭设备
    // Get device driver version.
    // Get device identifier.
    // Get device physical location.
    // Get device unique id.
    // Fill in the descriptor.
    assignDescriptorLocked(identifier);

    // Allocate device.  (The device object takes ownership of the fd at this point.)
    int32_t deviceId = mNextDeviceId++;
    Device* device = new Device(fd, deviceId, devicePath, identifier);  // 创建Device
    ...

    // Load the configuration file for the device.
    loadConfigurationLocked(device);  // 加载
    ... // 判断类型,加载key map 等

    // 添加到 epoll 监听
    if (registerDeviceForEpollLocked(device) != OK) {
        delete device;
        return -1;
    }

    configureFd(device); // 配置kernel key repeat和monotonic clock

    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
          "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
          deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
          device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
          device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));

    addDeviceLocked(device); // 通知添加设备
    return OK;
}

接下来先看如何给device 注册epoll事件

EventHub::registerDeviceForEpollLocked
status_t EventHub::registerDeviceForEpollLocked(Device* device) {
    if (device == nullptr) {
        if (DEBUG) {
            LOG_ALWAYS_FATAL("Cannot call registerDeviceForEpollLocked with null Device");
        }
        return BAD_VALUE;
    }
    status_t result = registerFdForEpoll(device->fd); // 将此设备的fd注册到epoll
    if (result != OK) {
        ALOGE("Could not add input device fd to epoll for device %" PRId32, device->id);
        return result;
    }
    if (device->videoDevice) {
        registerVideoDeviceForEpollLocked(*device->videoDevice);
    }
    return result;
}

接着调用 registerFdForEpoll , 将此设备的fd注册到epoll,当有新事件时,epoll_wait会返回相关事件信息.

status_t EventHub::registerFdForEpoll(int fd) {
    // TODO(b/121395353) - consider adding EPOLLRDHUP
    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP;
    eventItem.data.fd = fd;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { // 注册fd到epoll
        ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
        return -errno;
    }
    return OK;
}
EventHub::addDeviceLocked

这个函数完成打开设备的收尾工作.保存device到mDevices,并添加device到mOpeningDevices列表. 在getEvents中,当扫描完设备后,会处理mOpeningDevices列表生成相关设备添加的事件.

void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device); // 保存device到mDevices (KeyedVector<int32_t, Device*>)
    device->next = mOpeningDevices;  // 添加device到mOpeningDevices列表
    mOpeningDevices = device;
}
EventHub::readNotifyLocked

当epoll监听到mINotifyFd中有可读事件时,说明设备发生变化. 之后再合适的时机调用readNotifyLocked处理变化

status_t EventHub::readNotifyLocked() {
    int res;
    char event_buf[512];
    int event_size;
    int event_pos = 0;
    struct inotify_event* event;

    ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd);
    res = read(mINotifyFd, event_buf, sizeof(event_buf));
    if (res < (int)sizeof(*event)) {
        if (errno == EINTR) return 0;
        ALOGW("could not get event, %s\n", strerror(errno));
        return -1;
    }

    while (res >= (int)sizeof(*event)) {
        event = (struct inotify_event*)(event_buf + event_pos);
        if (event->len) {
            if (event->wd == mInputWd) { // 说明DEVICE_PATH目录下有变化
                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
                if (event->mask & IN_CREATE) {  // 有新设备节点创建
                    openDeviceLocked(filename.c_str());  //打开设备
                } else { // 否则关闭设备
                    ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
                    closeDeviceByPathLocked(filename.c_str());
                }
            } else if (event->wd == mVideoWd) {
                if (isV4lTouchNode(event->name)) {
                    std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
                    if (event->mask & IN_CREATE) {
                        openVideoDeviceLocked(filename);
                    } else {
                        ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
                        closeVideoDeviceByPathLocked(filename);
                    }
                }
            } else {
                LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
            }
        }
        event_size = sizeof(*event) + event->len;
        res -= event_size;
        event_pos += event_size;
    }
    return 0;
}

InputReader::processEventsLocked

再次回到InputReader::loopOnce, 当通过mEventHub->getEvents获取到相关事件,即count>0时则会调用processEventsLocked处理RawEvent

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
         // 处理type小于 FIRST_SYNTHETIC_EVENT=DEVICE_ADDED , 即处理原始事件,非合成的事件
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) { // 统计batchSize
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
                    rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize); // 处理原始 RawEvent
        } 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;
    }
}

下面先看添加设备的逻辑.

InputReader::addDeviceLocked

此处的mDevices与EventHub中的不同, 它的类型是std::unordered_map<int32_t /eventHubId/, std::shared_ptr>

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    if (mDevices.find(eventHubId) != mDevices.end()) { // 查找是否添加过
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }

    // 通过 device id 获取设备的 InputDeviceIdentifier
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    // 创建 InputDevice
    std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
    device->configure(when, &mConfig, 0); // 配置device
    device->reset(when);

    if (device->isIgnored()) {
        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
              "(ignored non-input device)",
              device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
    } else {
        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
              device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
              device->getSources());
    }

    mDevices.emplace(eventHubId, device); // 添加到map
    bumpGenerationLocked();  // 更新 mGeneration

    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        notifyExternalStylusPresenceChanged();
    }
}

InputReader::createDeviceLocked
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        int32_t eventHubId, const InputDeviceIdentifier& identifier) {
    // 查找是否存在与identifier.descriptor相同的键值对
    auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
        return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
                devicePair.second->getDescriptor() == identifier.descriptor;
    });

    std::shared_ptr<InputDevice> device;
    if (deviceIt != mDevices.end()) { // 存在则复用
        device = deviceIt->second;
    } else { // 否则创建新的
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    device->addEventHubDevice(eventHubId); // 添加EventHubDevice,填充InputMapper
    return device;
}

InputDevice::addEventHubDevice

此方法向InputDevice的mDevices添加设备信息, 并且根据设备类型初始化 InputMapper. populateMappers 为true时需要添加对应的InputMapper.
InputMapper(输入映射器)将原始输入事件转换为Android事件数据。
单个输入设备可以具有多个关联的输入映射器,以便解释不同类别的事件

/// @frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers /* 默认为true */) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        return;
    }
    // 创建 InputDeviceContext 对象
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    uint32_t classes = contextPtr->getDeviceClasses();
    std::vector<std::unique_ptr<InputMapper>> mappers;

    // Check if we should skip population
    if (!populateMappers) { // 是否需要添加InputMapper
        mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
        return;
    }
    // 下面针对不同的class,添加对应的 InputMapper
    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
    }

    // Scroll wheel-like devices.
    if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
        mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
    }

    // Vibrator-like devices.
    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
        mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
    }

    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { // 键盘
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { // 字符键
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes & INPUT_DEVICE_CLASS_DPAD) { // 方向键
        keyboardSource |= AINPUT_SOURCE_DPAD;
    }
    if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { // 游戏键盘
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    }

    if (keyboardSource != 0) { // 可以发现, 上面4种类别对应的都是KeyboardInputMapper
        mappers.push_back(
                std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
    }

    // Cursor-like devices.
    if (classes & INPUT_DEVICE_CLASS_CURSOR) { // 如鼠标设备
        mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
    }

    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { // 多点触摸
        mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { // 单点
        mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
    }

    // Joystick-like devices.
    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
        mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
    }

    // External stylus-like devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
    }

    // insert the context into the devices set
    // eventHubId为key, make_pair创建键
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}

上面的的mDevices是在InputDevice.h中定义的:

// map from eventHubId to device context and mappers
using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
// 等价于 unordered_map< int32_t, std::pair<InputDeviceContext*, std::vector<InputMapper*>> >
std::unordered_map<int32_t, DevicePair> mDevices;
设备类别定义

一个输入设备可能对应多个类别

///  @frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
 * Input device classes.
 */
enum {
    /* The input device is a keyboard or has buttons. */
    INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,

    /* The input device is an alpha-numeric keyboard (not just a dial pad). */
    INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,

    /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
    INPUT_DEVICE_CLASS_TOUCH = 0x00000004,

    /* The input device is a cursor device such as a trackball or mouse. */
    INPUT_DEVICE_CLASS_CURSOR = 0x00000008,

    /* The input device is a multi-touch touchscreen. */
    INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,

    /* The input device is a directional pad (implies keyboard, has DPAD keys). */
    INPUT_DEVICE_CLASS_DPAD = 0x00000020,

    /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
    INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,

    /* The input device has switches. */
    INPUT_DEVICE_CLASS_SWITCH = 0x00000080,

    /* The input device is a joystick (implies gamepad, has joystick absolute axes). */
    INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,

    /* The input device has a vibrator (supports FF_RUMBLE). */
    INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,

    /* The input device has a microphone. */
    INPUT_DEVICE_CLASS_MIC = 0x00000400,

    /* The input device is an external stylus (has data we want to fuse with touch data). */
    INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,

    /* The input device has a rotary encoder */
    INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000,

    /* The input device is virtual (not a real device, not part of UI configuration). */
    INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,

    /* The input device is external (not built-in). */
    INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
};

InputMapper

这个类是原始输入事件加工处理的地方

/* An input mapper transforms raw input events into cooked event data.
 * A single input device can have multiple associated input mappers in order to interpret
 * different classes of events.
 *
 * InputMapper lifecycle:
 * - create
 * - configure with 0 changes
 * - reset
 * - process, process, process (may occasionally reconfigure with non-zero changes or reset)
 * - reset
 * - destroy
 */
class InputMapper {
public:
    explicit InputMapper(InputDeviceContext& deviceContext);
    virtual void process(const RawEvent* rawEvent) = 0;
    ...
}
InputReader::bumpGenerationLocked

在getEvents中,判断mGeneration改变来确定inputDevice的状态改变

int32_t InputReader::bumpGenerationLocked() {
    return ++mGeneration;
}

当添加输入设备后,就可以等待相关事件的到来. 使用 processEventsForDeviceLocked 方法来处理纯粹的输入事件,如触摸屏幕或按power键.

InputReader::processEventsForDeviceLocked

这个函数是真正处理输入事件的地方

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
                                               size_t count) {
    // 先找到产生事件的device                                             
    auto deviceIt = mDevices.find(eventHubId);
    if (deviceIt == mDevices.end()) {
        ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
        return;
    }

    std::shared_ptr<InputDevice>& device = deviceIt->second;
    if (device->isIgnored()) { // 如果device是ignored, 不需处理
        // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }
    // 接下来device进行处理
    device->process(rawEvents, count);
}
InputDevice::process
/// @frameworks/native/services/inputflinger/reader/InputDevice.cpp
void 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.
    for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
        if (mDropUntilNextSync) { // 处理drop事件
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
                ALOGD("Recovered from input event buffer overrun.");
            } else {
                ALOGD("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;
            reset(rawEvent->when);
        } else {
            for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
                mapper.process(rawEvent);  // 交给具体的InputMapper处理
            });
        }
        --count;
    }
}

for_each_mapper_in_subdevice 方法是遍历取出 InputMapper, 然后执行相关方法. 结合上面的代码, 实际的操作就是遍历所有InputMapper并执行其process方法.

// run a function against every mapper on a specific subdevice
inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
                                         std::function<void(InputMapper&)> f) {
    auto deviceIt = mDevices.find(eventHubDevice);
    if (deviceIt != mDevices.end()) {
        auto& devicePair = deviceIt->second;
        auto& mappers = devicePair.second;
        for (auto& mapperPtr : mappers) {
            f(*mapperPtr);
        }
    }
}
KeyboardInputMapper#process

对于键盘设备而言, 对应的 InputMapper 是KeyboardInputMapper, 它的process方法如下:

/// @frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
        case EV_KEY: {  // key 事件
            int32_t scanCode = rawEvent->code; // 键盘扫描码, 与Android的键值有一个映射关系
            int32_t usageCode = mCurrentHidUsage;
            mCurrentHidUsage = 0;

            if (isKeyboardOrGamepadKey(scanCode)) {
                // 按下value值是1
                processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);  // 处理 key 事件
            }
            break;
        }
        ...
    }
}

KeyboardInputMapper::processKey
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;

    // 将scanCode与Android中的keyCode做一个映射. 比如POWER KEY的扫描码是116 , 而在Android的KeyEvent中的定义是26
    if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
                                  &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }

    if (down) { // 按下事件
        // Rotate key codes according to orientation if needed.
        if (mParameters.orientationAware) {
            keyCode = rotateKeyCode(keyCode, getOrientation());
        }

        // Add key down.
        ssize_t keyDownIndex = findKeyDown(scanCode); // 根据 scanCode 查找是否已经存储过
        if (keyDownIndex >= 0) { // 查到,说明是一个键的重复事件,确保keyCode一致
            // key repeat, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns[keyDownIndex].keyCode;
        } else { // 否则是初始Down
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
                getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
                return;
            }
            if (policyFlags & POLICY_FLAG_GESTURE) {
                getDeviceContext().cancelTouch(when);
            }

            KeyDown keyDown;
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
            mKeyDowns.push_back(keyDown); // 存储
        }

        mDownTime = when;
    } else {
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) { // 查到, 则此时发生的是up事件. 确保keyCode与之前一致, 键盘方向旋转可能导致键值变化
            // key up, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns[keyDownIndex].keyCode;
            mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
        } else { // 之前没有发生Down事件,则直接返回
            // 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;
        }
    }

    if (updateMetaStateIfNeeded(keyCode, down)) { // 更新metaState, 其描述了功能键的按下状态,如Ctrl按下
        // 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;
    }

    nsecs_t downTime = mDownTime;

    // Key down on external an 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.
    // TODO: Use the input device configuration to control this behavior more finely.
    if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
        !isMediaKey(keyCode)) {  // 是否要唤醒
        policyFlags |= POLICY_FLAG_WAKE;
    }

    if (mParameters.handlesKeyRepeat) { // 处理 key repeat
        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
    }

    // 封装key事件到NotifyKeyArgs
    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
                       policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                       AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener()->notifyKey(&args); // 此处实际调用了QueuedInputListener的notifyKey, 将args添加到它的队列中.
}
QueuedInputListener::notifyKey
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
    traceEvent(__func__, args->id);
    mArgsQueue.push_back(new NotifyKeyArgs(*args));  //将key事件信息添加到mArgsQueue
}

再次回到 InputReader::loopOnce , 当通过 processEventsForDeviceLocked 对原始事件进行加工处理后, 会将事件信息都缓存到 QueuedInputListener 的 mArgsQueue, 在方法最后通过mQueuedListener->flush()去真正的将事件投递到InputDispatcher,并清空队列.

QueuedInputListener#flush

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener); // 调用args的notify方法
        delete args;
    }
    mArgsQueue.clear();
}

此处的mInnerListener是创建QueuedInputListener时传入的listener,即是创建InputReader时传入的InputClassifier对象.
对于key事件,调用的是NotifyKeyArgs::notify

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyKey(this);
}

根据之前的派发流程分析(QueuedInputListener -> InputClassifier -> InputDispatcher), 此处会调用InputClassifier的notifyKey方法

InputClassifier#notifyKey

对于key事件的处理,在InputClassifie中的处理是直通的, 它的mListener实际上是InputDispatcher的指针

void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
    // pass through
    mListener->notifyKey(args);
}

InputDispatcher#notifyKey

通过上面的分析来看,此处的调用还在reader线程中. 当将事件投递到InputDispatcher后,再唤醒其处理事件,才将事件处理线程切换到dispatcher线程.

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
    ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
          "policyFlags=0x%x, action=0x%x, "
          "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
          args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
          args->action, args->flags, args->keyCode, args->scanCode, args->metaState,
          args->downTime);
#endif
    if (!validateKeyEvent(args->action)) { // 验证有效性
        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; // 从reader线程投递的事件自动trusted

    int32_t keyCode = args->keyCode;
    accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);

    // 将NotifyKeyArgs内容填充到KeyEvent
    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);

    android::base::Timer t;
    // 在事件入队之前做一些拦截操作,比如禁止传递给user, 此处最终会通过PhoneWindowManager来处理
    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
              std::to_string(t.duration().count()).c_str());
    }

    bool needWake;
    { // acquire lock
        mLock.lock();
        // 判断 InputFilter 是否要过滤此事件
        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();

            policyFlags |= POLICY_FLAG_FILTERED; // filtered 标志
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }
        // 创建派发队列的元素
        KeyEntry* newEntry =
                new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
                             args->displayId, policyFlags, args->action, flags, keyCode,
                             args->scanCode, metaState, repeatCount, args->downTime);

        // 添加到派发队列, needWake 表示是否需要唤醒dispatcher线程               
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) { // 需要唤醒dispatcher线程
        mLooper->wake();
    }
}

NativeInputManager::interceptKeyBeforeQueueing

在事件入队之前做一些拦截操作. 它会回调IMS的interceptKeyBeforeQueueing方法

void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {
    ATRACE_CALL();
    // Policy:
    // - Ignore untrusted events and pass them along.
    // - Ask the window manager what to do with normal events and trusted injected events.
    // - For normal events wake and brighten the screen if currently off or dim.
    bool interactive = mInteractive.load();
    if (interactive) { // 添加 interactive FLAG
        policyFlags |= POLICY_FLAG_INTERACTIVE;
    }
    if ((policyFlags & POLICY_FLAG_TRUSTED)) { // trusted 事件
        nsecs_t when = keyEvent->getEventTime();
        JNIEnv* env = jniEnv();
        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
        jint wmActions;
        if (keyEventObj) {
            wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags);  // 回调IMS的interceptKeyBeforeQueueing方法
            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                wmActions = 0;
            }
            android_view_KeyEvent_recycle(env, keyEventObj);
            env->DeleteLocalRef(keyEventObj);
        } else {
            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
            wmActions = 0;
        }

        handleInterceptActions(wmActions, when, /*byref*/ policyFlags); // 处理拦截的结果
    } else { // 非 trusted的, 根据interactive状态判断是否传给user
        if (interactive) {
            policyFlags |= POLICY_FLAG_PASS_TO_USER;
        }
    }
}

InputManagerService的interceptKeyBeforeQueueing方法调用了mWindowManagerCallbacks的同名方法. mWindowManagerCallbacks 是WMS的 mInputManagerCallback 成员,
在系统启动时设置到IMS的. 因此,此处将调用mInputManagerCallback的interceptKeyBeforeQueueing方法

// Native callback.
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}

mInputManagerCallback 是 InputManagerCallback 的实例, 看它的方法调用, 实际上交给了WMS的mPolicy处理, 实际上是PhoneWindowManager来处理

/**
 * Provides an opportunity for the window manager policy to intercept early key
 * processing as soon as the key has been read from the device.
 */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}
NativeInputManager::handleInterceptActions
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    if (wmActions & WM_ACTION_PASS_TO_USER) { // 若PhoneWindowManager处理返回包含WM_ACTION_PASS_TO_USER, 则给派发策略添加POLICY_FLAG_PASS_TO_USER
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    } else {
#if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("handleInterceptActions: Not passing key to user.");
#endif
    }
}
enqueueInboundEventLocked

这个方法主要是将事件条目添加到mInboundQueue. 若在添加之前,mInboundQueue已经是空, 那么说明此时没有事件在分发,dispatcher线程可能陷入等待,此时添加新事件需要唤醒处理

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.empty(); // 添加之前队列为空, 则需要唤醒
    mInboundQueue.push_back(entry);  // 添加到队列
    traceInboundQueueLengthLocked();

    switch (entry->type) {
        case EventEntry::Type::KEY: { // key事件
            // Optimize app switch latency.
            // If the application takes too long to catch up then we drop all events preceding
            // the app switch key.
            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
            if (isAppSwitchKeyEvent(keyEntry)) { // 处理app切换的特殊key, 优化切换时的响应速度
                if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
                    mAppSwitchSawKeyDown = true;
                } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
                    if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
                        ALOGD("App switch is pending!");
#endif
                        mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
                        mAppSwitchSawKeyDown = false;
                        needWake = true;
                    }
                }
            }
            break;
        }

        //... 其他事件
    }

    return needWake;
}

至此,事件已经被投递到了dispatcher的队列中,接下来就是它进行事件分发的处理,这个过程将在另一篇进行分析

总结

本篇文章分析了InputReader的工作过程,它从EventHub中获取原始事件,然后进行加工处理,最后投递到InputDispatcher的队列的过程.包括如下内容:

  • InputReader的创建与EventHub的创建
  • InputReader工作线程的创建与启动
  • InputReader工作线程的主要逻辑
    • 输入设备的管理
    • 原始事件的处理与投递

InputReader的工作主要依靠它内部的工作线程,每一次循环都会调用loopOnce方法, 从EventHub中获取原始事件,然后对原始事件进行加工,转换为适用于Android的相关NotifyArgs事件,并通过 QueuedInputListener 的notifyKey/notifyMotion等方法添加到其缓冲队列,最后通过 QueuedInputListener 的 flush 方法,将所有的缓冲事件通过NotifyArgs::notify 向InputDispatcher投递.在真正添加到InputDispatcher的派发队列之前,会调用策略类的interceptKeyBeforeQueueing/interceptMotionBeforeQueueing等方法,执行预先策略处理(比如是否传递给user).添加事件到InputDispatcher之后,它的工作线程被唤醒(若在休眠),然后执行相关派发流程.

下面列出相关流程关键函数:

  • InputReader::loopOnce
    • mEventHub->getEvents 通过EventHub获取原始事件,包括原始输入事件和(合成)设备事件
    • processEventsLocked 对原始事件的加工处理,并将事件加入QueuedInputListener的队列
      • processEventsForDeviceLocked
        • addDeviceLocked/removeDeviceLocked 处理设备添加移除
        • InputDevice::process 处理事件加工
          • for_each_mapper_in_subdevice
            • XXXInputMapper::process 设备类别的具体mapper进行事件加工
              • getListener()->notifyKey 调用了QueuedInputListener的notifyKey, 将args添加到它的队列中
    • mQueuedListener->flush 将派发队列的事件都投递到InputDispatcher
      • for_each NotifyArgs::notify
        • NotifyKeyArgs::notify 以key事件为例
          • InputClassifier::notifyKey
            • InputDispatcher::notifyKey
              • mPolicy->interceptKeyBeforeQueueing 入队前的策略处理
              • enqueueInboundEventLocked 将事件添加到InputDispatcher的派发队列
              • mLooper->wake 根据需要换线InputDispatcher线程

下面列出对设备的处理(以打开为例)

  • EventHub->getEvents

    • scanDirLocked 扫描目录下的所有设备并打开
    • readNotifyLocked 发生事件的fd是 mINotifyFd, 通常是有设备变化, 读取设备信息变化
      • openDeviceLocked
        • 创建 Device
        • assignDescriptorLocked
        • loadConfigurationLocked
        • 加载keyMap等
        • configureFd
        • registerDeviceForEpollLocked 注册设备节点的epoll事件监听,用于接收input事件
        • addDeviceLocked 保存设备,添加到mOpeningDevices,合成添加设备的事件
  • InputReader::processEventsLocked 处理事件

    • processEventsForDeviceLocked
      • addDeviceLocked 处理添加设备的事件
        • createDeviceLocked
          • 创建 InputDevice
          • device->addEventHubDevice(eventHubId); 填充InputMapper
        • device->configure 配置设备
        • device->reset
        • mDevices.emplace(eventHubId, device) 保存设备
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值