Android R input 之 InputReader 工作流程

Posted pecuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>& l

以上是关于Android R input 之 InputReader 工作流程的主要内容,如果未能解决你的问题,请参考以下文章

Android R input 之 InputChannel之发送事件处理反馈

Android R input 之 InputChannel之发送事件处理反馈

Android R input 之 InputDispatcher 工作流程

Android R input 之 InputDispatcher 工作流程

Android R input 之 InputManagerService 的建立

Android R input 之 InputManagerService 的建立