标签:mem appear cte proc log 总结 art 移除 pip
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);
-
- 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);
- 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);
- 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];
-
- RawEvent* event = buffer;
-
- size_t capacity = bufferSize;
- bool awoken = false;
- for (;;) {
- ...............
-
- }
-
-
- return event - buffer;
- }
以上是getEvents()的整体模型,接着看循环体中的方法。
2.1 重新打开设备(mNeedToReopenDevices)
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-
- if (mNeedToReopenDevices) {
- mNeedToReopenDevices = false;
-
- ALOGI("Reopening all input devices due to a configuration change.");
-
- closeAllDevicesLocked();
- mNeedToScanDevices = true;
- break;
- }
由EventHub构造函数可知mNeedToReopenDevices为初始值false,第一次调用getEvents()时不会运行上面的代码块。其中调用了closeAllDevicesLocked()函数
void EventHub::closeAllDevicesLocked() {
while (mDevices.size() > 0) {
closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
}
}
closeAllDevicesLocked()函数中遍历mDevices,通过closeDeviceLocked()函数卸载所有这些设备。closeDeviceLocked()函数如下
- void EventHub::closeDeviceLocked(Device* device) {
- ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
- device->path.string(), device->identifier.name.string(), device->id,
- device->fd, device->classes);
-
- if (device->id == mBuiltInKeyboardId) {
- ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
- device->path.string(), mBuiltInKeyboardId);
- mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
- }
-
- if (!device->isVirtual()) {
-
- if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
- ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
- }
- }
-
- mDevices.removeItem(device->id);
- device->close();
-
-
- Device* pred = NULL;
- bool found = false;
- for (Device* entry = mOpeningDevices; entry != NULL; ) {
- if (entry == device) {
- found = true;
- break;
- }
- pred = entry;
- entry = entry->next;
- }
- if (found) {
-
-
-
- ALOGI("Device %s was immediately closed after opening.", device->path.string());
- if (pred) {
- pred->next = device->next;
- } else {
- mOpeningDevices = device->next;
- }
- delete device;
- } else {
-
-
-
- device->next = mClosingDevices;
- mClosingDevices = device;
- }
- }
closeDeviceLocked()函数主要工作:
1.从Epoll中删除监听(EPOLL_CTL_DEL)。
2.mDevices中删除Device对象
3.将删除端Device对象添加到mClosingDevices中。用于之后向InputReader发送DEVICE_REMOVED事件
2.2 DEVICE_REMOVED事件(mClosingDevices)
- 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_ID : device->id;
- event->type = DEVICE_REMOVED;
- event += 1;
- delete device;
- mNeedToSendFinishedDeviceScan = true;
-
- if (--capacity == 0) {
- break;
- }
- }
mClosingDevices初始值为0,所以刚开始调用getEvents()函数不会运行上述代码块。该块中主要是遍历mClosingDevices,生成DEVICE_REMOVED事件。
2.3 扫描加载设备(mNeedToScanDevices)
- if (mNeedToScanDevices) {
- mNeedToScanDevices = false;
- scanDevicesLocked();
- mNeedToSendFinishedDeviceScan = true;
- }
mNeedToScanDevices初始值为true,所以第一次getEvents会运行该代码块。该代码块主要工作:
1 mNeedToScanDevices赋值为false,避免重复扫描打开设备。
2 调用scanDevicesLocked(),//打开/dev/input下所有输入设备。
3 mNeedToSendFinishedDeviceScan赋值为true,用于生成FINISHED_DEVICE_SCAN事件。
接着看一下scanDevicesLocked()函数
- void EventHub::scanDevicesLocked() {
- status_t res = scanDirLocked(DEVICE_PATH);
- if(res < 0) {
- ALOGE("scan dir failed for %s\n", DEVICE_PATH);
- }
-
- if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
- createVirtualKeyboardLocked();
- }
- }
scanDevicesLocked()函数中调用了scanDirLocked()函数,接着看scanDirLocked()函数:
- status_t EventHub::scanDirLocked(const char *dirname)
- {
- char devname[PATH_MAX];
- char *filename;
- DIR *dir;
- struct dirent *de;
- dir = opendir(dirname);
- if(dir == NULL)
- return -1;
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = ‘/‘;
- 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;
- }
scanDirLocked()函数遍历/dev/input文件夹下的所有设备节点,并分别执行openDeviceLocked(devname),加载设备。openDeviceLocked()函数比较长,就不全部贴出来了,只将一些重要的部分弄出来。
- status_t EventHub::openDeviceLocked(const char *devicePath) {
-
- int fd = open(devicePath, O_RDWR | O_CLOEXEC);
- if(fd < 0) {
- ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
- return -1;
- }
-
-
- 。。。。。。
-
- int32_t deviceId = mNextDeviceId++;
- Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
- 。。。。。。
-
- loadConfigurationLocked(device);
-
-
-
-
- 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)) {
- ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
- delete device;
- return -1;
- }
- 。。。。。
-
- addDeviceLocked(device);
- return 0;
- }
addDeviceLocked将Device添加到mDevice中,同时也会添加到mOpeningDevices中,用来生成DEVICE_ADDED事件,发送给InputReader。这之后就可以通过getEvents读取到设备产生的输入事件了。
2.4 DEVICE_ADDED事件(mOpeningDevices)
- while (mOpeningDevices != NULL) {
- Device* device = mOpeningDevices;
- ALOGD("Reporting device opened: id=%d, name=%s\n",
- device->id, device->path.string());
- 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;
- }
- }
由于上面scanDevicesLocked时将/dev/input下的设备节点打开,并添加到mOpeningDevices中,所以会运行此代码块。这里主要是遍历mOpeningDevices,设置DEVICE_ADDED事件。
2.5 FINISHED_DEVICE_SCAN事件(mNeedToSendFinishedDeviceScan)
- if (mNeedToSendFinishedDeviceScan) {
- mNeedToSendFinishedDeviceScan = false;
- event->when = now;
- event->type = FINISHED_DEVICE_SCAN;
- event += 1;
- if (--capacity == 0) {
- break;
- }
- }
上述三个代码块都会将mNeedToSendFinishedDeviceScan设为true,所以接着生成FINISHED_DEVICE_SCAN类型的事件。也就是当设备增删事件后,需要向getEvents()函数调用者发送FINISHED_DEVICE_SCAN事件。
由代码顺序可以知道DEVICE_REMOVED事件优先级最高、然后DEVICE_ADDED事件、FINISHED_DEVICE_SCAN事件最低。只有高优先级的事件处理完之后才会处理低优先级的事件。
2.6 iNotify事件、管道事件
接着是while循环,检查是否有未处理的设备事件。
- while (mPendingEventIndex < mPendingEventCount) {
- const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
-
- if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
- if (eventItem.events & EPOLLIN) {
- mPendingINotify = true;
- } else {
- ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
- }
- continue;
- }
- 。。。。。。
- }
-
-
-
-
-
- if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
- mPendingINotify = false;
- readNotifyLocked();
- deviceChanged = true;
- }
- ALOGD("getEvents -----9 deviceChanged:%d",deviceChanged);
-
- if (deviceChanged) {
- continue;
- }
- 。。。。。。
mPendingINotify赋值为false,表示之后没有待处理的inotify事件。
readNotifyLocked()
处理inotify事件。
deviceChanged设置为true,进行下一次循环,生成设备增删事件。
接着看一下readNotifyLocked()函数中做了些什么。
- status_t EventHub::readNotifyLocked() {
- int res;
- char devname[PATH_MAX];
- char *filename;
- char event_buf[512];
- int event_size;
- int event_pos = 0;
- struct inotify_event *event;
-
- ALOGD("EventHub::readNotify nfd: %d\n", mINotifyFd);
-
- res = read(mINotifyFd, event_buf, sizeof(event_buf));
- if(res < (int)sizeof(*event)) {
- if(errno == EINTR)
- return 0;
- ALOGW("could not get event, %s\n", strerror(errno));
- return -1;
- }
-
-
- strcpy(devname, DEVICE_PATH);
- filename = devname + strlen(devname);
- *filename++ = ‘/‘;
-
- while(res >= (int)sizeof(*event)) {
- event = (struct inotify_event *)(event_buf + event_pos);
-
- if(event->len) {
- strcpy(filename, event->name);
- if(event->mask & IN_CREATE) {
- openDeviceLocked(devname);
- } else {
- ALOGI("Removing device ‘%s‘ due to inotify event\n", devname);
- closeDeviceByPathLocked(devname);
- }
- }
-
- event_size = sizeof(*event) + event->len;
- res -= event_size;
- event_pos += event_size;
- }
- return 0;
- }
主要工作
1 通过read()函数读取iNotify事件
2 遍历所有的iNotify事件
3 判断iNotify事件类型,IN_CREATE类型则加载设备,IN_DELETE类型则卸载设备。
接着是判断是否是管道事件
- while (mPendingEventIndex < mPendingEventCount) {
- 。。。。。
- if (eventItem.data.u32 == EPOLL_ID_WAKE) {
- if (eventItem.events & EPOLLIN) {
- ALOGD("awoken after wake()");
- awoken = true;
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
- } else {
- ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
- eventItem.events);
- }
- continue;
- }
- 。。。。
- }
- 。。。。
- if (event != buffer || awoken) {
- break;
- }
2.7 输入事件
接着到输入事件了。根据输入事件,进行设置时间戳、id、类型、值等。拥有返回给调用者InputReader。
- while (mPendingEventIndex < mPendingEventCount) {
- 。。。。。
-
- ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
- 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);
- if (eventItem.events & EPOLLIN) {
- int32_t readSize = read(device->fd, readBuffer,
- sizeof(struct input_event) * capacity);
- if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
-
-
- ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d "
- "capacity: %d errno: %d)\n",
- device->fd, readSize, bufferSize, capacity, errno);
- deviceChanged = true;
- closeDeviceLocked(device);
- } else if (readSize < 0) {
- if (errno != EAGAIN && errno != EINTR) {
- ALOGW("could not get event (errno=%d)", errno);
- }
- } else if ((readSize % sizeof(struct input_event)) != 0) {
- ALOGE("could not get event (wrong size: %d)", readSize);
- } 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];
-
- 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));
- }
-
- #ifdef HAVE_POSIX_CLOCKS
-
- event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
- + nsecs_t(iev.time.tv_usec) * 1000LL;
- ALOGV("event time %lld, now %lld", event->when, now);
-
- if (event->when >= now + 10 * 1000000000LL) {
-
- nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
- if (event->when > time) {
- ALOGW("An input event from %s has a timestamp that appears to "
- "have been generated using the wrong clock source "
- "(expected CLOCK_MONOTONIC): "
- "event time %lld, current time %lld, call time %lld. "
- "Using current time instead.",
- device->path.string(), event->when, time, now);
- event->when = time;
- } else {
- ALOGV("Event time is ok but failed the fast path and required "
- "an extra call to systemTime: "
- "event time %lld, current time %lld, call time %lld.",
- event->when, time, now);
- }
- }
- #else
- event->when = now;
- #endif
-
- 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;
- }
- }
- } 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());
- }
- }
- 。。。。。。
- rerutn event-buffer;
- }
while循环后面是判断是否有inotify事件,wake事件。接着是获取epoll事件 。先获取到epoll事件,下次循环才会处理while循环。
通过mEpollFd描述符,获取epoll事件。保存在mPendingEventItems中,EPOLL_MAX_EVENTS(16)为限制一次最大读取事件次数,timeoutMillis为超时时间。
- mPendingEventIndex = 0;
-
- mLock.unlock();
- release_wake_lock(WAKE_LOCK_ID);
-
- int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
-
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
- mLock.lock();
-
- if (pollResult == 0) {
-
- mPendingEventCount = 0;
- break;
- }
-
- if (pollResult < 0) {
-
- mPendingEventCount = 0;
-
-
-
- if (errno != EINTR) {
- ALOGW("poll failed (errno=%d)\n", errno);
- usleep(100000);
- }
- } else {
-
-
- mPendingEventCount = size_t(pollResult);
- }
- }
到现在getEvents函数基本上就完了。还有许多内容待揣摩。
3 总结
EventHub主要工作:设备管理(加载、卸载)、输入事件读取。核心代码就是getEvent(),该代码中完成了这些事情。
其中使用到的epoll、inotify、管道这些技术可以好好研究下。。。。
。。。。。。
Android 输入系统(二)EventHub
标签:mem appear cte proc log 总结 art 移除 pip
原文地址:http://www.cnblogs.com/ydkf85/p/6569258.html