EventHub和 Input Lib 关系如下类图所示
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; }