aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXihua Chen <xihua.chen@intel.com>2018-01-12 13:42:18 +0800
committerMichael Bestas <mkbestas@lineageos.org>2019-04-04 21:52:00 +0300
commit8f693495e8db9cb3b966ccf17c2e086684f81e37 (patch)
treec5a3af92ac803ecf9af74b9dbe79da1a2b8c5b37
parent232ba3f87cb06235feba5c2abfb0578886f0ea54 (diff)
downloadandroid_bootable_recovery-8f693495e8db9cb3b966ccf17c2e086684f81e37.tar.gz
android_bootable_recovery-8f693495e8db9cb3b966ccf17c2e086684f81e37.tar.bz2
android_bootable_recovery-8f693495e8db9cb3b966ccf17c2e086684f81e37.zip
minui: Support input device hotplug in recovery mode.
In the old code, the recovery only enumerated the input devices at the startup, and read the input events from these devices. So if a USB input device is probed after the recovery startup, then the recovery can't read the events from this device. This patch use inotify to monitor /dev/input for new added input device, then support input device hotplug in recovery mode. Bug: 111847510 Test: can use USB keyboard hotplugged in recovery mode Change-Id: I7e7dcbd619d3c66a2f40a43418f5dac6a50c859e Signed-off-by: Liu Shuo A <shuo.a.liu@intel.com> Signed-off-by: Ming Tan <ming.tan@intel.com>
-rw-r--r--minui/events.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/minui/events.cpp b/minui/events.cpp
index 39cb4e1c..3db58aef 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
+#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -40,7 +41,9 @@ struct fd_info {
ev_callback cb;
};
+static ev_callback saved_input_cb;
static int g_epoll_fd;
+static int g_inotify_fd;
static epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
static int npolledevents;
@@ -54,12 +57,87 @@ static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
}
+static int inotify_cb(int fd, __unused uint32_t epevents) {
+ struct inotify_event* pevent;
+ char* buf;
+ DIR* dir;
+ size_t event_len;
+ size_t offset;
+
+ if (saved_input_cb == nullptr) return -1;
+
+ // The inotify will put one or several complete events.
+ // Should not read part of one event.
+ int ret = ioctl(fd, FIONREAD, &event_len);
+ if (ret != 0) return -1;
+
+ dir = opendir("/dev/input");
+ if (dir == nullptr) return -1;
+
+ buf = (char*)malloc(event_len);
+ if (buf == nullptr) {
+ closedir(dir);
+ return -1;
+ }
+
+ ret = read(fd, buf, event_len);
+ if (ret != (int)event_len) {
+ free(buf);
+ closedir(dir);
+ return -1;
+ }
+
+ offset = 0;
+ while (offset < event_len) {
+ pevent = (struct inotify_event*)(buf + offset);
+ if (offset + sizeof(inotify_event) + pevent->len > event_len) {
+ // The pevent->len is too large and buffer will over flow.
+ // In general, should not happen, just make more stable.
+ free(buf);
+ closedir(dir);
+ return -1;
+ }
+ offset += sizeof(inotify_event) + pevent->len;
+
+ pevent->name[pevent->len] = '\0';
+ if (strncmp(pevent->name, "event", 5)) continue;
+
+ int dfd = openat(dirfd(dir), pevent->name, O_RDONLY);
+ if (dfd == -1) break;
+
+ // Read the evbits of the input device.
+ unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
+ if (ioctl(dfd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
+ close(dfd);
+ continue;
+ }
+ // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed.
+ if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
+ close(dfd);
+ continue;
+ }
+
+ // Only add, we assume the user will not plug out and plug in USB device again and again :)
+ ev_add_fd(dfd, saved_input_cb);
+ }
+
+ free(buf);
+ closedir(dir);
+ return 0;
+}
+
int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
if (g_epoll_fd == -1) {
return -1;
}
+ g_inotify_fd = inotify_init();
+ if (g_inotify_fd >= 0) {
+ inotify_add_watch(g_inotify_fd, "/dev/input", IN_CREATE);
+ ev_add_fd(g_inotify_fd, inotify_cb);
+ }
+
bool epollctlfail = false;
DIR* dir = opendir("/dev/input");
if (dir != nullptr) {
@@ -117,6 +195,8 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
return -1;
}
+ saved_input_cb = input_cb;
+
return 0;
}
@@ -149,6 +229,7 @@ void ev_exit(void) {
}
ev_misc_count = 0;
ev_dev_count = 0;
+ saved_input_cb = nullptr;
close(g_epoll_fd);
}