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数据返回给调用则。
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;
}