2、EventHub
从InputManager的初始化可知,EventHub是NativeInputManager的构造函数中创建的。
@framework/base/services/core/jni/com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) {
...
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
本节将详细介绍EventHub的具体实现。
先看看构造函数:
@frameworks/native/services/inputflinger/EventHub.cpp
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) {
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
mINotifyFd = inotify_init();
int result = inotify_add_watch(mINotifyFd, "/dev/input", IN_DELETE | IN_CREATE);
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);
...
int wakeFds[2];
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
}
除了监控Input设备节点的添加和删除,EventHub还会监控一个pipe读端文件,这提供了一个唤醒EventHub的epoll的方法。
因为InputReader在没有event事件的时候也需要被唤醒,来处理其他事务,这种情况后续会提到。
InputReader会在每次loop时,都会调用EventHub的getEvents来获取input事件:
@frameworks/native/services/inputflinger/InputReader.cpp
void InputReader::loopOnce() {
...
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); // 在没有input事件时,会block在这里
...
if (count) {
processEventsLocked(mEventBuffer, count);
}
...
mQueuedListener->flush();
getEvents()实现主要分两部分:
1、打开和关闭设备
2、接收input事件
完整代码如下:
@frameworks/native/services/inputflinger/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
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.
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
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;
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != NULL) {
Device* device = mOpeningDevices;
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
// 设备的打开和关闭的事件
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
}
continue;
}
// 唤醒事件,需要跳出循环,让InputReader处理其他的事务(更新配置信息)
if (eventItem.data.u32 == EPOLL_ID_WAKE) {
if (eventItem.events & EPOLLIN) {
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
}
continue;
}
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
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)) {
...
} else if (readSize < 0) {
...
} else if ((readSize % sizeof(struct input_event)) != 0) {
...
} 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];
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL;
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
mPendingEventIndex -= 1;
break;
}
}
}
}
...
// 打开和关闭设备的事件
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) {
continue;
}
// 如果读取到event或被InputReader有其他事务要处理,则跳出循环
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
...
mPendingEventCount = size_t(pollResult);
}
// All done, return the number of events we read.
return event - buffer;
}
EventHub的构造函数中mNeedToScanDevices的初始值为true,所以第一次进入getEvents时,会扫描设备目录("/dev/input")。
@frameworks/native/services/inputflinger/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
AutoMutex _l(mLock);
...
for (;;) {
...
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
...
}
void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked("/dev/input");
...
}
status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
//扫描/dev/input/目录下的设备节点
while((de = readdir(dir))) {
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);
openDeviceLocked(devname);
}
closedir(dir);
return 0;
}
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
// 构建identifier
InputDeviceIdentifier identifier;
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}
...
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;
...
// 设置成NONBLOCK
fcntl(fd, F_SETFL, O_NONBLOCK)) ;
// 分配设备ID,并创建Device对象
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
...
// 将设备注册到epoll监控列表中
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
}
...
addDeviceLocked(device);
return 0;
}
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
}
从上面的openDeviceLocked()函数中可以看到,
这里打开"/dev/input/"目录下的input设备后,将其注册到epoll的监控队列中。
这样一旦对应设备上有可读的input事件,则epool_wait()就会返回,并带会deviceid。
而每个设备都是用addDeviveLocked()将对应设备以deviceid为索引加入到mDevices中,
因此我们可以用epoll_wait()返回的deviceid,找到具体的device:
@frameworks/native/services/inputflinger/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer;
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
...
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
// eventItem.data.u32既是deviceid
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
// 从device中得到fd后再去读设备,获取input事件
int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
...
} else if (readSize < 0) {
...
} else if ((readSize % sizeof(struct input_event)) != 0) {
...
} 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];
event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL;
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
mPendingEventIndex -= 1;
break;
}
}
}
}
...
mPendingEventIndex = 0;
// 等待input事件
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
...
mPendingEventCount = size_t(pollResult);
}
}
除了具体的input事件,设备的打开关闭等信息,也要包装成event,上报给InputReader:
@frameworks/native/services/inputflinger/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
...
for (;;) {
...
while (mClosingDevices) {
Device* device = mClosingDevices;
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
while (mOpeningDevices != NULL) {
Device* device = mOpeningDevices;
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
...
}
}
}
EventHub是InputReader用于打开和关闭Input设备,监听和读取Input事件的对象。
下一节将介绍InputReader处理EventHub中的Event的流程。
浙公网安备 33010602011771号