Merge "libbase: add host properties support."
diff --git a/adb/Android.bp b/adb/Android.bp
index 1f41e4f..553473f 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -96,6 +96,7 @@
     "adb_io.cpp",
     "adb_listeners.cpp",
     "adb_trace.cpp",
+    "adb_unique_fd.cpp",
     "adb_utils.cpp",
     "fdevent.cpp",
     "services.cpp",
@@ -276,6 +277,7 @@
 cc_library_static {
     name: "libadbd",
     defaults: ["adb_defaults"],
+    recovery_available: true,
 
     // libminadbd wants both, for some reason.
     compile_multilib: "both",
@@ -302,6 +304,7 @@
 
     // adbd must be static, as it is copied into the recovery image.
     static_executable: true,
+    recovery_available: true,
 
     srcs: [
         "daemon/main.cpp",
diff --git a/adb/adb_unique_fd.cpp b/adb/adb_unique_fd.cpp
new file mode 100644
index 0000000..2079be1
--- /dev/null
+++ b/adb/adb_unique_fd.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_unique_fd.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+#if !defined(_WIN32)
+bool Pipe(unique_fd* read, unique_fd* write, int flags) {
+    int pipefd[2];
+#if !defined(__APPLE__)
+    if (pipe2(pipefd, flags) != 0) {
+        return false;
+    }
+#else
+    // Darwin doesn't have pipe2. Implement it ourselves.
+    if (flags != 0 && (flags & ~(O_CLOEXEC | O_NONBLOCK)) != 0) {
+        errno = EINVAL;
+        return false;
+    }
+
+    if (pipe(pipefd) != 0) {
+        return false;
+    }
+
+    if (flags & O_CLOEXEC) {
+        if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 ||
+            fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
+            adb_close(pipefd[0]);
+            adb_close(pipefd[1]);
+            return false;
+        }
+    }
+
+    if (flags & O_NONBLOCK) {
+        if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 ||
+            fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
+            adb_close(pipefd[0]);
+            adb_close(pipefd[1]);
+            return false;
+        }
+    }
+#endif
+
+    read->reset(pipefd[0]);
+    write->reset(pipefd[1]);
+    return true;
+}
+#endif
diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h
index d1dc9d1..be63262 100644
--- a/adb/adb_unique_fd.h
+++ b/adb/adb_unique_fd.h
@@ -29,44 +29,5 @@
 using unique_fd = android::base::unique_fd_impl<AdbCloser>;
 
 #if !defined(_WIN32)
-inline bool Pipe(unique_fd* read, unique_fd* write, int flags = 0) {
-    int pipefd[2];
-#if !defined(__APPLE__)
-    if (pipe2(pipefd, flags) != 0) {
-        return false;
-    }
-#else
-    // Darwin doesn't have pipe2. Implement it ourselves.
-    if (flags != 0 && (flags & ~(O_CLOEXEC | O_NONBLOCK)) != 0) {
-        errno = EINVAL;
-        return false;
-    }
-
-    if (pipe(pipefd) != 0) {
-        return false;
-    }
-
-    if (flags & O_CLOEXEC) {
-        if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 ||
-            fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
-            close(pipefd[0]);
-            close(pipefd[1]);
-            return false;
-        }
-    }
-
-    if (flags & O_NONBLOCK) {
-        if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 ||
-            fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
-            close(pipefd[0]);
-            close(pipefd[1]);
-            return false;
-        }
-    }
-#endif
-
-    read->reset(pipefd[0]);
-    write->reset(pipefd[1]);
-    return true;
-}
+bool Pipe(unique_fd* read, unique_fd* write, int flags = 0);
 #endif
diff --git a/base/Android.bp b/base/Android.bp
index 3e51af3..3d80d97 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -93,6 +93,7 @@
     name: "libbase",
     defaults: ["libbase_defaults"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     vndk: {
         enabled: true,
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 7c28b28..0b13662 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -17,6 +17,7 @@
 cc_library_headers {
     name: "libdebuggerd_common_headers",
     export_include_dirs: ["common/include"],
+    recovery_available: true,
 }
 
 cc_library_shared {
@@ -67,6 +68,7 @@
 cc_library_static {
     name: "libdebuggerd_handler_core",
     defaults: ["debuggerd_defaults"],
+    recovery_available: true,
     srcs: ["handler/debuggerd_handler.cpp"],
 
     header_libs: [
@@ -88,6 +90,7 @@
 cc_library_static {
     name: "libdebuggerd_handler",
     defaults: ["debuggerd_defaults"],
+    recovery_available: true,
     srcs: ["handler/debuggerd_fallback_nop.cpp"],
 
     whole_static_libs: [
@@ -143,6 +146,7 @@
 cc_library_static {
     name: "libdebuggerd",
     defaults: ["debuggerd_defaults"],
+    recovery_available: true,
 
     srcs: [
         "libdebuggerd/backtrace.cpp",
diff --git a/demangle/Android.bp b/demangle/Android.bp
index cf6abfd..fd79cf8 100644
--- a/demangle/Android.bp
+++ b/demangle/Android.bp
@@ -36,6 +36,7 @@
     name: "libdemangle",
     defaults: ["libdemangle_defaults"],
     vendor_available: true,
+    recovery_available: true,
 
     srcs: [
         "Demangler.cpp",
diff --git a/diagnose_usb/Android.bp b/diagnose_usb/Android.bp
index a7ecf37..6bee28c 100644
--- a/diagnose_usb/Android.bp
+++ b/diagnose_usb/Android.bp
@@ -2,6 +2,7 @@
     name: "libdiagnose_usb",
     cflags: ["-Wall", "-Wextra", "-Werror"],
     host_supported: true,
+    recovery_available: true,
     target: {
         windows: {
             enabled: true,
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6493262..5aa87d9 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -316,7 +316,8 @@
 static int show_help() {
     // clang-format off
     fprintf(stdout,
-/*           1234567890123456789012345678901234567890123456789012345678901234567890123456 */
+//                    1         2         3         4         5         6         7         8
+//           12345678901234567890123456789012345678901234567890123456789012345678901234567890
             "usage: fastboot [OPTION...] COMMAND...\n"
             "\n"
             "flashing:\n"
@@ -324,8 +325,8 @@
             " flashall                   Flash all partitions from $ANDROID_PRODUCT_OUT.\n"
             "                            On A/B devices, flashed slot is set as active.\n"
             "                            Secondary images may be flashed to inactive slot.\n"
-            " flash PARTITION [FILENAME]\n"
-            "                            Flash given partition only.\n"
+            " flash PARTITION [FILENAME] Flash given partition, using the image from\n"
+            "                            $ANDROID_PRODUCT_OUT if no filename is given.\n"
             "\n"
             "basics:\n"
             " devices [-l]               List devices in bootloader (-l: with device paths).\n"
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 05dba15..bc3b04b 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -33,6 +33,7 @@
 cc_library_static {
     name: "libfs_mgr",
     defaults: ["fs_mgr_defaults"],
+    recovery_available: true,
     export_include_dirs: ["include"],
     include_dirs: ["system/vold"],
     srcs: [
@@ -79,6 +80,7 @@
 cc_library_static {
     name: "libfstab",
     vendor_available: true,
+    recovery_available: true,
     defaults: ["fs_mgr_defaults"],
     srcs: [
         "fs_mgr_fstab.cpp",
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..5652c5e 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);
@@ -730,9 +749,13 @@
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
     am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
     am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
+    Keychords keychords;
     am.QueueBuiltinAction(
-        [&epoll](const BuiltinArguments& args) -> Result<Success> {
-            KeychordInit(&epoll);
+        [&epoll, &keychords](const BuiltinArguments& args) -> Result<Success> {
+            for (const auto& svc : ServiceList::GetInstance()) {
+                svc->set_keychord_id(keychords.GetId(svc->keycodes()));
+            }
+            keychords.Start(&epoll, HandleKeychord);
             return Success();
         },
         "KeychordInit");
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 418cdeb..9aa8b2a 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -33,121 +33,89 @@
 #include <vector>
 
 #include <android-base/logging.h>
-#include <android-base/properties.h>
-
-#include "init.h"
-#include "service.h"
 
 namespace android {
 namespace init {
 
-namespace {
+Keychords::Keychords() : epoll_(nullptr), count_(0), inotify_fd_(-1) {}
 
-int keychords_count;
-Epoll* epoll;
-
-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))));
-        }
+Keychords::~Keychords() noexcept {
+    if (inotify_fd_ >= 0) {
+        epoll_->UnregisterHandler(inotify_fd_);
+        ::close(inotify_fd_);
     }
+    while (!registration_.empty()) GeteventCloseDevice(registration_.begin()->first);
+}
 
-    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))));
-    }
+Keychords::Mask::Mask(size_t bit) : bits_((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
 
-    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";
-
-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";
-        }
+void Keychords::Mask::SetBit(size_t bit, bool value) {
+    auto idx = bit / (kBitsPerByte * sizeof(mask_t));
+    if (idx >= bits_.size()) return;
+    if (value) {
+        bits_[idx] |= mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t)));
     } else {
-        LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
+        bits_[idx] &= ~(mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t))));
     }
 }
 
-void KeychordLambdaCheck() {
-    for (auto& e : keychord_entries) {
-        bool found = true;
+bool Keychords::Mask::GetBit(size_t bit) const {
+    auto idx = bit / (kBitsPerByte * sizeof(mask_t));
+    return bits_[idx] & (mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t))));
+}
+
+size_t Keychords::Mask::bytesize() const {
+    return bits_.size() * sizeof(mask_t);
+}
+
+void* Keychords::Mask::data() {
+    return bits_.data();
+}
+
+size_t Keychords::Mask::size() const {
+    return bits_.size() * sizeof(mask_t) * kBitsPerByte;
+}
+
+void Keychords::Mask::resize(size_t bit) {
+    auto idx = bit / (kBitsPerByte * sizeof(mask_t));
+    if (idx >= bits_.size()) {
+        bits_.resize(idx + 1, 0);
+    }
+}
+
+Keychords::Mask::operator bool() const {
+    for (size_t i = 0; i < bits_.size(); ++i) {
+        if (bits_[i]) return true;
+    }
+    return false;
+}
+
+Keychords::Mask Keychords::Mask::operator&(const Keychords::Mask& rval) const {
+    auto len = std::min(bits_.size(), rval.bits_.size());
+    Keychords::Mask ret;
+    ret.bits_.resize(len);
+    for (size_t i = 0; i < len; ++i) {
+        ret.bits_[i] = bits_[i] & rval.bits_[i];
+    }
+    return ret;
+}
+
+void Keychords::Mask::operator|=(const Keychords::Mask& rval) {
+    auto len = rval.bits_.size();
+    bits_.resize(len);
+    for (size_t i = 0; i < len; ++i) {
+        bits_[i] |= rval.bits_[i];
+    }
+}
+
+Keychords::Entry::Entry(const std::vector<int>& keycodes, int id)
+    : keycodes(keycodes), id(id), notified(false) {}
+
+void Keychords::LambdaCheck() {
+    for (auto& e : entries_) {
+        auto found = true;
         for (auto& code : e.keycodes) {
-            if (!keychord_current.GetBit(code)) {
+            if (!current_.GetBit(code)) {
                 e.notified = false;
                 found = false;
                 break;
@@ -156,27 +124,27 @@
         if (!found) continue;
         if (e.notified) continue;
         e.notified = true;
-        HandleKeychord(e.id);
+        handler_(e.id);
     }
 }
 
-void KeychordLambdaHandler(int fd) {
+void Keychords::LambdaHandler(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();
+    current_.SetBit(event.code, event.value);
+    LambdaCheck();
 }
 
-bool KeychordGeteventEnable(int fd) {
-    static bool EviocsmaskSupported = true;
-
+bool Keychords::GeteventEnable(int fd) {
     // 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);
+        Keychords::Mask mask(EV_KEY);
         mask.SetBit(EV_KEY);
         input_mask msg = {};
         msg.type = EV_SYN;
@@ -187,21 +155,23 @@
             EviocsmaskSupported = false;
         }
     }
+#endif
 
-    KeychordMask mask;
-    for (auto& e : keychord_entries) {
+    Keychords::Mask mask;
+    for (auto& e : entries_) {
         for (auto& code : e.keycodes) {
             mask.resize(code);
             mask.SetBit(code);
         }
     }
 
-    keychord_current.resize(mask.size());
-    KeychordMask available(mask.size());
+    current_.resize(mask.size());
+    Keychords::Mask available(mask.size());
     auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
     if (res == -1) return false;
     if (!(available & mask)) return false;
 
+#ifdef EVIOCSMASK
     if (EviocsmaskSupported) {
         input_mask msg = {};
         msg.type = EV_KEY;
@@ -209,46 +179,45 @@
         msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
         ::ioctl(fd, EVIOCSMASK, &msg);
     }
+#endif
 
-    KeychordMask set(mask.size());
+    Keychords::Mask set(mask.size());
     res = ::ioctl(fd, EVIOCGKEY(res), set.data());
     if (res > 0) {
-        keychord_current |= mask & available & set;
-        KeychordLambdaCheck();
+        current_ |= mask & available & set;
+        LambdaCheck();
     }
-    epoll->RegisterHandler(fd, [fd]() { KeychordLambdaHandler(fd); });
+    epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
     return true;
 }
 
-void GeteventOpenDevice(const std::string& device) {
-    if (keychord_registration.count(device)) return;
+void Keychords::GeteventOpenDevice(const std::string& device) {
+    if (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;
         return;
     }
-    if (!KeychordGeteventEnable(fd)) {
+    if (!GeteventEnable(fd)) {
         ::close(fd);
     } else {
-        keychord_registration.emplace(device, fd);
+        registration_.emplace(device, fd);
     }
 }
 
-void GeteventCloseDevice(const std::string& device) {
-    auto it = keychord_registration.find(device);
-    if (it == keychord_registration.end()) return;
+void Keychords::GeteventCloseDevice(const std::string& device) {
+    auto it = registration_.find(device);
+    if (it == registration_.end()) return;
     auto fd = (*it).second;
-    epoll->UnregisterHandler(fd);
-    keychord_registration.erase(it);
+    epoll_->UnregisterHandler(fd);
+    registration_.erase(it);
     ::close(fd);
 }
 
-int inotify_fd = -1;
+void Keychords::InotifyHandler() {
+    unsigned char buf[512];  // History shows 32-64 bytes typical
 
-void InotifyHandler() {
-    unsigned char buf[512];
-
-    auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
+    auto res = TEMP_FAILURE_RETRY(::read(inotify_fd_, buf, sizeof(buf)));
     if (res < 0) {
         PLOG(WARNING) << "could not get event";
         return;
@@ -274,14 +243,15 @@
     }
 }
 
-void GeteventOpenDevice() {
-    inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
-    if (inotify_fd < 0) {
+void Keychords::GeteventOpenDevice() {
+    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 | IN_ONLYDIR) < 0) {
+    } else if (::inotify_add_watch(inotify_fd_, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) <
+               0) {
         PLOG(WARNING) << "Could not add watch for " << kDevicePath;
-        ::close(inotify_fd);
-        inotify_fd = -1;
+        ::close(inotify_fd_);
+        inotify_fd_ = -1;
     }
 
     std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
@@ -296,27 +266,22 @@
         }
     }
 
-    if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler);
+    if (inotify_fd_ >= 0) {
+        epoll_->RegisterHandler(inotify_fd_, [this]() { this->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);
+int Keychords::GetId(const std::vector<int>& keycodes) {
+    if (keycodes.empty()) return 0;
+    ++count_;
+    entries_.emplace_back(Entry(keycodes, count_));
+    return count_;
 }
 
-}  // namespace
-
-void KeychordInit(Epoll* init_epoll) {
-    epoll = init_epoll;
-    for (const auto& service : ServiceList::GetInstance()) {
-        AddServiceKeycodes(service.get());
-    }
-    if (keychords_count) GeteventOpenDevice();
+void Keychords::Start(Epoll* epoll, std::function<void(int)> handler) {
+    epoll_ = epoll;
+    handler_ = handler;
+    if (count_) GeteventOpenDevice();
 }
 
 }  // namespace init
diff --git a/init/keychords.h b/init/keychords.h
index f3aecbb..74a9195 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -17,12 +17,84 @@
 #ifndef _INIT_KEYCHORDS_H_
 #define _INIT_KEYCHORDS_H_
 
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+
 #include "epoll.h"
 
 namespace android {
 namespace init {
 
-void KeychordInit(Epoll* init_epoll);
+class Keychords {
+  public:
+    Keychords();
+    Keychords(const Keychords&) = delete;
+    Keychords(Keychords&&) = delete;
+    Keychords& operator=(const Keychords&) = delete;
+    Keychords& operator=(Keychords&&) = delete;
+    ~Keychords() noexcept;
+
+    int GetId(const std::vector<int>& keycodes);
+    void Start(Epoll* epoll, std::function<void(int)> handler);
+
+  private:
+    // Bit management
+    class Mask {
+      public:
+        explicit Mask(size_t bit = 0);
+
+        void SetBit(size_t bit, bool value = true);
+        bool GetBit(size_t bit) const;
+
+        size_t bytesize() const;
+        void* data();
+        size_t size() const;
+        void resize(size_t bit);
+
+        operator bool() const;
+        Mask operator&(const Mask& rval) const;
+        void operator|=(const Mask& rval);
+
+      private:
+        typedef unsigned int mask_t;
+        static constexpr size_t kBitsPerByte = 8;
+
+        std::vector<mask_t> bits_;
+    };
+
+    struct Entry {
+        Entry(const std::vector<int>& keycodes, int id);
+
+        const std::vector<int> keycodes;
+        const int id;
+        bool notified;
+    };
+
+    static constexpr char kDevicePath[] = "/dev/input";
+
+    void LambdaCheck();
+    void LambdaHandler(int fd);
+    void InotifyHandler();
+
+    bool GeteventEnable(int fd);
+    void GeteventOpenDevice(const std::string& device);
+    void GeteventOpenDevice();
+    void GeteventCloseDevice(const std::string& device);
+
+    Epoll* epoll_;
+    std::function<void(int)> handler_;
+
+    std::map<std::string, int> registration_;
+
+    int count_;
+    std::vector<Entry> entries_;
+
+    Mask current_;
+
+    int inotify_fd_;
+};
 
 }  // namespace init
 }  // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index c9ed87f..a698735 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>
@@ -543,10 +544,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();
diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp
index 8a2afea..4ab439d 100644
--- a/libasyncio/Android.bp
+++ b/libasyncio/Android.bp
@@ -27,6 +27,7 @@
     name: "libasyncio",
     defaults: ["libasyncio_defaults"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     srcs: [
         "AsyncIO.cpp",
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 0f93dd0..b4bf35f 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -58,6 +58,7 @@
 cc_library {
     name: "libbacktrace",
     vendor_available: false,
+    recovery_available: true,
     vndk: {
         enabled: true,
         support_system_process: true,
@@ -102,8 +103,6 @@
             include_dirs: [
                 "art/runtime",
             ],
-
-            header_libs: ["jni_headers"],
         },
         android: {
             static_libs: ["libasync_safe"],
@@ -112,6 +111,10 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_shared_libs: ["libdexfile"],
         },
+        recovery: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_shared_libs: ["libdexfile"],
+        },
     },
     whole_static_libs: ["libdemangle"],
 }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 1e3d379..f78a31f 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -46,6 +46,7 @@
 
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
 #include <android-base/unique_fd.h>
 #include <cutils/atomic.h>
 #include <cutils/threads.h>
@@ -1186,49 +1187,45 @@
   ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
 }
 
-static const char* CopySharedLibrary() {
-#if defined(__LP64__)
-  const char* lib_name = "lib64";
-#else
-  const char* lib_name = "lib";
-#endif
+static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
+  std::string system_dir;
 
 #if defined(__BIONIC__)
-  const char* tmp_so_name = "/data/local/tmp/libbacktrace_test.so";
-  std::string cp_cmd = android::base::StringPrintf("cp /system/%s/libbacktrace_test.so %s",
-                                                   lib_name, tmp_so_name);
+  system_dir = "/system/lib";
 #else
-  const char* tmp_so_name = "/tmp/libbacktrace_test.so";
-  if (getenv("ANDROID_HOST_OUT") == NULL) {
-    fprintf(stderr, "ANDROID_HOST_OUT not set, make sure you run lunch.");
-    return nullptr;
-  }
-  std::string cp_cmd = android::base::StringPrintf("cp %s/%s/libbacktrace_test.so %s",
-                                                   getenv("ANDROID_HOST_OUT"), lib_name,
-                                                   tmp_so_name);
+  const char* host_out_env = getenv("ANDROID_HOST_OUT");
+  ASSERT_TRUE(host_out_env != nullptr);
+  system_dir = std::string(host_out_env) + "/lib";
 #endif
 
-  // Copy the shared so to a tempory directory.
-  system(cp_cmd.c_str());
+#if defined(__LP64__)
+  system_dir += "64";
+#endif
 
-  return tmp_so_name;
+  *tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
+  std::string cp_cmd =
+      android::base::StringPrintf("cp %s/libbacktrace_test.so %s", system_dir.c_str(), tmp_dir);
+
+  // Copy the shared so to a tempory directory.
+  ASSERT_EQ(0, system(cp_cmd.c_str()));
 }
 
 TEST(libbacktrace, check_unreadable_elf_local) {
-  const char* tmp_so_name = CopySharedLibrary();
-  ASSERT_TRUE(tmp_so_name != nullptr);
+  TemporaryDir td;
+  std::string tmp_so_name;
+  ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
 
   struct stat buf;
-  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  ASSERT_TRUE(stat(tmp_so_name.c_str(), &buf) != -1);
   uint64_t map_size = buf.st_size;
 
-  int fd = open(tmp_so_name, O_RDONLY);
+  int fd = open(tmp_so_name.c_str(), O_RDONLY);
   ASSERT_TRUE(fd != -1);
 
   void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
   ASSERT_TRUE(map != MAP_FAILED);
   close(fd);
-  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+  ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
 
   std::vector<std::string> found_functions;
   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
@@ -1256,32 +1253,33 @@
 }
 
 TEST(libbacktrace, check_unreadable_elf_remote) {
-  const char* tmp_so_name = CopySharedLibrary();
-  ASSERT_TRUE(tmp_so_name != nullptr);
+  TemporaryDir td;
+  std::string tmp_so_name;
+  ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
 
   g_ready = 0;
 
   struct stat buf;
-  ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+  ASSERT_TRUE(stat(tmp_so_name.c_str(), &buf) != -1);
   uint64_t map_size = buf.st_size;
 
   pid_t pid;
   if ((pid = fork()) == 0) {
-    int fd = open(tmp_so_name, O_RDONLY);
+    int fd = open(tmp_so_name.c_str(), O_RDONLY);
     if (fd == -1) {
-      fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name, strerror(errno));
-      unlink(tmp_so_name);
+      fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name.c_str(), strerror(errno));
+      unlink(tmp_so_name.c_str());
       exit(0);
     }
 
     void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
     if (map == MAP_FAILED) {
       fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
-      unlink(tmp_so_name);
+      unlink(tmp_so_name.c_str());
       exit(0);
     }
     close(fd);
-    if (unlink(tmp_so_name) == -1) {
+    if (unlink(tmp_so_name.c_str()) == -1) {
       fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
       exit(0);
     }
@@ -1394,11 +1392,13 @@
 typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
 
 TEST(libbacktrace, unwind_through_unreadable_elf_local) {
-  const char* tmp_so_name = CopySharedLibrary();
-  ASSERT_TRUE(tmp_so_name != nullptr);
-  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  TemporaryDir td;
+  std::string tmp_so_name;
+  ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
+
+  void* lib_handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
   ASSERT_TRUE(lib_handle != nullptr);
-  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+  ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
 
   test_func_t test_func;
   test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
@@ -1411,11 +1411,13 @@
 }
 
 TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
-  const char* tmp_so_name = CopySharedLibrary();
-  ASSERT_TRUE(tmp_so_name != nullptr);
-  void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+  TemporaryDir td;
+  std::string tmp_so_name;
+  ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
+
+  void* lib_handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
   ASSERT_TRUE(lib_handle != nullptr);
-  ASSERT_TRUE(unlink(tmp_so_name) != -1);
+  ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
 
   test_func_t test_func;
   test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
@@ -1444,7 +1446,8 @@
 
     size_t frame_num;
     if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
-                                 &frame_num)) {
+                                 &frame_num) &&
+        frame_num != 0) {
       VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uint64_t>(test_func), frame_num);
       done = true;
     }
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index 47de12a..e47560f 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -17,6 +17,7 @@
 cc_library {
     name: "libcrypto_utils",
     vendor_available: true,
+    recovery_available: true,
     vndk: {
         enabled: true,
     },
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index f3593ff..b388e95 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -2,6 +2,7 @@
     name: "libkeyutils",
     cflags: ["-Werror"],
     defaults: ["linux_bionic_supported"],
+    recovery_available: true,
     export_include_dirs: ["include/"],
     local_include_dirs: ["include/"],
     srcs: ["keyutils.cpp"],
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
index d776b3d..15f03d0 100644
--- a/libprocinfo/Android.bp
+++ b/libprocinfo/Android.bp
@@ -27,6 +27,7 @@
     name: "libprocinfo",
     defaults: ["libprocinfo_defaults"],
     vendor_available: true,
+    recovery_available: true,
     vndk: {
         enabled: true,
     },
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index b894656..c7c089f 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -3,6 +3,7 @@
 cc_library {
     name: "libsparse",
     host_supported: true,
+    recovery_available: true,
     unique_host_soname: true,
     srcs: [
         "backed_block.c",
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 435ed94..26be64d 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -38,6 +38,7 @@
 cc_library {
     name: "libunwindstack",
     vendor_available: true,
+    recovery_available: true,
     vndk: {
         enabled: true,
         support_system_process: true,
@@ -94,6 +95,14 @@
             ],
             exclude_shared_libs: ["libdexfile"],
         },
+        recovery: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_srcs: [
+                "DexFile.cpp",
+                "DexFiles.cpp",
+            ],
+            exclude_shared_libs: ["libdexfile"],
+        },
     },
 
     arch: {
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index d4ba4f4..c378646 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -12,6 +12,7 @@
 cc_library {
     name: "liblogwrap",
     defaults: ["logwrapper_defaults"],
+    recovery_available: true,
     srcs: ["logwrap.c"],
     shared_libs: [
         "libcutils",
diff --git a/qemu_pipe/Android.bp b/qemu_pipe/Android.bp
index 93c347b..c6bda4a 100644
--- a/qemu_pipe/Android.bp
+++ b/qemu_pipe/Android.bp
@@ -3,6 +3,7 @@
 cc_library_static {
     name: "libqemu_pipe",
     vendor_available: true,
+    recovery_available: true,
     sanitize: {
         misc_undefined: ["integer"],
     },