接着上一篇的InputManagerService,这里主要介绍一下EventHub。EventHub主要是访问/dev/input下的所有设备节点,并将输入事件、设备节点的增删返给InputReader。
1 EventHub初始化
由上一篇可知,EventHub对象是在NativeInputManager构造函数中创建的。先看一下EventHub构造函数中都做了些什么
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1),
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对象,mEpollFd为epoll对象的描述符
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
//创建inotify对象,mINotifyFd为inotify对象的描述符
mINotifyFd = inotify_init();
//DEVICE_PATH值为"/dev/input",监听该目录下的设备节点创建与删除操作。通过read函数读取事件。
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
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;
//EPOLL_CTL_ADD表示增加事件
//epoll_ctl将事件监听添加到epoll对象中去。
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
这段代码主要工作:1.初始化一些成员变量
2.创建epoll对象,EPOLL_SIZE_HINT = 8代表最大监听数为8.
3.创建inotify对象,监听/dev/input下设备节点的增删。
4.将mINotifyFd添加到epoll中,作为一个监控对象。
5.创建管道,将管道读取端的可读事件添加到epoll中。使epoll_wait()返回,唤醒InputReader线程。
2 EventHub::getEvents()
EventHub的主要工作都是在getEvents函数中,InputReaderThread通过循环调用EventHub的getEvents()函数获取输入事件。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指针向后移动一个元素。
RawEvent* event = buffer;
//capacity存buffer中剩余端元素数量,capacity为0,表示buffer已满。
size_t capacity = bufferSize;
bool awoken = false;
for (;;) {
...............
//循环体。
}
// All done, return the number of events we read.
return event - buffer;
}
以上是getEvents()的整体模型,接着看循环体中的方法。
2.1 重新打开设备(mNeedToReopenDevices)
//获取系统当前时间(native层的方法)。
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// Reopen input devices if needed.
if (mNeedToReopenDevices) {//判断是否需要重新打开设备
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked();//关闭、卸载所有设备
mNeedToScanDevices = true; //下次扫描设备
break; // return to the caller before we actually rescan
}
由EventHub构造函数可知mNeedToReopenDevices为初始值false,第一次调用getEvents()时不会运行上面的代码块。其中调用了closeAllDevicesLocked()函数
void EventHub::closeAllDevicesLocked() {
while (mDevices.size() > 0) {