Merge "Remove unused using statement / host stub"
diff --git a/adb/Android.bp b/adb/Android.bp
index b9a1596..99de54e 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -222,7 +222,6 @@
 
 cc_binary_host {
     name: "adb",
-    tags: ["debug"],
 
     defaults: ["adb_defaults"],
 
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3bf281c..76ca19a 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -365,8 +365,8 @@
         switch (p->msg.arg0) {
 #if ADB_HOST
             case ADB_AUTH_TOKEN:
-                if (t->GetConnectionState() == kCsOffline) {
-                    t->SetConnectionState(kCsUnauthorized);
+                if (t->GetConnectionState() != kCsAuthorizing) {
+                    t->SetConnectionState(kCsAuthorizing);
                 }
                 send_auth_response(p->payload.data(), p->msg.data_length, t);
                 break;
@@ -1103,14 +1103,11 @@
     if (!strcmp(service, "reconnect-offline")) {
         std::string response;
         close_usb_devices([&response](const atransport* transport) {
-            switch (transport->GetConnectionState()) {
-                case kCsOffline:
-                case kCsUnauthorized:
-                    response += "reconnecting " + transport->serial_name() + "\n";
-                    return true;
-                default:
-                    return false;
+            if (!ConnectionStateIsOnline(transport->GetConnectionState())) {
+                response += "reconnecting " + transport->serial_name() + "\n";
+                return true;
             }
+            return false;
         });
         if (!response.empty()) {
             response.resize(response.size() - 1);
diff --git a/adb/adb.h b/adb/adb.h
index 1e58ee1..ede55da 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -95,16 +95,33 @@
 
 enum ConnectionState {
     kCsAny = -1,
-    kCsOffline = 0,
+
+    kCsConnecting = 0,  // Haven't received a response from the device yet.
+    kCsAuthorizing,     // Authorizing with keys from ADB_VENDOR_KEYS.
+    kCsUnauthorized,    // ADB_VENDOR_KEYS exhausted, fell back to user prompt.
+    kCsNoPerm,          // Insufficient permissions to communicate with the device.
+    kCsOffline,
+
     kCsBootloader,
     kCsDevice,
     kCsHost,
     kCsRecovery,
-    kCsNoPerm,  // Insufficient permissions to communicate with the device.
     kCsSideload,
-    kCsUnauthorized,
 };
 
+inline bool ConnectionStateIsOnline(ConnectionState state) {
+    switch (state) {
+        case kCsBootloader:
+        case kCsDevice:
+        case kCsHost:
+        case kCsRecovery:
+        case kCsSideload:
+            return true;
+        default:
+            return false;
+    }
+}
+
 void print_packet(const char* label, apacket* p);
 
 // These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index ade2623..0f4dd33 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -464,6 +464,7 @@
     std::shared_ptr<RSA> key = t->NextKey();
     if (key == nullptr) {
         // No more private keys to try, send the public key.
+        t->SetConnectionState(kCsUnauthorized);
         send_auth_publickey(t);
         return;
     }
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e476e07..39983ab 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -149,8 +149,8 @@
         " emu COMMAND              run emulator console command\n"
         "\n"
         "app installation:\n"
-        " install [-lrtsdg] PACKAGE\n"
-        " install-multiple [-lrtsdpg] PACKAGE...\n"
+        " install [-lrtsdg] [--instant] PACKAGE\n"
+        " install-multiple [-lrtsdpg] [--instant] PACKAGE...\n"
         "     push package(s) to the device and install them\n"
         "     -l: forward lock application\n"
         "     -r: replace existing application\n"
@@ -159,6 +159,7 @@
         "     -d: allow version code downgrade (debuggable packages only)\n"
         "     -p: partial application install (install-multiple only)\n"
         "     -g: grant all runtime permissions\n"
+        "     --instant: cause the app to be installed as an ephemeral install app\n"
         " uninstall [-k] PACKAGE\n"
         "     remove this app package from the device\n"
         "     '-k': keep the data and cache directories\n"
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 7bc0165..e567ff4 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -750,7 +750,7 @@
     if (!s->transport) {
         SendFail(s->peer->fd, "device offline (no transport)");
         goto fail;
-    } else if (s->transport->GetConnectionState() == kCsOffline) {
+    } else if (!ConnectionStateIsOnline(s->transport->GetConnectionState())) {
         /* if there's no remote we fail the connection
          ** right here and terminate it
          */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index fa7cc8c..be7f8fe 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -708,22 +708,41 @@
     }
     lock.unlock();
 
-    // Don't return unauthorized devices; the caller can't do anything with them.
-    if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
-        *error_out = "device unauthorized.\n";
-        char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
-        *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
-        *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
-        *error_out += "\n";
-        *error_out += "Try 'adb kill-server' if that seems wrong.\n";
-        *error_out += "Otherwise check for a confirmation dialog on your device.";
-        result = nullptr;
-    }
+    if (result && !accept_any_state) {
+        // The caller requires an active transport.
+        // Make sure that we're actually connected.
+        ConnectionState state = result->GetConnectionState();
+        switch (state) {
+            case kCsConnecting:
+                *error_out = "device still connecting";
+                result = nullptr;
+                break;
 
-    // Don't return offline devices; the caller can't do anything with them.
-    if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
-        *error_out = "device offline";
-        result = nullptr;
+            case kCsAuthorizing:
+                *error_out = "device still authorizing";
+                result = nullptr;
+                break;
+
+            case kCsUnauthorized: {
+                *error_out = "device unauthorized.\n";
+                char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+                *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+                *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+                *error_out += "\n";
+                *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+                *error_out += "Otherwise check for a confirmation dialog on your device.";
+                result = nullptr;
+                break;
+            }
+
+            case kCsOffline:
+                *error_out = "device offline";
+                result = nullptr;
+                break;
+
+            default:
+                break;
+        }
     }
 
     if (result) {
@@ -802,6 +821,10 @@
             return "sideload";
         case kCsUnauthorized:
             return "unauthorized";
+        case kCsAuthorizing:
+            return "authorizing";
+        case kCsConnecting:
+            return "connecting";
         default:
             return "unknown";
     }
@@ -1080,7 +1103,7 @@
 
 void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
                             unsigned writeable) {
-    atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
+    atransport* t = new atransport((writeable ? kCsConnecting : kCsNoPerm));
 
     D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
     init_usb_transport(t, usb);
diff --git a/adb/transport.h b/adb/transport.h
index ebc186b..e1cbc09 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -198,7 +198,7 @@
     // class in one go is a very large change. Given how bad our testing is,
     // it's better to do this piece by piece.
 
-    atransport(ConnectionState state = kCsOffline)
+    atransport(ConnectionState state = kCsConnecting)
         : id(NextTransportId()),
           connection_state_(state),
           connection_waitable_(std::make_shared<ConnectionWaitable>()),
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 9bd0628..983e195 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -101,14 +101,13 @@
 #
 
 my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
+my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 ifdef HOST_CROSS_OS
-# Archive fastboot.exe for win_sdk build.
-$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
+$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
 endif
 my_dist_files :=
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8bd92cc..17d34e1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -240,6 +240,29 @@
     return Success();
 }
 
+static Result<Success> do_interface_restart(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    svc->Restart();
+    return Success();
+}
+
+static Result<Success> do_interface_start(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    if (auto result = svc->Start(); !result) {
+        return Error() << "Could not start interface: " << result.error();
+    }
+    return Success();
+}
+
+static Result<Success> do_interface_stop(const BuiltinArguments& args) {
+    Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
+    if (!svc) return Error() << "interface " << args[1] << " not found";
+    svc->Stop();
+    return Success();
+}
+
 // mkdir <path> [mode] [owner] [group]
 static Result<Success> do_mkdir(const BuiltinArguments& args) {
     mode_t mode = 0755;
@@ -1050,6 +1073,9 @@
         {"init_user0",              {0,     0,    {false,  do_init_user0}}},
         {"insmod",                  {1,     kMax, {true,   do_insmod}}},
         {"installkey",              {1,     1,    {false,  do_installkey}}},
+        {"interface_restart",       {1,     1,    {false,  do_interface_restart}}},
+        {"interface_start",         {1,     1,    {false,  do_interface_start}}},
+        {"interface_stop",          {1,     1,    {false,  do_interface_stop}}},
         {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
diff --git a/init/init.cpp b/init/init.cpp
index 0d5690b..645184b 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";
     }
 }
 
@@ -277,40 +297,29 @@
 
     const ControlMessageFunction& function = it->second;
 
-    if (function.target == ControlTarget::SERVICE) {
-        Service* svc = ServiceList::GetInstance().FindService(name);
-        if (svc == nullptr) {
-            LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
-            return;
-        }
-        if (auto result = function.action(svc); !result) {
-            LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
-                       << result.error();
-        }
+    Service* svc = nullptr;
 
+    switch (function.target) {
+        case ControlTarget::SERVICE:
+            svc = ServiceList::GetInstance().FindService(name);
+            break;
+        case ControlTarget::INTERFACE:
+            svc = ServiceList::GetInstance().FindInterface(name);
+            break;
+        default:
+            LOG(ERROR) << "Invalid function target from static map key '" << msg << "': "
+                       << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
+            return;
+    }
+
+    if (svc == nullptr) {
+        LOG(ERROR) << "Could not find '" << name << "' for ctl." << msg;
         return;
     }
 
-    if (function.target == ControlTarget::INTERFACE) {
-        for (const auto& svc : ServiceList::GetInstance()) {
-            if (svc->interfaces().count(name) == 0) {
-                continue;
-            }
-
-            if (auto result = function.action(svc.get()); !result) {
-                LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
-                           << " with interface " << name << ": " << result.error();
-            }
-
-            return;
-        }
-
-        LOG(ERROR) << "Could not find service hosting interface " << name;
-        return;
+    if (auto result = function.action(svc); !result) {
+        LOG(ERROR) << "Could not ctl." << msg << " for '" << name << "': " << result.error();
     }
-
-    LOG(ERROR) << "Invalid function target from static map key '" << msg
-               << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
 }
 
 static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
@@ -334,8 +343,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 +761,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 +818,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
diff --git a/init/service.h b/init/service.h
index cf38f69..9cb35b8 100644
--- a/init/service.h
+++ b/init/service.h
@@ -244,6 +244,16 @@
         return nullptr;
     }
 
+    Service* FindInterface(const std::string& interface_name) {
+        for (const auto& svc : services_) {
+            if (svc->interfaces().count(interface_name) > 0) {
+                return svc.get();
+            }
+        }
+
+        return nullptr;
+    }
+
     void DumpState() const;
 
     auto begin() const { return services_.begin(); }
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index dd46750..e823257 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -160,6 +160,15 @@
                 misc_undefined: ["integer"],
             },
         },
+
+        vendor: {
+            exclude_srcs: [
+                // qtaguid.cpp loads libnetd_client.so with dlopen().  Since
+                // the interface of libnetd_client.so may vary between AOSP
+                // releases, exclude qtaguid.cpp from the VNDK-SP variant.
+                "qtaguid.cpp",
+            ],
+        }
     },
 
     shared_libs: ["liblog"],
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index b2bec99..bb990d5 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -24,7 +24,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/libcutils/canned_fs_config.cpp b/libcutils/canned_fs_config.cpp
index 6b5763b..2772ef0 100644
--- a/libcutils/canned_fs_config.cpp
+++ b/libcutils/canned_fs_config.cpp
@@ -21,7 +21,6 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/libcutils/hashmap.cpp b/libcutils/hashmap.cpp
index 65b6ab1..10e3b25 100644
--- a/libcutils/hashmap.cpp
+++ b/libcutils/hashmap.cpp
@@ -21,7 +21,6 @@
 #include <cutils/threads.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdbool.h>
 #include <sys/types.h>
 
 typedef struct Entry Entry;
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index f95c6c5..c9580af 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -24,7 +24,6 @@
 #include <limits.h>
 #include <pthread.h>
 #include <stdatomic.h>
-#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index 6549b8d..e6e17ce 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -29,6 +29,13 @@
     defaults: ["metricslogger_defaults"],
 }
 
+// static version of libmetricslogger, needed by a few art static binaries
+cc_library_static {
+    name: "libmetricslogger_static",
+    srcs: metricslogger_lib_src_files,
+    defaults: ["metricslogger_defaults"],
+}
+
 // metricslogger shared library, debug
 // -----------------------------------------------------------------------------
 cc_library_shared {
diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
index 189bc4b..2c76869 100644
--- a/libmetricslogger/include/metricslogger/metrics_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <log/log_event_list.h>
 #include <cstdint>
 #include <string>
 
@@ -32,6 +33,34 @@
 // |value| in the field |field|.
 void LogMultiAction(int32_t category, int32_t field, const std::string& value);
 
+// Logs a Tron complex event.
+//
+// A complex event can include data in a structure not suppored by the other
+// log event types above.
+//
+// Note that instances of this class are single use. You must call Record()
+// to write the event to the event log.
+class ComplexEventLogger {
+  private:
+    android_log_event_list logger;
+
+  public:
+    // Create a complex event with category|category|.
+    explicit ComplexEventLogger(int category);
+    // Add tagged data to the event, with the given tag and integer value.
+    void AddTaggedData(int tag, int32_t value);
+    // Add tagged data to the event, with the given tag and string value.
+    void AddTaggedData(int tag, const std::string& value);
+    // Add tagged data to the event, with the given tag and integer value.
+    void AddTaggedData(int tag, int64_t value);
+    // Add tagged data to the event, with the given tag and float value.
+    void AddTaggedData(int tag, float value);
+    // Record this event. This method can only be used once per instance
+    // of ComplexEventLogger. Do not made any subsequent calls to AddTaggedData
+    // after recording an event.
+    void Record();
+};
+
 // TODO: replace these with the metric_logger.proto definitions
 enum {
     LOGBUILDER_CATEGORY = 757,
@@ -44,11 +73,23 @@
 
     ACTION_BOOT = 1098,
     FIELD_PLATFORM_REASON = 1099,
+
+    ACTION_HIDDEN_API_ACCESSED = 1391,
+    FIELD_HIDDEN_API_ACCESS_METHOD = 1392,
+    FIELD_HIDDEN_API_ACCESS_DENIED = 1393,
+    FIELD_HIDDEN_API_SIGNATURE = 1394,
 };
 
 enum {
     TYPE_ACTION = 4,
 };
 
+enum {
+    ACCESS_METHOD_NONE = 0,
+    ACCESS_METHOD_REFLECTION = 1,
+    ACCESS_METHOD_JNI = 2,
+    ACCESS_METHOD_LINKING = 3,
+};
+
 }  // namespace metricslogger
 }  // namespace android
diff --git a/libmetricslogger/metrics_logger.cpp b/libmetricslogger/metrics_logger.cpp
index fdc4407..912fa12 100644
--- a/libmetricslogger/metrics_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -23,9 +23,14 @@
 
 namespace {
 
+#ifdef __ANDROID__
 EventTagMap* kEventTagMap = android_openEventTagMap(nullptr);
 const int kSysuiMultiActionTag = android_lookupEventTagNum(
     kEventTagMap, "sysui_multi_action", "(content|4)", ANDROID_LOG_UNKNOWN);
+#else
+// android_openEventTagMap does not work on host builds.
+const int kSysuiMultiActionTag = 0;
+#endif
 
 }  // namespace
 
@@ -53,5 +58,29 @@
         << field << value << LOG_ID_EVENTS;
 }
 
+ComplexEventLogger::ComplexEventLogger(int category) : logger(kSysuiMultiActionTag) {
+    logger << LOGBUILDER_CATEGORY << category;
+}
+
+void ComplexEventLogger::AddTaggedData(int tag, int32_t value) {
+    logger << tag << value;
+}
+
+void ComplexEventLogger::AddTaggedData(int tag, const std::string& value) {
+    logger << tag << value;
+}
+
+void ComplexEventLogger::AddTaggedData(int tag, int64_t value) {
+    logger << tag << value;
+}
+
+void ComplexEventLogger::AddTaggedData(int tag, float value) {
+    logger << tag << value;
+}
+
+void ComplexEventLogger::Record() {
+    logger << LOG_ID_EVENTS;
+}
+
 }  // namespace metricslogger
 }  // namespace android
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 7c40a77..750761f 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -67,8 +67,9 @@
 # ZygoteInit class preloading ends:
 3030 boot_progress_preload_end (time|2|3)
 
-# Dalvik VM
+# Dalvik VM / ART
 20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)
+20004 art_hidden_api_access (access_method|1),(flags|1),(class|3),(member|3),(type_signature|3)
 
 75000 sqlite_mem_alarm_current (current|1|2)
 75001 sqlite_mem_alarm_max (max|1|2)
diff --git a/logd/main.cpp b/logd/main.cpp
index 4af0d21..606aa63 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -33,7 +33,6 @@
 #include <syslog.h>
 #include <unistd.h>
 
-#include <cstdbool>
 #include <memory>
 
 #include <android-base/macros.h>