framework 学习笔记21. input输入事件番外4(事件读取InputReader)

在上一节 input输入事件番外3 中讲到 IMS 在 native 层的启动,其中关于事件读取线程循环读取事件时调用了如下代码:

// 循环执行任务
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();  // 循环执行 mReader 的 loopOnce() 方法;
    return true;
}

事件的读取关键就是 InputReader 的 loopOnce() 方法,接下来就从这个方法入手分析 InputReader 这个类以及它所要完成的任务;

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector 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

    // 1. 读取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            // 2. 事件的简单处理;
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        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);
    }
    
    // 3. 把事件传给 InputDispatcher 处理(也可以理解为交给分发线程处理)
    mQueuedListener->flush();  // 这个 mQueuedListener 其实就是 InputDispatcher
}

从上面的代码中可以总结为三点:
(1)读取事件;
(2)事件的简单处理;
(3)把事件传给 InputDispatcher 处理(也可以理解为交给分发线程处理);

1. 读取事件

读取事件是通过 mEventHub->getEvents() 方法获取的,其基本原理在 Linux知识 中已经介绍过,接下来简单分析一下 EventHub。
1.1 EventHub 的构造函数:

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
    //(epoll 的用法第 1 步):epoll_create()
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);  // EPOLL_SIZE_HINT 指定最大监听个数为 8

    // inotify 用法第 1 步:inotify_init(),初始化 fd
    mINotifyFd = inotify_init();
    // inotify 用法第 2 步:inotify_add_watch(),监测;其中 DEVICE_PATH = "/dev/input";
    // inotify 用法第 3 步:read(),读取;在 getEvents() 中调用
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);  

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;  // 这里并没有使用fd字段,而使用了自定义的值EPOLL_ID_INOTIFY
    //(epoll 的用法第 2 步):epoll_ctl()
    //(epoll 的用法第 3 步):epoll_wait();在 getEvents() 中调用
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);  // 将对mINotifyFd的监听注册到epoll对象中

    // ... 省略部分代码 见注释 1
}

在构造函数中,使用了 inotify 机制监测 "/dev/input" 目录的变化;使用 epoll 监测有无数据;大致流程如下:
(1)创建 inotify 的文件句柄 mINotifyFd = inotify_init() 并通过 inotify_add_watch() 监测 "/dev/input" 目录;
(2)在 openDeviceLocked() 中调用 fd = open(devicePath, O_RDWR | O_CLOEXEC) 打开各种设备节点,例如 /dev/input/event0;
(3)使用 epoll_wait() 监测这些文件句柄 mINotifyFd、fd;
(4)读取文件句柄,构造相应的 RawEvent (下面有介绍),例如新增了设备节点就可以通过 mINotifyFd 监测到;

注释1:在构造函数省略的代码中,EventHub 创建了一个名为 wakeFds 的匿名管道,并将管道读取端的描述符的可读事件注册到 epoll 对象中。因为 InputReader 在执行 getEvents() 时会因无事件而导致其线程阻塞在 epoll_wait() 的调用里,然而有时希望能够立刻唤醒 InputReader 线程使其处理一些请求。此时只需向 wakeFds 管道的写入端写入任意数据,此时读取端有数据可读,使得epoll_wait() 得以返回,从而达到唤醒 InputReader 线程的目的;

1.2 获取事件:getEvents()
通过 mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE) 方法来获取事件,其中 mEventBuffer 是一个大小为 256 的 RawEvent 数组,用于存放获取到的事件;

static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];

struct RawEvent {
    nsecs_t when;
    int32_t deviceId;
    int32_t type;  // 事件的类型
    int32_t code;
    int32_t value;
};

// RawEvent 的 type 类型:
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,
};

// 另外在扫描 "dev/input" 目录下设备节点的过程中,中可以发现还有一下的一些事件类型:
    // openDeviceLocked() 中;
    // EV_KEY 0x01 按键事件  
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);  
    // EV_ABS 0x03 绝对坐标,如触摸屏上报的坐标
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); 
    // EV_REL 0x02 相对坐标,   如鼠标上报的坐标 
    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
    // 用来描述具备两种状态的输入开关
    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
    // EV_LED 0x11 LED   
    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
    // EV_FF 0x15 力反馈 
    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
// 另外,还有  EV_SYN(0x00 同步事件);SYN_REPORT(一次事件的结尾)  等等;
// 收到一个点之后并不会立即处理,而是一个事件完成之后才会处理,SYN_REPORT就是这个事件的标志。

接下来是 getEvents() 的分析:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);
    AutoMutex _l(mLock);
    struct input_event readBuffer[bufferSize];
   // event指针指向了在 buffer 下一个可用于存储事件的 RawEvent 结构体。每存储一个事件,event 指针都回向后偏移一个元素
    RawEvent* event = buffer;
   // capacity 记录了 buffer 中剩余的元素数量。当capacity为0时,表示 buffer 已满,此时需要停继续处理新
   // 事件,并将已处理的事件返回给调用者
    size_t capacity = bufferSize;
    bool awoken = false;

    // getEvents()的关键部分:在这个循环中,会先将可用事件放入到buffer中并返回。如果没有可用事件,
    // 则进入 epoll_wait() 等待事件的到来,epoll_wait() 返回后会重新循环将可用将新事件放入 buffer
    for (;;) {
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // ... 省略部分代码

        //(1)第一步:****************************** 见下方解释 *****************************
        if (mNeedToScanDevices) {  // 稍稍注意下在 EventHub 构造函数中 mNeedToScanDevices(true)
            mNeedToScanDevices = false;
            // 第一次进入时扫描 "dev/input" 目录下所有的设备节点时,会建立设备列表存储在mDevice成员变量
            // 中 (EventHub中有设备列表 KeyedVector mDevices);并通过 open() 函
            // 数打开节点,最终调用 epoll_ctl() 添加到 epoll 中;
            scanDevicesLocked();  // 这个方法有兴趣可以跟进去看看
            mNeedToSendFinishedDeviceScan = true;
        }

        // ...

        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        // Grab the next input event.
        //(2)第二步:****************************** 见下方解释 *****************************
        bool deviceChanged = false;
        // mPendingEventItems:处理未被 InputReader 取走的输入事件与设备事件
        while (mPendingEventIndex < mPendingEventCount) {
           /* 在这里分析每一个 epoll_event,如果是表示设备节点可读,则读取原始事件并放置到 buffer
              中。如果是表示 mINotifyFd 可读,则设置 mPendingINotify 为 true,当 InputReader 
              将现有的输入事件都取出后读取 mINotifyFd 中的事件,并进行相应的设备加载与卸载操作。
              另外,如果此 epoll_event 表示 wakeFds 的读取端有数据可读,则设置 awake 标志为 true,
              无论此次 getEvents() 调用有无取到事件,都不会再次进行 epoll_wait() 进行事件等待 */
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }

            if (eventItem.data.u32 == EPOLL_ID_WAKE) {
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    awoken = true;
                    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;
            }

            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            if (deviceIndex < 0) {
                ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
                        eventItem.events, eventItem.data.u32);
                continue;
            }

            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                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) {
                    ALOGE("could not get event (wrong size: %d)", readSize);
                } else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        // input_event 是 linux kernel 获取到的输入事件
                        struct input_event& iev = readBuffer[i];

                        if (iev.type == EV_MSC) {
                            if (iev.code == MSC_ANDROID_TIME_SEC) {
                                device->timestampOverrideSec = iev.value;
                                continue;
                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {
                                device->timestampOverrideUsec = iev.value;
                                continue;
                            }
                        }
                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {
                            iev.time.tv_sec = device->timestampOverrideSec;
                            iev.time.tv_usec = device->timestampOverrideUsec;
                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
                                device->timestampOverrideSec = 0;
                                device->timestampOverrideUsec = 0;
                            }
                            ALOGV("applied override time %d.%06d",
                                    int(iev.time.tv_sec), int(iev.time.tv_usec));
                        }

#else
                        event->when = now;
#endif
                        // 将 input_event 封装成 RawEvent
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    if (capacity == 0) {
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            } else if (eventItem.events & EPOLLHUP) {
                ALOGI("Removing device %s due to epoll hang-up event.",
                        device->identifier.name.string());
                deviceChanged = true;
                closeDeviceLocked(device);
            } else {
                ALOGW("Received unexpected epoll event 0x%08x for device %s.",
                        eventItem.events, device->identifier.name.string());
            }
        }

        //(3)第三步:****************************** 见下方解释 *****************************
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
           /* 读取 mINotifyFd 中的事件,同时对输入设备进行相应的加载与卸载操作。这个操作必须当
              InputReader 将现有输入事件读取并处理完毕后才能进行,因为现有的输入事件可能来自需要
              被卸载的输入设备,InputReader 处理这些事件依赖于对应的设备信息 */
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }

        // Report added or removed devices immediately.
        // 设备节点增删操作发生时,则重新执行循环体,以便将设备变化的事件放入buffer中
        if (deviceChanged) {
            continue;
        }

        // Return now if we have collected any events or if we were explicitly awoken.
        // 如果此次getEvents()调用成功获取了一些事件,或者要求唤醒InputReader,则退出循环并
        // 结束getEvents()的调用,使InputReader可以立刻对事件进行处理
        if (event != buffer || awoken) {
            break;
        }

        //(4)第四步:****************************** 见下方解释 *****************************
        // 此次getEvents()调用没能获取事件
        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll, must be before release_wake_lock
        release_wake_lock(WAKE_LOCK_ID);

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

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock

        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.
            // 从 epoll_wait() 中得到新的事件后,重新循环,对新事件进行处理
            mPendingEventCount = size_t(pollResult);
        }
    }

    // All done, return the number of events we read.
    // 返回本次getEvents()调用所读取的事件数量
    return event - buffer;
}

(1)第一步:首先进行与设备相关的工作。如 EventHub 创建后第一次执行 getEvents() 函数时,需要扫描 "/de/input" 目录下所有设备节点并打开这些设备节点。另外,当设备节点的发生增加时,会将设备事件存入到 buffer 中;

(2)第二步:处理未被 InputReader 取走的输入事件与设备事件。epoll_wait() 所取出的 epoll_event 存储在mPendingEventItems中,mPendingEventCount 指定了 mPendingEventItems 数组所存储的事件个数。而mPendingEventIndex 指定尚未处理的 epoll_event 的索引;

(3)第三步:如果 mINotifyFd 有数据可读,说明设备节点发生了增删操作;

(4)第四步:如果此次 getEvents() 调用没能获取事件,说明 mPendingEventItems 中没有事件可用,于是执行 epoll_wait() 函数等待新的事件到来,将结果存储到 mPendingEventItems 里,并重置 mPendingEventIndex 为 0;

2. 事件的简单处理

在 InputReader 中 loopOnce() 方法中调用 processEventsLocked(mEventBuffer, count) 会对获取到的事件进行简单的处理,其复杂的处理及分发是在 InputDispatcher 中完成的;

// 根据获取到的 RawEvent 的 type 类型进行处理:
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        // 如果是常规的 event 事件,FIRST_SYNTHETIC_EVENT = DEVICE_ADDED (0x10000000)
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }

            // processEventsForDeviceLocked() 处理一般的事件: 见 2.2 
            // 把这次获取到的 event 数组中属于同一批次的,进一步处理,判定条件就是:常规 event 以及是属于同一设备 
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  
        } 
        // 处理 3 种特殊的事件:例如添加设备, 见 2.1 
        else {  // 这里就是3种特殊的 event 类型,例如有时候打开设备的时候会有这个 ADD 事件
            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;
            }
        }
        // 如果在上面没有处理完 event 数组中的成员,那么依次继续 
        count -= batchSize;
        rawEvent += batchSize;
    }
}

2.1 添加设备:
既然是添加设备,那么必定有一个容器来保存这些设备,这个容器就是 KeyedVector mDevices;还记得获取输入事件的时候,扫描 "dev/input" 目录下设备节点时也有一个保存设备的容器 KeyedVector mDevices 吗?在这里介绍一下两者的区别:简单来说就是里面的设备不同;

// EventHub 中的 Device:
struct Device {
        Device* next;
        // 文件句柄;
        int fd; // may be -1 if device is virtual 
        // classes 信息,在 InputReader 中会用到;
        uint32_t classes;
        // 设备信息;
        const InputDeviceIdentifier identifier;  
        // 配置信息(例如 Linux 内核获取到的按键值1,在 Android 中经过配置文件转换并不是1,而是其他值);
        String8 configurationFile; 
        PropertyMap* configuration;
        // ... 省略
}

// InputReader 中的 InputDevice:
class InputDevice {
private:
    InputReaderContext* mContext;
    int32_t mId;
    int32_t mGeneration;
    int32_t mControllerNumber;
    InputDeviceIdentifier mIdentifier;

    // 关注点:这里有一个 InputMapper 的成员变量,它的作用是将各种封装了各种不同的事件类型,例如
    // 键盘事件的设备对应的是 KeyboardInputMapper;
    Vector mMappers;
    // ... 省略
}

这里就会有一个问题,为什么对于一个设备要进行添加两次,这么做是不是多余的呢?在我看来,这么设计的目的应该是一个分层设计(或者说单一职责)的思想;在 EventHub 中处理的是比较原始的数据,主要是一些事件的获取、设备的配置等工作,而在 InputReader 中是对 EventHub 中获取的一些事件进行初步处理和传递事件发给 InputDispatcher 处理,所以才这么封装的;

那么,接下来就分析一下添加设备的源代码 addDeviceLocked():

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex >= 0) {
        ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
        return;
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);

    // 创建出 InputDevice;  详见下面 createDeviceLocked() 的分析
    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
    device->configure(when, &mConfig, 0);
    device->reset(when);

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

    mDevices.add(deviceId, device);  // 将创建出的 device 加入到 mDevices 中;
    bumpGenerationLocked();
}

创建 InputDevice:createDeviceLocked()

// 根据 rawEvent 中的 deviceId 创建相应的 InputDevice 并添加相应的 Mapper
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
            controllerNumber, identifier, classes);

    // External devices.
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
        device->setExternal(true);
    }

    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        device->addMapper(new SwitchInputMapper(device));
    }

    // Vibrator-like devices.
    if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
        device->addMapper(new VibratorInputMapper(device));
    }

    // 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) {
        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
    }

    // Cursor-like devices.
    if (classes & INPUT_DEVICE_CLASS_CURSOR) {
        device->addMapper(new CursorInputMapper(device));
    }

    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }

    // Joystick-like devices.
    if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
        device->addMapper(new JoystickInputMapper(device));
    }

    return device;
}

2.2 事件初步处理:

// InputReader.cpp 中 processEventsForDeviceLocked() 方法:
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }
    // 这里根据 deviceId 取出上面添加进去的 InputDevice
    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}


// InputReader.cpp 中 process() 方法:
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    // 这里有个 mapper 数组,在 create 时 会根据 classes 类型去匹配处理 mapper,一般都是匹配一个
    size_t numMappers = mMappers.size();

    // 遍历事件数组,依次去处理  
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
                rawEvent->when);

        if (mDropUntilNextSync) {
            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().string());
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                // 调用 mapper 的 process 函数,交给 InputDispatcher 并开始分发流程;
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);  // 最终是调用了 设备相应的 mapper->process(rawEvent) 方法;
            }
        }
    }
}

3. 事件传递给 InputDispatcher 处理:

事件经过获取,初步处理,最终执行了 mapper->process(rawEvent) 方法,对于 mapper->process() 这个方法需要查看 InputReader::createDeviceLocked() 中创建的具体的InputMapper的process函数。下面就以 SingleTouchInputMapper 的 process() 为例:

SingleTouchInputMapper 的 process() 方法:

// (1)
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);  // 调用父类的process  
    mSingleTouchMotionAccumulator.process(rawEvent);
}

void TouchInputMapper::process(const RawEvent* rawEvent) {
    mCursorButtonAccumulator.process(rawEvent); 
    mCursorScrollAccumulator.process(rawEvent); 
    mTouchButtonAccumulator.process(rawEvent); 
    // 一组同步事件,并且已经完结(有事件结束标值 SYN_REPORT);  
    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        sync(rawEvent->when);  // 关键方法,后续有分析;
    }
}
/**
以下语句均是将输入事件信息转存至类成员变量中:
    mCursorButtonAccumulator.process(rawEvent);  // 注释 1 
    mCursorScrollAccumulator.process(rawEvent);   // 注释 2
    mTouchButtonAccumulator.process(rawEvent);   // 注释 3
    mSingleTouchMotionAccumulator.process(rawEvent);  // 注释 4
**/

注释1:mCursorButtonAccumulator.process(rawEvent)
记录鼠标或触摸板的按键状态:记录 rawEvent->type 为 EV_KEY,且rawEvent->code为BTN_LEFT、BTN_RIGHT、BTN_MIDDLE、BTN_BACK、BTN_SIDE、BTN_FORWARD、BTN_EXTRA、BTN_TASK 事件。

注释2:mCursorScrollAccumulator.process(rawEvent)
记录光标滚动:记录rawEvent->type为EV_REL,且rawEvent->code为REL_WHEEL、REL_HWHEEL 事件。

注释3:mTouchButtonAccumulator.process(rawEvent)
记录触摸 手写笔 工具按钮状态:记录rawEvent->type为EV_KEY,且rawEvent->code为BTN_TOUCH、BTN_STYLUS、BTN_STYLUS2、BTN_TOOL_FINGER、BTN_TOOL_PEN、BTN_TOOL_RUBBER、BTN_TOOL_BRUSH、BTN_TOOL_PENCIL、BTN_TOOL_AIRBRUSH、BTN_TOOL_MOUSE、BTN_TOOL_LENS、BTN_TOOL_DOUBLETAP、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP 事件。
BTN_TOUCH 的数据在这里被处理了,且其 value 被保存在 mBtnTouch 成员变量中;

注释4:mSingleTouchMotionAccumulator.process
记录ABS相关的值,记录rawEvent->type为EV_ABS,且rawEvent->scanCode为ABS_X、ABS_Y、ABS_PRESSURE、ABS_TOOL_WIDTH、ABS_DISTANCE、ABS_TILT_X、ABS_TILT_Y的事件。
ABS_X和ABS_Y 的数据在这里被处理了。

TouchInputMapper 中的 sync(nsecs_t when)方法:

// 输入事件分发的关键在 sync(nsecs_t when) 中:这个同步函数比较长,下面是简化后的代码,重点事件的分发
void TouchInputMapper::sync(nsecs_t when) {
    // Sync button state.
    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
            | mCursorButtonAccumulator.getButtonState();

    // Sync scroll state.
    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
    mCursorScrollAccumulator.finishSync();

    // Sync touch state.
    bool havePointerIds = true;
    mCurrentRawPointerData.clear();
    /*调用子类的 syncTouch,这里是 SingleTouchMotionAccumulator的syncTouch(),
      更新 ABS 坐标值,这里是把数据存入到 mCurrentRawPointerData 中供下面 cook */
    syncTouch(when, &havePointerIds);  //这里是一个虚函数  

/***** 虚函数是一个类中希望重载的成员函数 ,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数 *****/

    // Reset state that we will compute below.
    mCurrentFingerIdBits.clear();
    mCurrentStylusIdBits.clear();
    mCurrentMouseIdBits.clear();
    mCurrentCookedPointerData.clear();  // 先清除一下
    if (mDeviceMode == DEVICE_MODE_DISABLED) {
        // Drop all input if the device is disabled.
        mCurrentRawPointerData.clear();
        mCurrentButtonState = 0;
    } else {
        // ...    
        // 这个函数很庞大,cook 数据,主要是生成 mCurrentCookedPointerData.pointerCoords,
        // mCurrentCookedPointerData.pointerProperties 和 mCurrentCookedPointerData.idToIndex
        cookPointerData();   
        if (mDeviceMode == DEVICE_MODE_POINTER) {
            PointerUsage pointerUsage = mPointerUsage;
            dispatchPointerUsage(when, policyFlags, pointerUsage);  
        } else {
            if (mDeviceMode == DEVICE_MODE_DIRECT
                    && mConfig.showTouches && mPointerController != NULL) {
                mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);                
                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
                mPointerController->setButtonState(mCurrentButtonState);
                mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
                        mCurrentCookedPointerData.idToIndex,
                        mCurrentCookedPointerData.touchingIdBits);
            }

            // 分发事件,这里的三个方法最终都回调用 dispatchMotion()
            dispatchHoverExit(when, policyFlags);
            dispatchTouches(when, policyFlags);
            dispatchHoverEnterAndMove(when, policyFlags);
        }

           // 之后的代码是一些数据保存之类的操作
           // ...
    }
    // ...
    mCurrentRawVScroll = 0;
    mCurrentRawHScroll = 0;
}

事件传递给 InputDispatcher 处理 dispatchMotion():

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
        const PointerProperties* properties, const PointerCoords* coords,
        const uint32_t* idToIndex, BitSet32 idBits,
        int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
    // ...
    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    // 这里的 getListener() 其实就是 InputReader 的构造函数中传入的 mDispatcher 作为回调,只是做了进一步封装;
    getListener()->notifyMotion(&args);  
}

通过调用 dispatchMotion() 方法,事件最终交由 InputDispatcher 处理,到这里本小节的内容就结束了,下一节将继续 InputDispatcher 的学习。

你可能感兴趣的:(framework 学习笔记21. input输入事件番外4(事件读取InputReader))