Merge "init: refactor keychord for testing" am: 16dd3582b7
am: 334b4c843e

Change-Id: I8ccebe1a9cd1dd2c6386f4a641a3eb3ea3c13fc1
diff --git a/init/Android.bp b/init/Android.bp
index 63f3fca..a3083c1 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -232,6 +232,8 @@
         "action_parser.cpp",
         "capabilities.cpp",
         "descriptors.cpp",
+        "epoll.cpp",
+        "keychords.cpp",
         "import_parser.cpp",
         "host_init_parser.cpp",
         "host_init_stubs.cpp",
diff --git a/init/init.cpp b/init/init.cpp
index fd9a90c..43242b2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -553,6 +553,25 @@
     }
 }
 
+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") {
+        Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
+        if (svc) {
+            LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
+            if (auto result = svc->Start(); !result) {
+                LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
+                           << ": " << result.error();
+            }
+        } else {
+            LOG(ERROR) << "Service for keychord " << id << " not found";
+        }
+    } else {
+        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
+    }
+}
+
 int main(int argc, char** argv) {
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
@@ -732,7 +751,10 @@
     am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
     am.QueueBuiltinAction(
         [&epoll](const BuiltinArguments& args) -> Result<Success> {
-            KeychordInit(&epoll);
+            for (const auto& svc : ServiceList::GetInstance()) {
+                svc->set_keychord_id(GetKeychordId(svc->keycodes()));
+            }
+            KeychordInit(&epoll, HandleKeychord);
             return Success();
         },
         "KeychordInit");
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 418cdeb..1a8f2ae 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -33,10 +33,6 @@
 #include <vector>
 
 #include <android-base/logging.h>
-#include <android-base/properties.h>
-
-#include "init.h"
-#include "service.h"
 
 namespace android {
 namespace init {
@@ -45,6 +41,7 @@
 
 int keychords_count;
 Epoll* epoll;
+std::function<void(int)> handle_keychord;
 
 struct KeychordEntry {
     const std::vector<int> keycodes;
@@ -124,25 +121,6 @@
 
 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", "");
-    if (adb_enabled == "running") {
-        Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
-        if (svc) {
-            LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
-            if (auto result = svc->Start(); !result) {
-                LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
-                           << ": " << result.error();
-            }
-        } else {
-            LOG(ERROR) << "Service for keychord " << id << " not found";
-        }
-    } else {
-        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
-    }
-}
-
 void KeychordLambdaCheck() {
     for (auto& e : keychord_entries) {
         bool found = true;
@@ -156,7 +134,7 @@
         if (!found) continue;
         if (e.notified) continue;
         e.notified = true;
-        HandleKeychord(e.id);
+        handle_keychord(e.id);
     }
 }
 
@@ -169,12 +147,12 @@
 }
 
 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;
 
+#ifdef EVIOCSMASK
+    static auto EviocsmaskSupported = true;
     if (EviocsmaskSupported) {
         KeychordMask mask(EV_KEY);
         mask.SetBit(EV_KEY);
@@ -187,6 +165,7 @@
             EviocsmaskSupported = false;
         }
     }
+#endif
 
     KeychordMask mask;
     for (auto& e : keychord_entries) {
@@ -202,6 +181,7 @@
     if (res == -1) return false;
     if (!(available & mask)) return false;
 
+#ifdef EVIOCSMASK
     if (EviocsmaskSupported) {
         input_mask msg = {};
         msg.type = EV_KEY;
@@ -209,6 +189,7 @@
         msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
         ::ioctl(fd, EVIOCSMASK, &msg);
     }
+#endif
 
     KeychordMask set(mask.size());
     res = ::ioctl(fd, EVIOCGKEY(res), set.data());
@@ -299,23 +280,18 @@
     if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler);
 }
 
-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(Epoll* init_epoll) {
+int GetKeychordId(const std::vector<int>& keycodes) {
+    if (keycodes.empty()) return 0;
+    ++keychords_count;
+    keychord_entries.emplace_back(KeychordEntry(keycodes, keychords_count));
+    return keychords_count;
+}
+
+void KeychordInit(Epoll* init_epoll, std::function<void(int)> handler) {
     epoll = init_epoll;
-    for (const auto& service : ServiceList::GetInstance()) {
-        AddServiceKeycodes(service.get());
-    }
+    handle_keychord = handler;
     if (keychords_count) GeteventOpenDevice();
 }
 
diff --git a/init/keychords.h b/init/keychords.h
index f3aecbb..f273c8c 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -17,12 +17,16 @@
 #ifndef _INIT_KEYCHORDS_H_
 #define _INIT_KEYCHORDS_H_
 
+#include <functional>
+#include <vector>
+
 #include "epoll.h"
 
 namespace android {
 namespace init {
 
-void KeychordInit(Epoll* init_epoll);
+void KeychordInit(Epoll* init_epoll, std::function<void(int)> handler);
+int GetKeychordId(const std::vector<int>& keycodes);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index 0e08d9b..5778a93 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -18,6 +18,7 @@
 
 #include <fcntl.h>
 #include <inttypes.h>
+#include <linux/input.h>
 #include <linux/securebits.h>
 #include <sched.h>
 #include <sys/mount.h>
@@ -544,10 +545,13 @@
 Result<Success> Service::ParseKeycodes(const std::vector<std::string>& args) {
     for (std::size_t i = 1; i < args.size(); i++) {
         int code;
-        if (ParseInt(args[i], &code)) {
+        if (ParseInt(args[i], &code, 0, KEY_MAX)) {
+            for (auto& key : keycodes_) {
+                if (key == code) return Error() << "duplicate keycode: " << args[i];
+            }
             keycodes_.emplace_back(code);
         } else {
-            LOG(WARNING) << "ignoring invalid keycode: " << args[i];
+            return Error() << "invalid keycode: " << args[i];
         }
     }
     return Success();