上篇文章《Android6.0输入系统之InputManagerService构成分析》 完成了IMS的创建,接着就沿着输入系统这条路继续往下走。
在EventHub的构造函数中,它通过INotify与Epoll机制建立起对设备点增删事件及可读状态的监听。INotify是Linux内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除、读写等等。它有两个基本对象,inotify对象对应一个队列,应用程序可以向inotify对象添加多个监听,当被监听的事件发生时,可以通过read()函数从inotify对象中将事件信息读取出来;而watch对象则用来描述文件系统的变化事件的监听,它是一个二元组,包括监听目标和事件掩码两个元素,监听目标是文件系统的一个路径,可以是文件也可以是文件夹。Epoll可以使用一次等待监听多个描述符的可读/可写状态。
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) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//1.首先使用epoll_create()函数创建一个epoll对象
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
...
//2.创建一个inotify对象,用来监听设备节点的增删事件
mINotifyFd = inotify_init();
//将存储设备点的路径dev/input作为监听对象添加到inotify对象中
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);
//3.将mINotifyFd作为epoll的一个监控对象
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN; //监听mINotifyFd可读
eventItem.data.u32 = EPOLL_ID_INOTIFY;
//将对mINotifyFd的监听注册到epoll对象中
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
...
}
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指针指向在buffer中下一个可用于存储事件的RawEvent结构体。每存储一个事件,event指针都会向后偏移一个元素 */
RawEvent* event = buffer;
//capacity记录了buffer中的剩余的元素数量
size_t capacity = bufferSize;
bool awoken = false;
//循环getEvent()函数的主体
for (;;) {
...
//遍历mClosingDevices链表,为每一个已卸载的设备生成DEVICE_REMOVED事件
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
event->when = now; //设置产生事件的事件戳
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_I