Merge changes from topic "b/64114943"

* changes:
  init: switch from /dev/keychord to /dev/input/
  init: use std::function for epoll handling
diff --git a/init/init.cpp b/init/init.cpp
index 0d5690b..54bbb4b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -31,6 +31,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <map>
+#include <memory>
+#include <optional>
+
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -43,9 +47,6 @@
 #include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 
-#include <memory>
-#include <optional>
-
 #include "action_parser.h"
 #include "import_parser.h"
 #include "init_first_stage.h"
@@ -130,12 +131,31 @@
     }
 }
 
-void register_epoll_handler(int fd, void (*fn)()) {
+static std::map<int, std::function<void()>> epoll_handlers;
+
+void register_epoll_handler(int fd, std::function<void()> handler) {
+    auto[it, inserted] = epoll_handlers.emplace(fd, std::move(handler));
+    if (!inserted) {
+        LOG(ERROR) << "Cannot specify two epoll handlers for a given FD";
+        return;
+    }
     epoll_event ev;
     ev.events = EPOLLIN;
-    ev.data.ptr = reinterpret_cast<void*>(fn);
+    // std::map's iterators do not get invalidated until erased, so we use the pointer to the
+    // std::function in the map directly for epoll_ctl.
+    ev.data.ptr = reinterpret_cast<void*>(&it->second);
     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        PLOG(ERROR) << "epoll_ctl failed";
+        PLOG(ERROR) << "epoll_ctl failed to add fd";
+        epoll_handlers.erase(fd);
+    }
+}
+
+void unregister_epoll_handler(int fd) {
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
+        PLOG(ERROR) << "epoll_ctl failed to remove fd";
+    }
+    if (epoll_handlers.erase(fd) != 1) {
+        LOG(ERROR) << "Attempting to remove epoll handler for FD without an existing handler";
     }
 }
 
@@ -334,8 +354,8 @@
     return Success();
 }
 
-static Result<Success> keychord_init_action(const BuiltinArguments& args) {
-    keychord_init();
+static Result<Success> KeychordInitAction(const BuiltinArguments& args) {
+    KeychordInit();
     return Success();
 }
 
@@ -752,7 +772,7 @@
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
     am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
     am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
-    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
+    am.QueueBuiltinAction(KeychordInitAction, "KeychordInit");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
     // Trigger all the boot actions to get us started.
@@ -809,7 +829,7 @@
         if (nr == -1) {
             PLOG(ERROR) << "epoll_wait failed";
         } else if (nr == 1) {
-            ((void (*)()) ev.data.ptr)();
+            std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
         }
     }
 
diff --git a/init/init.h b/init/init.h
index d4a0e96..e7c4d8d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -42,7 +43,8 @@
 
 void property_changed(const std::string& name, const std::string& value);
 
-void register_epoll_handler(int fd, void (*fn)());
+void register_epoll_handler(int fd, std::function<void()> handler);
+void unregister_epoll_handler(int fd);
 
 bool start_waiting_for_property(const char *name, const char *value);
 
diff --git a/init/keychords.cpp b/init/keychords.cpp
index e686ce1..f55d2c4 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -16,13 +16,20 @@
 
 #include "keychords.h"
 
+#include <dirent.h>
 #include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
+#include <linux/input.h>
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
-#include <linux/keychord.h>
 #include <unistd.h>
 
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 
@@ -31,51 +38,87 @@
 namespace android {
 namespace init {
 
-static struct input_keychord *keychords = 0;
-static int keychords_count = 0;
-static int keychords_length = 0;
-static int keychord_fd = -1;
+namespace {
 
-void add_service_keycodes(Service* svc)
-{
-    struct input_keychord *keychord;
-    size_t i, size;
+int keychords_count;
 
-    if (!svc->keycodes().empty()) {
-        /* add a new keychord to the list */
-        size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
-        keychords = (input_keychord*) realloc(keychords, keychords_length + size);
-        if (!keychords) {
-            PLOG(ERROR) << "could not allocate keychords";
-            keychords_length = 0;
-            keychords_count = 0;
-            return;
+struct KeychordEntry {
+    const std::vector<int> keycodes;
+    bool notified;
+    int id;
+
+    KeychordEntry(const std::vector<int>& keycodes, int id)
+        : keycodes(keycodes), notified(false), id(id) {}
+};
+
+std::vector<KeychordEntry> keychord_entries;
+
+// Bit management
+class KeychordMask {
+  private:
+    typedef unsigned int mask_t;
+    std::vector<mask_t> bits;
+    static constexpr size_t bits_per_byte = 8;
+
+  public:
+    explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
+
+    void SetBit(size_t bit, bool value = true) {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        if (idx >= bits.size()) return;
+        if (value) {
+            bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
+        } else {
+            bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
         }
-
-        keychord = (struct input_keychord *)((char *)keychords + keychords_length);
-        keychord->version = KEYCHORD_VERSION;
-        keychord->id = keychords_count + 1;
-        keychord->count = svc->keycodes().size();
-        svc->set_keychord_id(keychord->id);
-
-        for (i = 0; i < svc->keycodes().size(); i++) {
-            keychord->keycodes[i] = svc->keycodes()[i];
-        }
-        keychords_count++;
-        keychords_length += size;
-    }
-}
-
-static void handle_keychord() {
-    int ret;
-    __u16 id;
-
-    ret = read(keychord_fd, &id, sizeof(id));
-    if (ret != sizeof(id)) {
-        PLOG(ERROR) << "could not read keychord id";
-        return;
     }
 
+    bool GetBit(size_t bit) const {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
+    }
+
+    size_t bytesize() const { return bits.size() * sizeof(mask_t); }
+    void* data() { return bits.data(); }
+    size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
+    void resize(size_t bit) {
+        auto idx = bit / (bits_per_byte * sizeof(mask_t));
+        if (idx >= bits.size()) {
+            bits.resize(idx + 1, 0);
+        }
+    }
+
+    operator bool() const {
+        for (size_t i = 0; i < bits.size(); ++i) {
+            if (bits[i]) return true;
+        }
+        return false;
+    }
+
+    KeychordMask operator&(const KeychordMask& rval) const {
+        auto len = std::min(bits.size(), rval.bits.size());
+        KeychordMask ret;
+        ret.bits.resize(len);
+        for (size_t i = 0; i < len; ++i) {
+            ret.bits[i] = bits[i] & rval.bits[i];
+        }
+        return ret;
+    }
+
+    void operator|=(const KeychordMask& rval) {
+        size_t len = rval.bits.size();
+        bits.resize(len);
+        for (size_t i = 0; i < len; ++i) {
+            bits[i] |= rval.bits[i];
+        }
+    }
+};
+
+KeychordMask keychord_current;
+
+constexpr char kDevicePath[] = "/dev/input";
+
+void HandleKeychord(int id) {
     // Only handle keychords if adb is enabled.
     std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
@@ -94,32 +137,125 @@
     }
 }
 
-void keychord_init() {
+void KeychordLambdaCheck() {
+    for (auto& e : keychord_entries) {
+        bool found = true;
+        for (auto& code : e.keycodes) {
+            if (!keychord_current.GetBit(code)) {
+                e.notified = false;
+                found = false;
+                break;
+            }
+        }
+        if (!found) continue;
+        if (e.notified) continue;
+        e.notified = true;
+        HandleKeychord(e.id);
+    }
+}
+
+void KeychordLambdaHandler(int fd) {
+    input_event event;
+    auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
+    if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
+    keychord_current.SetBit(event.code, event.value);
+    KeychordLambdaCheck();
+}
+
+bool KeychordGeteventEnable(int fd) {
+    static bool EviocsmaskSupported = true;
+
+    // Make sure it is an event channel, should pass this ioctl call
+    int version;
+    if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
+
+    if (EviocsmaskSupported) {
+        KeychordMask mask(EV_KEY);
+        mask.SetBit(EV_KEY);
+        input_mask msg = {};
+        msg.type = EV_SYN;
+        msg.codes_size = mask.bytesize();
+        msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+        if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
+            PLOG(WARNING) << "EVIOCSMASK not supported";
+            EviocsmaskSupported = false;
+        }
+    }
+
+    KeychordMask mask;
+    for (auto& e : keychord_entries) {
+        for (auto& code : e.keycodes) {
+            mask.resize(code);
+            mask.SetBit(code);
+        }
+    }
+
+    keychord_current.resize(mask.size());
+    KeychordMask available(mask.size());
+    auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
+    if (res == -1) return false;
+    if (!(available & mask)) return false;
+
+    if (EviocsmaskSupported) {
+        input_mask msg = {};
+        msg.type = EV_KEY;
+        msg.codes_size = mask.bytesize();
+        msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
+        ::ioctl(fd, EVIOCSMASK, &msg);
+    }
+
+    KeychordMask set(mask.size());
+    res = ::ioctl(fd, EVIOCGKEY(res), set.data());
+    if (res > 0) {
+        keychord_current |= mask & available & set;
+        KeychordLambdaCheck();
+    }
+    register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
+    return true;
+}
+
+void GeteventOpenDevice(const std::string& device) {
+    auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
+    if (fd == -1) {
+        PLOG(ERROR) << "Can not open " << device;
+        return;
+    }
+    if (!KeychordGeteventEnable(fd)) {
+        ::close(fd);
+    }
+}
+
+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);
+    }
+}
+
+void AddServiceKeycodes(Service* svc) {
+    if (svc->keycodes().empty()) return;
+    for (auto& code : svc->keycodes()) {
+        if ((code < 0) || (code >= KEY_MAX)) return;
+    }
+    ++keychords_count;
+    keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
+    svc->set_keychord_id(keychords_count);
+}
+
+}  // namespace
+
+void KeychordInit() {
     for (const auto& service : ServiceList::GetInstance()) {
-        add_service_keycodes(service.get());
+        AddServiceKeycodes(service.get());
     }
-
-    // Nothing to do if no services require keychords.
-    if (!keychords) {
-        return;
-    }
-
-    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
-    if (keychord_fd == -1) {
-        PLOG(ERROR) << "could not open /dev/keychord";
-        return;
-    }
-
-    int ret = write(keychord_fd, keychords, keychords_length);
-    if (ret != keychords_length) {
-        PLOG(ERROR) << "could not configure /dev/keychord " << ret;
-        close(keychord_fd);
-    }
-
-    free(keychords);
-    keychords = nullptr;
-
-    register_epoll_handler(keychord_fd, handle_keychord);
+    if (keychords_count) GeteventOpenDevice();
 }
 
 }  // namespace init
diff --git a/init/keychords.h b/init/keychords.h
index 1c34098..689a3b5 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -22,8 +22,7 @@
 namespace android {
 namespace init {
 
-void add_service_keycodes(Service* svc);
-void keychord_init();
+void KeychordInit();
 
 }  // namespace init
 }  // namespace android