Android 输入事件系统之 EventHub 和 Input Lib(事件解析库)

   EventHub和 Input Lib 关系如下类图所示

  •  Device 类是 EventHub的内部类,这里用EventHub&Device 表示,EventHub和Device是属于inputflinger 模块(frameworks\native\services\inputflinger)
  •  其余类都在Input Lib库里(frameworks\native\libs\input)

    KeyLayoutMap\KeyCharacterMap\VirtualKeyMap 都包含各自的Parser内部类。


下面看下具体细节实现,EventHub 中实现了两个关键的函数,一是EventHub() 构造函数,另一个是getEvents() 函数。

一、 EventHub() 构造函数主要是联合inotify 和 epoll 机制,监听设备的插拔事件,设备节点的数据。

inotify :监听输入设备的add和delete事件。

epoll : 监听各输入设备节点是否有新数据,这个机制主要优点是监听大批量fd时效率依旧很高,而这个也是select方式最大缺点。

              如果某个节点有新数据,epoll_wait 函数会返回新数据,阻塞等待事件。

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);

    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);

    mINotifyFd = inotify_init();
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);// 监听设备插拔 ,DEVICE_PATH = "/dev/input"
    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
            DEVICE_PATH, errno);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);// 监听设备目录个节点数据 ,DEVICE_PATH = "/dev/input"
    .....

}
二 、getEvents() 函数功能

 1. 初次启动或者配置改变时,重新扫描设备,加载设备配置信息。

 2. 执行epoll_wait 监听设备节点,如果监听到设备节点有变化,则登记设备节点到pending 列表;否则阻塞等待。

 3. 把pending 列表里的event 里记录的设备节点,读取节点数据,并保存到buffer里返回给调用者。

 4. 如果读取到event,则退出for循环,把event数据返回给调用则。

<pre name="code" class="cpp">size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    .....

    for (;;) {
        ....
        // 是否需要扫描设备,第一次肯定需要
        if (mNeedToScanDevices) {
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }
        .....
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            ......
            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);// 得到新数据的设备id
            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);// 获取到有新数据的设备
            ALOGV("eventItem.data.u32:%d deviceIndex:%d path:%s",eventItem.data.u32,deviceIndex,device->path.string());
            if (eventItem.events & EPOLLIN) {
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);// 从设备读取数据

                        ......
                else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
                                device->path.string(),
                                (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                iev.type, iev.code, iev.value);

                        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));
                        }

                        // 把数据格式化
                        event->when = now;

                        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());
            }
        }
        // 如果读取到数据,则退出循环
        if (event != buffer || awoken) {
            break;
        }
        .....
        // 否则继续监听
        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
        ....
    }

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





你可能感兴趣的:(Android 输入事件系统之 EventHub 和 Input Lib(事件解析库))