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
This commit is contained in:
parent
86dade8f6f
commit
44692de855
1 changed files with 68 additions and 10 deletions
|
|
@ -20,12 +20,14 @@
|
|||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -118,6 +120,8 @@ KeychordMask keychord_current;
|
|||
|
||||
constexpr char kDevicePath[] = "/dev/input";
|
||||
|
||||
std::map<std::string, int> 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<size_t>(res) >= sizeof(inotify_event)) {
|
||||
auto event = reinterpret_cast<inotify_event*>(event_buf);
|
||||
auto event_size = sizeof(inotify_event) + event->len;
|
||||
if (static_cast<size_t>(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<DIR, decltype(&closedir)> 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<DIR, decltype(&closedir)> 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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue