From 44692de85517042095d2bf4a5122ca0d50b1d7d0 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 2 May 2018 11:22:15 -0700 Subject: [PATCH] init: Add inotify for /dev/input/ Since event sources can come and go asynchronously because of delayed driver instantiation due to initialization or firmware upload, USB attched devices, kernel module loads, or test automation sources like monkey, add in inotify on /dev/input/ to support these possibilities. Test: manual, boot, check registered chord works Bug: 64114943 Change-Id: Ie598bb6f5bf94b2034ab33cf3be7fa15d3467141 --- init/keychords.cpp | 78 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/init/keychords.cpp b/init/keychords.cpp index f55d2c43c..10c56e311 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -20,12 +20,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -118,6 +120,8 @@ KeychordMask keychord_current; constexpr char kDevicePath[] = "/dev/input"; +std::map keychord_registration; + void HandleKeychord(int id) { // Only handle keychords if adb is enabled. std::string adb_enabled = android::base::GetProperty("init.svc.adbd", ""); @@ -215,6 +219,7 @@ bool KeychordGeteventEnable(int fd) { } void GeteventOpenDevice(const std::string& device) { + if (keychord_registration.count(device)) return; auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC)); if (fd == -1) { PLOG(ERROR) << "Can not open " << device; @@ -222,21 +227,74 @@ void GeteventOpenDevice(const std::string& device) { } if (!KeychordGeteventEnable(fd)) { ::close(fd); + } else { + keychord_registration.emplace(device, fd); + } +} + +void GeteventCloseDevice(const std::string& device) { + auto it = keychord_registration.find(device); + if (it == keychord_registration.end()) return; + auto fd = (*it).second; + unregister_epoll_handler(fd); + keychord_registration.erase(it); + ::close(fd); +} + +int inotify_fd = -1; + +void InotifyHandler() { + unsigned char buf[512]; + + auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf))); + if (res < 0) { + PLOG(WARNING) << "could not get event"; + return; + } + + auto event_buf = buf; + while (static_cast(res) >= sizeof(inotify_event)) { + auto event = reinterpret_cast(event_buf); + auto event_size = sizeof(inotify_event) + event->len; + if (static_cast(res) < event_size) break; + if (event->len) { + std::string devname(kDevicePath); + devname += '/'; + devname += event->name; + if (event->mask & IN_CREATE) { + GeteventOpenDevice(devname); + } else { + GeteventCloseDevice(devname); + } + } + res -= event_size; + event_buf += event_size; } } void GeteventOpenDevice() { - std::unique_ptr device(opendir(kDevicePath), closedir); - if (!device) return; - - dirent* entry; - while ((entry = readdir(device.get()))) { - if (entry->d_name[0] == '.') continue; - std::string devname(kDevicePath); - devname += '/'; - devname += entry->d_name; - GeteventOpenDevice(devname); + inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (inotify_fd < 0) { + PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath; + } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE) < 0) { + PLOG(WARNING) << "Could not add watch for " << kDevicePath; + ::close(inotify_fd); + inotify_fd = -1; } + + std::unique_ptr device(opendir(kDevicePath), closedir); + if (device) { + dirent* entry; + while ((entry = readdir(device.get()))) { + if (entry->d_name[0] == '.') continue; + std::string devname(kDevicePath); + devname += '/'; + devname += entry->d_name; + GeteventOpenDevice(devname); + } + } + + if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler); } void AddServiceKeycodes(Service* svc) {