Merge "base: tag unique_fd::reset as reinitializing for clang-tidy."
diff --git a/adb/Android.bp b/adb/Android.bp
index a26017f..139ee23 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -314,6 +314,7 @@
         "libadb_protos",
         "libadb_tls_connection",
         "libandroidfw",
+        "libapp_processes_protos_full",
         "libbase",
         "libcutils",
         "libcrypto_utils",
@@ -323,7 +324,7 @@
         "liblog",
         "liblz4",
         "libmdnssd",
-        "libprotobuf-cpp-lite",
+        "libprotobuf-cpp-full",
         "libssl",
         "libusb",
         "libutils",
@@ -387,6 +388,7 @@
 
     static_libs: [
         "libadbconnection_server",
+        "libapp_processes_protos_lite",
         "libdiagnose_usb",
     ],
 
@@ -403,6 +405,12 @@
         "liblog",
     ],
 
+    proto: {
+        type: "lite",
+        static: true,
+        export_proto_headers: true,
+    },
+
     target: {
         android: {
             whole_static_libs: [
@@ -429,7 +437,7 @@
     },
 }
 
-cc_library_static {
+cc_library {
     name: "libadbd_services",
     defaults: ["adbd_defaults", "host_adbd_supported"],
     recovery_available: true,
@@ -450,7 +458,9 @@
     static_libs: [
         "libadbconnection_server",
         "libadbd_core",
+        "libapp_processes_protos_lite",
         "libdiagnose_usb",
+        "libprotobuf-cpp-lite",
     ],
 
     shared_libs: [
@@ -464,6 +474,7 @@
         "libbase",
         "libcrypto",
         "libcrypto_utils",
+        "libcutils_sockets",
         "liblog",
     ],
 
@@ -507,6 +518,8 @@
     whole_static_libs: [
         "libadbconnection_server",
         "libadbd_core",
+        "libapp_processes_protos_lite",
+        "libprotobuf-cpp-lite",
     ],
 
     shared_libs: [
@@ -515,6 +528,7 @@
         "libadb_tls_connection",
         "libadbd_auth",
         "libadbd_fs",
+        "libadbd_services",
         "libasyncio",
         "libbase",
         "libcrypto",
@@ -533,7 +547,6 @@
     },
 
     static_libs: [
-        "libadbd_services",
         "libcutils_sockets",
         "libdiagnose_usb",
         "libmdnssd",
@@ -569,6 +582,7 @@
         "libadbconnection_server",
         "libadbd",
         "libadbd_services",
+        "libapp_processes_protos_lite",
         "libasyncio",
         "libbase",
         "libcap",
@@ -578,6 +592,7 @@
         "liblog",
         "libmdnssd",
         "libminijail",
+        "libprotobuf-cpp-lite",
         "libselinux",
         "libssl",
     ],
diff --git a/adb/adb.h b/adb/adb.h
index 86d205c..9f8d299 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -169,6 +169,7 @@
 int init_jdwp(void);
 asocket* create_jdwp_service_socket();
 asocket* create_jdwp_tracker_service_socket();
+asocket* create_app_tracker_service_socket();
 unique_fd create_jdwp_connection_fd(int jdwp_pid);
 #endif
 
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 8738ce7..4b2fa04 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -145,12 +145,12 @@
 
     std::lock_guard<std::mutex> lock(g_keys_mutex);
     std::string fingerprint = hash_key(key.get());
-    if (g_keys.find(fingerprint) != g_keys.end()) {
-        LOG(INFO) << "ignoring already-loaded key: " << file;
-    } else {
-        LOG(INFO) << "Loaded fingerprint=[" << SHA256BitsToHexString(fingerprint) << "]";
+    bool already_loaded = (g_keys.find(fingerprint) != g_keys.end());
+    if (!already_loaded) {
         g_keys[fingerprint] = std::move(key);
     }
+    LOG(INFO) << (already_loaded ? "ignored already-loaded" : "loaded new") << " key from '" << file
+              << "' with fingerprint " << SHA256BitsToHexString(fingerprint);
     return true;
 }
 
@@ -159,23 +159,25 @@
 
     struct stat st;
     if (stat(path.c_str(), &st) != 0) {
-        PLOG(ERROR) << "failed to stat '" << path << "'";
+        PLOG(ERROR) << "load_keys: failed to stat '" << path << "'";
         return false;
     }
 
     if (S_ISREG(st.st_mode)) {
         return load_key(path);
-    } else if (S_ISDIR(st.st_mode)) {
+    }
+
+    if (S_ISDIR(st.st_mode)) {
         if (!allow_dir) {
             // inotify isn't recursive. It would break expectations to load keys in nested
             // directories but not monitor them for new keys.
-            LOG(WARNING) << "refusing to recurse into directory '" << path << "'";
+            LOG(WARNING) << "load_keys: refusing to recurse into directory '" << path << "'";
             return false;
         }
 
         std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
         if (!dir) {
-            PLOG(ERROR) << "failed to open directory '" << path << "'";
+            PLOG(ERROR) << "load_keys: failed to open directory '" << path << "'";
             return false;
         }
 
@@ -189,7 +191,7 @@
             }
 
             if (!android::base::EndsWith(name, ".adb_key")) {
-                LOG(INFO) << "skipping non-adb_key '" << path << "/" << name << "'";
+                LOG(INFO) << "skipped non-adb_key '" << path << "/" << name << "'";
                 continue;
             }
 
@@ -198,7 +200,7 @@
         return result;
     }
 
-    LOG(ERROR) << "unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
+    LOG(ERROR) << "load_keys: unexpected type for '" << path << "': 0x" << std::hex << st.st_mode;
     return false;
 }
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 081bac4..1186060 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -50,6 +50,8 @@
 #include <unistd.h>
 #endif
 
+#include <google/protobuf/text_format.h>
+
 #include "adb.h"
 #include "adb_auth.h"
 #include "adb_client.h"
@@ -57,6 +59,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "app_processes.pb.h"
 #include "bugreport.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
@@ -1354,17 +1357,49 @@
     }
 }
 
-static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+static int adb_connect_command(const std::string& command, TransportId* transport,
+                               StandardStreamsCallbackInterface* callback) {
     std::string error;
     unique_fd fd(adb_connect(transport, command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
-    read_and_dump(fd);
+    read_and_dump(fd, false, callback);
     return 0;
 }
 
+static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
+    return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK);
+}
+
+// A class that prints out human readable form of the protobuf message for "track-app" service
+// (received in binary format).
+class TrackAppStreamsCallback : public DefaultStandardStreamsCallback {
+  public:
+    TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {}
+
+    // Assume the buffer contains at least 4 bytes of valid data.
+    void OnStdout(const char* buffer, int length) override {
+        if (length < 4) return;  // Unexpected length received. Do nothing.
+
+        adb::proto::AppProcesses binary_proto;
+        // The first 4 bytes are the length of remaining content in hexadecimal format.
+        binary_proto.ParseFromString(std::string(buffer + 4, length - 4));
+        char summary[24];  // The following string includes digits and 16 fixed characters.
+        int written = snprintf(summary, sizeof(summary), "Process count: %d\n",
+                               binary_proto.process_size());
+        OnStream(nullptr, stdout, summary, written);
+
+        std::string string_proto;
+        google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto);
+        OnStream(nullptr, stdout, string_proto.data(), string_proto.length());
+    }
+
+  private:
+    DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback);
+};
+
 static int adb_connect_command_bidirectional(const std::string& command) {
     std::string error;
     unique_fd fd(adb_connect(command, &error));
@@ -1925,6 +1960,18 @@
         return adb_connect_command("jdwp");
     } else if (!strcmp(argv[0], "track-jdwp")) {
         return adb_connect_command("track-jdwp");
+    } else if (!strcmp(argv[0], "track-app")) {
+        FeatureSet features;
+        std::string error;
+        if (!adb_get_feature_set(&features, &error)) {
+            fprintf(stderr, "error: %s\n", error.c_str());
+            return 1;
+        }
+        if (!CanUseFeature(features, kFeatureTrackApp)) {
+            error_exit("track-app is not supported by the device");
+        }
+        TrackAppStreamsCallback callback;
+        return adb_connect_command("track-app", nullptr, &callback);
     } else if (!strcmp(argv[0], "track-devices")) {
         if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
             error_exit("usage: adb track-devices [-l]");
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 922f2ba..cc38926 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -29,6 +29,7 @@
 #include <utime.h>
 
 #include <chrono>
+#include <deque>
 #include <functional>
 #include <memory>
 #include <sstream>
@@ -203,7 +204,7 @@
 
 class SyncConnection {
   public:
-    SyncConnection() : expect_done_(false) {
+    SyncConnection() {
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
         std::string error;
@@ -239,16 +240,6 @@
 
     bool IsValid() { return fd >= 0; }
 
-    bool ReceivedError(const char* from, const char* to) {
-        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
-        int rc = adb_poll(&pfd, 1, 0);
-        if (rc < 0) {
-            Error("failed to poll: %s", strerror(errno));
-            return true;
-        }
-        return rc != 0;
-    }
-
     void NewTransfer() {
         current_ledger_.Reset();
     }
@@ -258,6 +249,11 @@
         global_ledger_.bytes_transferred += bytes;
     }
 
+    void RecordFileSent(std::string from, std::string to) {
+        RecordFilesTransferred(1);
+        deferred_acknowledgements_.emplace_back(std::move(from), std::move(to));
+    }
+
     void RecordFilesTransferred(size_t files) {
         current_ledger_.files_transferred += files;
         global_ledger_.files_transferred += files;
@@ -283,39 +279,38 @@
         }
     }
 
-    bool SendRequest(int id, const char* path_and_mode) {
-        size_t path_length = strlen(path_and_mode);
-        if (path_length > 1024) {
-            Error("SendRequest failed: path too long: %zu", path_length);
+    bool SendRequest(int id, const std::string& path) {
+        if (path.length() > 1024) {
+            Error("SendRequest failed: path too long: %zu", path.length());
             errno = ENAMETOOLONG;
             return false;
         }
 
         // Sending header and payload in a single write makes a noticeable
         // difference to "adb sync" performance.
-        std::vector<char> buf(sizeof(SyncRequest) + path_length);
+        std::vector<char> buf(sizeof(SyncRequest) + path.length());
         SyncRequest* req = reinterpret_cast<SyncRequest*>(&buf[0]);
         req->id = id;
-        req->path_length = path_length;
+        req->path_length = path.length();
         char* data = reinterpret_cast<char*>(req + 1);
-        memcpy(data, path_and_mode, path_length);
+        memcpy(data, path.data(), path.length());
 
-        return WriteFdExactly(fd, &buf[0], buf.size());
+        return WriteFdExactly(fd, buf.data(), buf.size());
     }
 
-    bool SendStat(const char* path_and_mode) {
+    bool SendStat(const std::string& path) {
         if (!have_stat_v2_) {
             errno = ENOTSUP;
             return false;
         }
-        return SendRequest(ID_STAT_V2, path_and_mode);
+        return SendRequest(ID_STAT_V2, path);
     }
 
-    bool SendLstat(const char* path_and_mode) {
+    bool SendLstat(const std::string& path) {
         if (have_stat_v2_) {
-            return SendRequest(ID_LSTAT_V2, path_and_mode);
+            return SendRequest(ID_LSTAT_V2, path);
         } else {
-            return SendRequest(ID_LSTAT_V1, path_and_mode);
+            return SendRequest(ID_LSTAT_V1, path);
         }
     }
 
@@ -374,7 +369,7 @@
         return true;
     }
 
-    bool SendLs(const char* path) {
+    bool SendLs(const std::string& path) {
         return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
     }
 
@@ -415,28 +410,26 @@
 
     // Sending header, payload, and footer in a single write makes a huge
     // difference to "adb sync" performance.
-    bool SendSmallFile(const char* path_and_mode,
-                       const char* lpath, const char* rpath,
-                       unsigned mtime,
-                       const char* data, size_t data_length) {
-        size_t path_length = strlen(path_and_mode);
-        if (path_length > 1024) {
-            Error("SendSmallFile failed: path too long: %zu", path_length);
+    bool SendSmallFile(const std::string& path, mode_t mode, const std::string& lpath,
+                       const std::string& rpath, unsigned mtime, const char* data,
+                       size_t data_length) {
+        std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
+        if (path_and_mode.length() > 1024) {
+            Error("SendSmallFile failed: path too long: %zu", path_and_mode.length());
             errno = ENAMETOOLONG;
             return false;
         }
 
-        std::vector<char> buf(sizeof(SyncRequest) + path_length +
-                              sizeof(SyncRequest) + data_length +
-                              sizeof(SyncRequest));
+        std::vector<char> buf(sizeof(SyncRequest) + path_and_mode.length() + sizeof(SyncRequest) +
+                              data_length + sizeof(SyncRequest));
         char* p = &buf[0];
 
         SyncRequest* req_send = reinterpret_cast<SyncRequest*>(p);
         req_send->id = ID_SEND;
-        req_send->path_length = path_length;
+        req_send->path_length = path_and_mode.length();
         p += sizeof(SyncRequest);
-        memcpy(p, path_and_mode, path_length);
-        p += path_length;
+        memcpy(p, path_and_mode.data(), path_and_mode.size());
+        p += path_and_mode.length();
 
         SyncRequest* req_data = reinterpret_cast<SyncRequest*>(p);
         req_data->id = ID_DATA;
@@ -451,34 +444,34 @@
         p += sizeof(SyncRequest);
 
         WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
-        expect_done_ = true;
 
-        // RecordFilesTransferred gets called in CopyDone.
+        RecordFileSent(lpath, rpath);
         RecordBytesTransferred(data_length);
         ReportProgress(rpath, data_length, data_length);
         return true;
     }
 
-    bool SendLargeFile(const char* path_and_mode,
-                       const char* lpath, const char* rpath,
-                       unsigned mtime) {
+    bool SendLargeFile(const std::string& path, mode_t mode, const std::string& lpath,
+                       const std::string& rpath, unsigned mtime) {
+        std::string path_and_mode = android::base::StringPrintf("%s,%d", path.c_str(), mode);
         if (!SendRequest(ID_SEND, path_and_mode)) {
-            Error("failed to send ID_SEND message '%s': %s", path_and_mode, strerror(errno));
+            Error("failed to send ID_SEND message '%s': %s", path_and_mode.c_str(),
+                  strerror(errno));
             return false;
         }
 
         struct stat st;
-        if (stat(lpath, &st) == -1) {
-            Error("cannot stat '%s': %s", lpath, strerror(errno));
+        if (stat(lpath.c_str(), &st) == -1) {
+            Error("cannot stat '%s': %s", lpath.c_str(), strerror(errno));
             return false;
         }
 
         uint64_t total_size = st.st_size;
         uint64_t bytes_copied = 0;
 
-        unique_fd lfd(adb_open(lpath, O_RDONLY));
+        unique_fd lfd(adb_open(lpath.c_str(), O_RDONLY));
         if (lfd < 0) {
-            Error("opening '%s' locally failed: %s", lpath, strerror(errno));
+            Error("opening '%s' locally failed: %s", lpath.c_str(), strerror(errno));
             return false;
         }
 
@@ -487,7 +480,7 @@
         while (true) {
             int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
             if (bytes_read == -1) {
-                Error("reading '%s' locally failed: %s", lpath, strerror(errno));
+                Error("reading '%s' locally failed: %s", lpath.c_str(), strerror(errno));
                 return false;
             } else if (bytes_read == 0) {
                 break;
@@ -499,55 +492,53 @@
             RecordBytesTransferred(bytes_read);
             bytes_copied += bytes_read;
 
-            // Check to see if we've received an error from the other side.
-            if (ReceivedError(lpath, rpath)) {
-                break;
-            }
-
             ReportProgress(rpath, bytes_copied, total_size);
         }
 
         syncmsg msg;
         msg.data.id = ID_DONE;
         msg.data.size = mtime;
-        expect_done_ = true;
-
-        // RecordFilesTransferred gets called in CopyDone.
+        RecordFileSent(lpath, rpath);
         return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
     }
 
-    bool CopyDone(const char* from, const char* to) {
+    bool ReadAcknowledgments() {
+        bool result = true;
+        while (!deferred_acknowledgements_.empty()) {
+            auto [from, to] = std::move(deferred_acknowledgements_.front());
+            deferred_acknowledgements_.pop_front();
+            result &= CopyDone(from, to);
+        }
+        return result;
+    }
+
+    bool CopyDone(const std::string& from, const std::string& to) {
         syncmsg msg;
         if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
-            Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
+            Error("failed to copy '%s' to '%s': couldn't read from device", from.c_str(),
+                  to.c_str());
             return false;
         }
         if (msg.status.id == ID_OKAY) {
-            if (expect_done_) {
-                expect_done_ = false;
-                RecordFilesTransferred(1);
-                return true;
-            } else {
-                Error("failed to copy '%s' to '%s': received premature success", from, to);
-                return true;
-            }
+            return true;
         }
         if (msg.status.id != ID_FAIL) {
-            Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
+            Error("failed to copy '%s' to '%s': unknown reason %d", from.c_str(), to.c_str(),
+                  msg.status.id);
             return false;
         }
         return ReportCopyFailure(from, to, msg);
     }
 
-    bool ReportCopyFailure(const char* from, const char* to, const syncmsg& msg) {
+    bool ReportCopyFailure(const std::string& from, const std::string& to, const syncmsg& msg) {
         std::vector<char> buf(msg.status.msglen + 1);
         if (!ReadFdExactly(fd, &buf[0], msg.status.msglen)) {
-            Error("failed to copy '%s' to '%s'; failed to read reason (!): %s",
-                  from, to, strerror(errno));
+            Error("failed to copy '%s' to '%s'; failed to read reason (!): %s", from.c_str(),
+                  to.c_str(), strerror(errno));
             return false;
         }
         buf[msg.status.msglen] = 0;
-        Error("failed to copy '%s' to '%s': remote %s", from, to, &buf[0]);
+        Error("failed to copy '%s' to '%s': remote %s", from.c_str(), to.c_str(), &buf[0]);
         return false;
     }
 
@@ -616,7 +607,7 @@
     size_t max;
 
   private:
-    bool expect_done_;
+    std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
     FeatureSet features_;
     bool have_stat_v2_;
     bool have_ls_v2_;
@@ -629,16 +620,19 @@
         return SendRequest(ID_QUIT, ""); // TODO: add a SendResponse?
     }
 
-    bool WriteOrDie(const char* from, const char* to, const void* data, size_t data_length) {
+    bool WriteOrDie(const std::string& from, const std::string& to, const void* data,
+                    size_t data_length) {
         if (!WriteFdExactly(fd, data, data_length)) {
             if (errno == ECONNRESET) {
                 // Assume adbd told us why it was closing the connection, and
                 // try to read failure reason from adbd.
                 syncmsg msg;
                 if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
-                    Error("failed to copy '%s' to '%s': no response: %s", from, to, strerror(errno));
+                    Error("failed to copy '%s' to '%s': no response: %s", from.c_str(), to.c_str(),
+                          strerror(errno));
                 } else if (msg.status.id != ID_FAIL) {
-                    Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from, to, msg.status.id);
+                    Error("failed to copy '%s' to '%s': not ID_FAIL: %d", from.c_str(), to.c_str(),
+                          msg.status.id);
                 } else {
                     ReportCopyFailure(from, to, msg);
                 }
@@ -651,20 +645,20 @@
     }
 };
 
-static bool sync_ls(SyncConnection& sc, const char* path,
+static bool sync_ls(SyncConnection& sc, const std::string& path,
                     const std::function<sync_ls_cb>& func) {
     return sc.SendLs(path) && sc.FinishLs(func);
 }
 
-static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat(SyncConnection& sc, const std::string& path, struct stat* st) {
     return sc.SendStat(path) && sc.FinishStat(st);
 }
 
-static bool sync_lstat(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_lstat(SyncConnection& sc, const std::string& path, struct stat* st) {
     return sc.SendLstat(path) && sc.FinishStat(st);
 }
 
-static bool sync_stat_fallback(SyncConnection& sc, const char* path, struct stat* st) {
+static bool sync_stat_fallback(SyncConnection& sc, const std::string& path, struct stat* st) {
     if (sync_stat(sc, path, st)) {
         return true;
     }
@@ -688,7 +682,7 @@
         struct stat tmp_st;
 
         st->st_mode &= ~S_IFMT;
-        if (sync_lstat(sc, dir_path.c_str(), &tmp_st)) {
+        if (sync_lstat(sc, dir_path, &tmp_st)) {
             st->st_mode |= S_IFDIR;
         } else {
             st->st_mode |= S_IFREG;
@@ -697,10 +691,8 @@
     return true;
 }
 
-static bool sync_send(SyncConnection& sc, const char* lpath, const char* rpath, unsigned mtime,
-                      mode_t mode, bool sync) {
-    std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
-
+static bool sync_send(SyncConnection& sc, const std::string& lpath, const std::string& rpath,
+                      unsigned mtime, mode_t mode, bool sync) {
     if (sync) {
         struct stat st;
         if (sync_lstat(sc, rpath, &st)) {
@@ -714,41 +706,40 @@
     if (S_ISLNK(mode)) {
 #if !defined(_WIN32)
         char buf[PATH_MAX];
-        ssize_t data_length = readlink(lpath, buf, PATH_MAX - 1);
+        ssize_t data_length = readlink(lpath.c_str(), buf, PATH_MAX - 1);
         if (data_length == -1) {
-            sc.Error("readlink '%s' failed: %s", lpath, strerror(errno));
+            sc.Error("readlink '%s' failed: %s", lpath.c_str(), strerror(errno));
             return false;
         }
         buf[data_length++] = '\0';
 
-        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime, buf, data_length)) {
+        if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length)) {
             return false;
         }
-        return sc.CopyDone(lpath, rpath);
+        return true;
 #endif
     }
 
     struct stat st;
-    if (stat(lpath, &st) == -1) {
-        sc.Error("failed to stat local file '%s': %s", lpath, strerror(errno));
+    if (stat(lpath.c_str(), &st) == -1) {
+        sc.Error("failed to stat local file '%s': %s", lpath.c_str(), strerror(errno));
         return false;
     }
     if (st.st_size < SYNC_DATA_MAX) {
         std::string data;
         if (!android::base::ReadFileToString(lpath, &data, true)) {
-            sc.Error("failed to read all of '%s': %s", lpath, strerror(errno));
+            sc.Error("failed to read all of '%s': %s", lpath.c_str(), strerror(errno));
             return false;
         }
-        if (!sc.SendSmallFile(path_and_mode.c_str(), lpath, rpath, mtime,
-                              data.data(), data.size())) {
+        if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, data.data(), data.size())) {
             return false;
         }
     } else {
-        if (!sc.SendLargeFile(path_and_mode.c_str(), lpath, rpath, mtime)) {
+        if (!sc.SendLargeFile(rpath, mode, lpath, rpath, mtime)) {
             return false;
         }
     }
-    return sc.CopyDone(lpath, rpath);
+    return true;
 }
 
 static bool sync_recv(SyncConnection& sc, const char* rpath, const char* lpath,
@@ -943,7 +934,7 @@
 
     if (check_timestamps) {
         for (const copyinfo& ci : file_list) {
-            if (!sc.SendLstat(ci.rpath.c_str())) {
+            if (!sc.SendLstat(ci.rpath)) {
                 sc.Error("failed to send lstat");
                 return false;
             }
@@ -965,7 +956,7 @@
             if (list_only) {
                 sc.Println("would push: %s -> %s", ci.lpath.c_str(), ci.rpath.c_str());
             } else {
-                if (!sync_send(sc, ci.lpath.c_str(), ci.rpath.c_str(), ci.time, ci.mode, false)) {
+                if (!sync_send(sc, ci.lpath, ci.rpath, ci.time, ci.mode, false)) {
                     return false;
                 }
             }
@@ -1069,6 +1060,7 @@
         sc.ReportTransferRate(src_path, TransferDirection::push);
     }
 
+    success &= sc.ReadAcknowledgments();
     sc.ReportOverallTransferRate(TransferDirection::push);
     return success;
 }
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index b92a7de..c99aead 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -21,6 +21,7 @@
 #include "sysdeps.h"
 
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,6 +34,7 @@
 #include <thread>
 #include <vector>
 
+#include <adbconnection/process_info.h>
 #include <adbconnection/server.h>
 #include <android-base/cmsg.h>
 #include <android-base/unique_fd.h>
@@ -41,6 +43,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "app_processes.pb.h"
 
 using android::base::borrowed_fd;
 using android::base::unique_fd;
@@ -132,18 +135,24 @@
  ** for each JDWP process, we record its pid and its connected socket
  **/
 
+enum class TrackerKind {
+    kJdwp,
+    kApp,
+};
+
 static void jdwp_process_event(int socket, unsigned events, void* _proc);
 static void jdwp_process_list_updated(void);
+static void app_process_list_updated(void);
 
 struct JdwpProcess;
 static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();
 
 struct JdwpProcess {
-    JdwpProcess(unique_fd socket, pid_t pid) {
-        CHECK(pid != 0);
+    JdwpProcess(unique_fd socket, ProcessInfo process) {
+        CHECK(process.pid != 0);
 
         this->socket = socket;
-        this->pid = pid;
+        this->process = process;
         this->fde = fdevent_create(socket.release(), jdwp_process_event, this);
 
         if (!this->fde) {
@@ -171,17 +180,19 @@
     }
 
     borrowed_fd socket = -1;
-    int32_t pid = -1;
+    ProcessInfo process;
     fdevent* fde = nullptr;
 
     std::vector<unique_fd> out_fds;
 };
 
+// Populate the list of processes for "track-jdwp" service.
 static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
     std::string temp;
 
     for (auto& proc : _jdwp_list) {
-        std::string next = std::to_string(proc->pid) + "\n";
+        if (!proc->process.debuggable) continue;
+        std::string next = std::to_string(proc->process.pid) + "\n";
         if (temp.length() + next.length() > bufferlen) {
             D("truncating JDWP process list (max len = %zu)", bufferlen);
             break;
@@ -193,7 +204,44 @@
     return temp.length();
 }
 
-static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+// Populate the list of processes for "track-app" service.
+// The list is a protobuf message in the binary format for efficiency.
+static size_t app_process_list(char* buffer, size_t bufferlen) {
+    adb::proto::AppProcesses output;  // result that's guaranteed to fit in the given buffer
+    adb::proto::AppProcesses temp;    // temporary result that may be longer than the given buffer
+    std::string serialized_message;
+
+    for (auto& proc : _jdwp_list) {
+        if (!proc->process.debuggable && !proc->process.profileable) continue;
+        auto* entry = temp.add_process();
+        entry->set_pid(proc->process.pid);
+        entry->set_debuggable(proc->process.debuggable);
+        entry->set_profileable(proc->process.profileable);
+        entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length);
+        temp.SerializeToString(&serialized_message);
+        if (serialized_message.size() > bufferlen) {
+            D("truncating app process list (max len = %zu)", bufferlen);
+            break;
+        }
+        output = temp;
+    }
+    output.SerializeToString(&serialized_message);
+    memcpy(buffer, serialized_message.data(), serialized_message.length());
+    return serialized_message.length();
+}
+
+// Populate the list of processes for either "track-jdwp" or "track-app" services,
+// depending on the given kind.
+static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) {
+    switch (kind) {
+        case TrackerKind::kJdwp:
+            return jdwp_process_list(buffer, bufferlen);
+        case TrackerKind::kApp:
+            return app_process_list(buffer, bufferlen);
+    }
+}
+
+static size_t process_list_msg(TrackerKind kind, char* buffer, size_t bufferlen) {
     // Message is length-prefixed with 4 hex digits in ASCII.
     static constexpr size_t header_len = 4;
     if (bufferlen < header_len) {
@@ -201,7 +249,7 @@
     }
 
     char head[header_len + 1];
-    size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+    size_t len = process_list(kind, buffer + header_len, bufferlen - header_len);
     snprintf(head, sizeof head, "%04zx", len);
     memcpy(buffer, head, header_len);
     return len + header_len;
@@ -213,7 +261,7 @@
 
     if (events & FDE_READ) {
         // We already have the PID, if we can read from the socket, we've probably hit EOF.
-        D("terminating JDWP connection %d", proc->pid);
+        D("terminating JDWP connection %" PRId64, proc->process.pid);
         goto CloseProcess;
     }
 
@@ -223,11 +271,12 @@
 
         int fd = proc->out_fds.back().get();
         if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
-            D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
+            D("sending new file descriptor to JDWP %" PRId64 " failed: %s", proc->process.pid,
+              strerror(errno));
             goto CloseProcess;
         }
 
-        D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+        D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid);
 
         proc->out_fds.pop_back();
         if (proc->out_fds.empty()) {
@@ -238,15 +287,20 @@
     return;
 
 CloseProcess:
+    bool debuggable = proc->process.debuggable;
+    bool profileable = proc->process.profileable;
     proc->RemoveFromList();
-    jdwp_process_list_updated();
+    if (debuggable) jdwp_process_list_updated();
+    if (debuggable || profileable) app_process_list_updated();
 }
 
 unique_fd create_jdwp_connection_fd(int pid) {
     D("looking for pid %d in JDWP process list", pid);
 
     for (auto& proc : _jdwp_list) {
-        if (proc->pid == pid) {
+        // Don't allow JDWP connection to a non-debuggable process.
+        if (!proc->process.debuggable) continue;
+        if (proc->process.pid == static_cast<uint64_t>(pid)) {
             int fds[2];
 
             if (adb_socketpair(fds) < 0) {
@@ -338,18 +392,22 @@
  **/
 
 struct JdwpTracker : public asocket {
+    TrackerKind kind;
     bool need_initial;
+
+    explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {}
 };
 
 static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();
 
-static void jdwp_process_list_updated(void) {
+static void process_list_updated(TrackerKind kind) {
     std::string data;
-    data.resize(1024);
-    data.resize(jdwp_process_list_msg(&data[0], data.size()));
+    const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048;
+    data.resize(kMaxLength);
+    data.resize(process_list_msg(kind, &data[0], data.size()));
 
     for (auto& t : _jdwp_trackers) {
-        if (t->peer) {
+        if (t->kind == kind && t->peer) {
             // The tracker might not have been connected yet.
             apacket::payload_type payload(data.begin(), data.end());
             t->peer->enqueue(t->peer, std::move(payload));
@@ -357,6 +415,14 @@
     }
 }
 
+static void jdwp_process_list_updated(void) {
+    process_list_updated(TrackerKind::kJdwp);
+}
+
+static void app_process_list_updated(void) {
+    process_list_updated(TrackerKind::kApp);
+}
+
 static void jdwp_tracker_close(asocket* s) {
     D("LS(%d): destroying jdwp tracker service", s->id);
 
@@ -380,7 +446,7 @@
     if (t->need_initial) {
         apacket::payload_type data;
         data.resize(s->get_max_payload());
-        data.resize(jdwp_process_list_msg(&data[0], data.size()));
+        data.resize(process_list_msg(t->kind, &data[0], data.size()));
         t->need_initial = false;
         s->peer->enqueue(s->peer, std::move(data));
     }
@@ -393,8 +459,8 @@
     return -1;
 }
 
-asocket* create_jdwp_tracker_service_socket(void) {
-    auto t = std::make_unique<JdwpTracker>();
+asocket* create_process_tracker_service_socket(TrackerKind kind) {
+    auto t = std::make_unique<JdwpTracker>(kind, true);
     if (!t) {
         LOG(FATAL) << "failed to allocate JdwpTracker";
     }
@@ -407,7 +473,6 @@
     t->ready = jdwp_tracker_ready;
     t->enqueue = jdwp_tracker_enqueue;
     t->close = jdwp_tracker_close;
-    t->need_initial = true;
 
     asocket* result = t.get();
 
@@ -416,19 +481,28 @@
     return result;
 }
 
+asocket* create_jdwp_tracker_service_socket() {
+    return create_process_tracker_service_socket(TrackerKind::kJdwp);
+}
+
+asocket* create_app_tracker_service_socket() {
+    return create_process_tracker_service_socket(TrackerKind::kApp);
+}
+
 int init_jdwp(void) {
     std::thread([]() {
         adb_thread_setname("jdwp control");
-        adbconnection_listen([](int fd, pid_t pid) {
-            LOG(INFO) << "jdwp connection from " << pid;
-            fdevent_run_on_main_thread([fd, pid] {
+        adbconnection_listen([](int fd, ProcessInfo process) {
+            LOG(INFO) << "jdwp connection from " << process.pid;
+            fdevent_run_on_main_thread([fd, process] {
                 unique_fd ufd(fd);
-                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
+                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
                 if (!proc) {
                     LOG(FATAL) << "failed to allocate JdwpProcess";
                 }
                 _jdwp_list.emplace_back(std::move(proc));
-                jdwp_process_list_updated();
+                if (process.debuggable) jdwp_process_list_updated();
+                if (process.debuggable || process.profileable) app_process_list_updated();
             });
         });
     }).detach();
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
index fa692c0..c1e766e 100644
--- a/adb/daemon/mdns.cpp
+++ b/adb/daemon/mdns.cpp
@@ -150,11 +150,11 @@
     for (size_t i = 0; i < len; ++i) {
         uint8_t val = dist(mt);
         if (val < 10) {
-            ret += '0' + val;
+            ret += static_cast<char>('0' + val);
         } else if (val < 36) {
-            ret += 'A' + (val - 10);
+            ret += static_cast<char>('A' + (val - 10));
         } else {
-            ret += 'a' + (val - 36);
+            ret += static_cast<char>('a' + (val - 36));
         }
     }
     return ret;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 6bbf66e..a9d1fe8 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -241,6 +241,8 @@
         return create_jdwp_service_socket();
     } else if (name == "track-jdwp") {
         return create_jdwp_tracker_service_socket();
+    } else if (name == "track-app") {
+        return create_app_tracker_service_socket();
     } else if (android::base::ConsumePrefix(&name, "sink:")) {
         uint64_t byte_count = 0;
         if (!ParseUint(&byte_count, name)) {
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
index ee48abb..c132342 100644
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ b/adb/libs/adbconnection/adbconnection_client.cpp
@@ -29,6 +29,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "adbconnection/process_info.h"
+
 using android::base::unique_fd;
 
 static constexpr char kJdwpControlName[] = "\0jdwp-control";
@@ -60,6 +62,8 @@
 
   std::optional<uint64_t> pid;
   std::optional<bool> debuggable;
+  std::optional<bool> profileable;
+  std::optional<std::string> architecture;
 
   for (size_t i = 0; i < info_count; ++i) {
     auto info = info_elems[i];
@@ -77,7 +81,23 @@
           LOG(ERROR) << "multiple debuggable entries in AdbConnectionClientInfo, ignoring";
           continue;
         }
-        debuggable = info->data.pid;
+        debuggable = info->data.debuggable;
+        break;
+
+      case AdbConnectionClientInfoType::profileable:
+        if (profileable) {
+          LOG(ERROR) << "multiple profileable entries in AdbConnectionClientInfo, ignoring";
+          continue;
+        }
+        profileable = info->data.profileable;
+        break;
+
+      case AdbConnectionClientInfoType::architecture:
+        if (architecture) {
+          LOG(ERROR) << "multiple architecture entries in AdbConnectionClientInfo, ignoring";
+          continue;
+        }
+        architecture = std::string(info->data.architecture.name, info->data.architecture.size);
         break;
     }
   }
@@ -92,6 +112,16 @@
     return nullptr;
   }
 
+  if (!profileable) {
+    LOG(ERROR) << "AdbConnectionClientInfo missing required field profileable";
+    return nullptr;
+  }
+
+  if (!architecture) {
+    LOG(ERROR) << "AdbConnectionClientInfo missing required field architecture";
+    return nullptr;
+  }
+
   ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
   if (ctx->control_socket_ < 0) {
     PLOG(ERROR) << "failed to create Unix domain socket";
@@ -120,10 +150,10 @@
     return nullptr;
   }
 
-  uint32_t pid_u32 = static_cast<uint32_t>(*pid);
-  rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &pid_u32, sizeof(pid_u32)));
-  if (rc != sizeof(pid_u32)) {
-    PLOG(ERROR) << "failed to send JDWP process pid to adbd";
+  ProcessInfo process(*pid, *debuggable, *profileable, *architecture);
+  rc = TEMP_FAILURE_RETRY(write(ctx->control_socket_.get(), &process, sizeof(process)));
+  if (rc != sizeof(process)) {
+    PLOG(ERROR) << "failed to send JDWP process info to adbd";
   }
 
   return ctx.release();
diff --git a/adb/libs/adbconnection/adbconnection_server.cpp b/adb/libs/adbconnection/adbconnection_server.cpp
index 939da2f..aac9615 100644
--- a/adb/libs/adbconnection/adbconnection_server.cpp
+++ b/adb/libs/adbconnection/adbconnection_server.cpp
@@ -28,6 +28,8 @@
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "adbconnection/process_info.h"
+
 using android::base::unique_fd;
 
 #define JDWP_CONTROL_NAME "\0jdwp-control"
@@ -36,7 +38,7 @@
 static_assert(JDWP_CONTROL_NAME_LEN <= sizeof(reinterpret_cast<sockaddr_un*>(0)->sun_path));
 
 // Listen for incoming jdwp clients forever.
-void adbconnection_listen(void (*callback)(int fd, pid_t pid)) {
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process)) {
   sockaddr_un addr = {};
   socklen_t addrlen = JDWP_CONTROL_NAME_LEN + sizeof(addr.sun_family);
 
@@ -106,16 +108,13 @@
                      << ") in pending connections";
         }
 
-        // Massively oversized buffer: we're expecting an int32_t from the other end.
-        char buf[32];
-        int rc = TEMP_FAILURE_RETRY(recv(it->get(), buf, sizeof(buf), MSG_DONTWAIT));
-        if (rc != 4) {
+        ProcessInfo process;
+        int rc = TEMP_FAILURE_RETRY(recv(it->get(), &process, sizeof(process), MSG_DONTWAIT));
+        if (rc != sizeof(process)) {
           LOG(ERROR) << "received data of incorrect size from JDWP client: read " << rc
-                     << ", expected 4";
+                     << ", expected " << sizeof(process);
         } else {
-          int32_t pid;
-          memcpy(&pid, buf, sizeof(pid));
-          callback(it->release(), static_cast<pid_t>(pid));
+          callback(it->release(), process);
         }
 
         if (epoll_ctl(epfd.get(), EPOLL_CTL_DEL, event.data.fd, nullptr) != 0) {
diff --git a/adb/libs/adbconnection/include/adbconnection/client.h b/adb/libs/adbconnection/include/adbconnection/client.h
index 692fea0..a74cd36 100644
--- a/adb/libs/adbconnection/include/adbconnection/client.h
+++ b/adb/libs/adbconnection/include/adbconnection/client.h
@@ -28,6 +28,8 @@
 enum AdbConnectionClientInfoType {
   pid,
   debuggable,
+  profileable,
+  architecture,
 };
 
 struct AdbConnectionClientInfo {
@@ -35,11 +37,17 @@
   union {
     uint64_t pid;
     bool debuggable;
+    bool profileable;
+    struct {
+      const char* name;
+      size_t size;
+    } architecture;
   } data;
 };
 
 // Construct a context and connect to adbd.
 // Returns null if we fail to connect to adbd.
+// Note this is an apex interface as it's loaded by ART.
 AdbConnectionClientContext* adbconnection_client_new(
     const AdbConnectionClientInfo* const* info_elems, size_t info_count);
 
diff --git a/adb/libs/adbconnection/include/adbconnection/process_info.h b/adb/libs/adbconnection/include/adbconnection/process_info.h
new file mode 100644
index 0000000..86d3259
--- /dev/null
+++ b/adb/libs/adbconnection/include/adbconnection/process_info.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+#include <string>
+
+struct ProcessInfo {
+  const static size_t kMaxArchNameLength = 16;
+
+  uint64_t pid;
+  bool debuggable;
+  bool profileable;
+  int32_t arch_name_length;            // length of architecture name in bytes
+  char arch_name[kMaxArchNameLength];  // ISA name, e.g., "arm64"
+
+  ProcessInfo() : pid(0), debuggable(false), profileable(false), arch_name_length(0) {}
+
+  ProcessInfo(uint64_t pid, bool dbg, bool prof, const std::string& arch)
+      : pid(pid), debuggable(dbg), profileable(prof) {
+    arch_name_length = std::min(arch.size(), kMaxArchNameLength);
+    memcpy(arch_name, arch.data(), arch_name_length);
+  }
+};
diff --git a/adb/libs/adbconnection/include/adbconnection/server.h b/adb/libs/adbconnection/include/adbconnection/server.h
index 57ca6cd..b1059ba 100644
--- a/adb/libs/adbconnection/include/adbconnection/server.h
+++ b/adb/libs/adbconnection/include/adbconnection/server.h
@@ -20,7 +20,7 @@
 
 #include <android-base/unique_fd.h>
 
-extern "C" {
+#include "adbconnection/process_info.h"
 
-void adbconnection_listen(void (*callback)(int fd, pid_t pid));
-}
+// Note this is NOT an apex interface as it's linked only into adbd.
+void adbconnection_listen(void (*callback)(int fd, ProcessInfo process));
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index a7e5d9c..fe828a0 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -68,3 +68,61 @@
         "//apex_available:platform",
     ],
 }
+
+cc_defaults {
+    name: "libapp_processes_protos_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Werror",
+    ],
+
+    compile_multilib: "both",
+
+    srcs: [
+        "app_processes.proto",
+    ],
+    target: {
+        windows: {
+            compile_multilib: "first",
+            enabled: true,
+        },
+    },
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+    ],
+
+    stl: "libc++_static",
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
+cc_library {
+    name: "libapp_processes_protos_lite",
+    defaults: ["libapp_processes_protos_defaults"],
+
+    apex_available: ["//apex_available:platform"],
+
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+
+    host_supported: true,
+    recovery_available: true,
+}
+
+cc_library_host_static {
+    name: "libapp_processes_protos_full",
+    defaults: ["libapp_processes_protos_defaults"],
+
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+}
diff --git a/init/service_lock.cpp b/adb/proto/app_processes.proto
similarity index 64%
rename from init/service_lock.cpp
rename to adb/proto/app_processes.proto
index 404d439..1183645 100644
--- a/init/service_lock.cpp
+++ b/adb/proto/app_processes.proto
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-#include "service_lock.h"
+syntax = "proto3";
 
-namespace android {
-namespace init {
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "AppProcessesProto";
 
-RecursiveMutex service_lock;
+package adb.proto;
 
-}  // namespace init
-}  // namespace android
+message ProcessEntry {
+    int64 pid = 1;
+    bool debuggable = 2;
+    bool profileable = 3;
+    string architecture = 4;
+}
+
+message AppProcesses {
+  repeated ProcessEntry process = 1;
+}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 8b3461a..447a8fe 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -81,6 +81,7 @@
 const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
 const char* const kFeatureAbbExec = "abb_exec";
 const char* const kFeatureRemountShell = "remount_shell";
+const char* const kFeatureTrackApp = "track_app";
 
 namespace {
 
@@ -1175,6 +1176,7 @@
             kFeatureFixedPushSymlinkTimestamp,
             kFeatureAbbExec,
             kFeatureRemountShell,
+            kFeatureTrackApp,
             // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
             // to know about. Otherwise, the client can be stuck running an old
             // version of the server even after upgrading their copy of adb.
diff --git a/adb/transport.h b/adb/transport.h
index 8a0f62a..a62349e 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -82,6 +82,8 @@
 // adbd properly updates symlink timestamps on push.
 extern const char* const kFeatureFixedPushSymlinkTimestamp;
 extern const char* const kFeatureRemountShell;
+// adbd supports `track-app` service reporting debuggable/profileable apps.
+extern const char* const kFeatureTrackApp;
 
 TransportId NextTransportId();
 
diff --git a/base/Android.bp b/base/Android.bp
index f2e4122..12de3b2 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -47,6 +47,10 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_defaults {
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 1c3427f..c2c2cc4 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -84,17 +84,21 @@
 }
 
 cc_fuzz {
-  name: "dm_linear_table_fuzzer",
-  defaults: ["fs_mgr_defaults"],
-  srcs: [
-    "dm_linear_fuzzer.cpp",
-    "test_util.cpp",
-  ],
-  static_libs: [
+    name: "dm_linear_table_fuzzer",
+    defaults: ["fs_mgr_defaults"],
+    srcs: [
+        "dm_linear_fuzzer.cpp",
+        "test_util.cpp",
+    ],
+    static_libs: [
         "libdm",
         "libbase",
         "libext2_uuid",
         "libfs_mgr",
         "liblog",
-  ],
+    ],
+}
+
+vts_config {
+    name: "VtsKernelLibdmTest",
 }
diff --git a/fs_mgr/libdm/Android.mk b/fs_mgr/libdm/Android.mk
deleted file mode 100644
index 6aedc25..0000000
--- a/fs_mgr/libdm/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLibdmTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 254fbed..673e145 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -120,7 +120,7 @@
         return false;
     }
     if (!WaitForFileDeleted(unique_path, timeout_ms)) {
-        LOG(ERROR) << "Timeout out waiting for " << unique_path << " to be deleted";
+        LOG(ERROR) << "Failed waiting for " << unique_path << " to be deleted";
         return false;
     }
     return true;
@@ -161,7 +161,7 @@
         return true;
     }
     if (!WaitForFile(unique_path, timeout_ms)) {
-        LOG(ERROR) << "Timed out waiting for device path: " << unique_path;
+        LOG(ERROR) << "Failed waiting for device path: " << unique_path;
         DeleteDevice(name);
         return false;
     }
diff --git a/fs_mgr/libdm/utility.cpp b/fs_mgr/libdm/utility.cpp
index f252565..0eb59ab 100644
--- a/fs_mgr/libdm/utility.cpp
+++ b/fs_mgr/libdm/utility.cpp
@@ -19,6 +19,8 @@
 
 #include <thread>
 
+#include <android-base/logging.h>
+
 using namespace std::literals;
 
 namespace android {
@@ -45,7 +47,11 @@
         // If the file exists but returns EPERM or something, we consider the
         // condition met.
         if (access(path.c_str(), F_OK) != 0) {
-            if (errno == ENOENT) return WaitResult::Wait;
+            if (errno == ENOENT) {
+                return WaitResult::Wait;
+            }
+            PLOG(ERROR) << "access failed: " << path;
+            return WaitResult::Fail;
         }
         return WaitResult::Done;
     };
@@ -54,9 +60,13 @@
 
 bool WaitForFileDeleted(const std::string& path, const std::chrono::milliseconds& timeout_ms) {
     auto condition = [&]() -> WaitResult {
-        if (access(path.c_str(), F_OK) == 0 || errno != ENOENT) {
+        if (access(path.c_str(), F_OK) == 0) {
             return WaitResult::Wait;
         }
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "access failed: " << path;
+            return WaitResult::Fail;
+        }
         return WaitResult::Done;
     };
     return WaitForCondition(condition, timeout_ms);
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 96c36ed..5e29d4e 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -19,7 +19,6 @@
 #include <android-base/properties.h>
 #include <android/gsi/BnProgressCallback.h>
 #include <android/gsi/IGsiService.h>
-#include <android/gsi/IGsid.h>
 #include <binder/IServiceManager.h>
 #include <libfiemap/image_manager.h>
 #include <libgsi/libgsi.h>
@@ -225,54 +224,22 @@
     return false;
 }
 
-static android::sp<IGsid> AcquireIGsid(const std::chrono::milliseconds& timeout_ms) {
-    if (android::base::GetProperty("init.svc.gsid", "") != "running") {
-        if (!android::base::SetProperty("ctl.start", "gsid") ||
-            !android::base::WaitForProperty("init.svc.gsid", "running", timeout_ms)) {
-            LOG(ERROR) << "Could not start the gsid service";
-            return nullptr;
-        }
-        // Sleep for 250ms to give the service time to register.
-        usleep(250 * 1000);
-    }
+static sp<IGsiService> GetGsiService() {
     auto sm = android::defaultServiceManager();
     auto name = android::String16(kGsiServiceName);
-    auto service = sm->checkService(name);
-    return android::interface_cast<IGsid>(service);
-}
-
-static android::sp<IGsid> GetGsiService(const std::chrono::milliseconds& timeout_ms) {
-    auto start_time = std::chrono::steady_clock::now();
-
-    std::chrono::milliseconds elapsed = std::chrono::milliseconds::zero();
-    do {
-        if (auto gsid = AcquireIGsid(timeout_ms - elapsed); gsid != nullptr) {
-            return gsid;
-        }
-        auto now = std::chrono::steady_clock::now();
-        elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
-    } while (elapsed <= timeout_ms);
-
-    LOG(ERROR) << "Timed out trying to acquire IGsid interface";
+    android::sp<android::IBinder> res = sm->waitForService(name);
+    if (res) {
+        return android::interface_cast<IGsiService>(res);
+    }
     return nullptr;
 }
 
-std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir,
-                                                   const std::chrono::milliseconds& timeout_ms) {
-    auto gsid = GetGsiService(timeout_ms);
-    if (!gsid) {
-        return nullptr;
-    }
-
-    android::sp<IGsiService> service;
-    auto status = gsid->getClient(&service);
-    if (!status.isOk() || !service) {
-        LOG(ERROR) << "Could not acquire IGsiService";
-        return nullptr;
-    }
-
+std::unique_ptr<IImageManager> IImageManager::Open(
+        const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
+    android::sp<IGsiService> service = GetGsiService();
     android::sp<IImageService> manager;
-    status = service->openImageService(dir, &manager);
+
+    auto status = service->openImageService(dir, &manager);
     if (!status.isOk() || !manager) {
         LOG(ERROR) << "Could not acquire IImageManager: " << status.exceptionMessage().string();
         return nullptr;
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index ea0fca8..ad19f38 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -108,3 +108,6 @@
     defaults: ["liblp_test_defaults"],
 }
 
+vts_config {
+    name: "VtsKernelLiblpTest",
+}
diff --git a/fs_mgr/liblp/Android.mk b/fs_mgr/liblp/Android.mk
deleted file mode 100644
index 7f7f891..0000000
--- a/fs_mgr/liblp/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := VtsKernelLiblpTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 0a0a21d..d670ca0 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -96,16 +96,6 @@
     static_libs: [
         "libfs_mgr_binder"
     ],
-
-    shared_libs: [
-        // TODO(b/148818798): remove when parent bug is fixed
-        "libutilscallstack",
-    ],
-    cflags: [
-        "-g",
-        "-O0",
-        "-DLIBSNAPSHOT_USE_CALLSTACK",
-    ],
 }
 
 cc_library_static {
@@ -179,9 +169,6 @@
         "libsparse",
         "libutils",
         "libz",
-
-        // TODO(b/148818798): remove when parent bug is fixed
-        "libutilscallstack",
     ],
     static_libs: [
         "libfs_mgr",
@@ -231,8 +218,5 @@
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
-
-        // TODO(b/148818798): remove when parent bug is fixed.
-        "libutilscallstack",
     ],
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 32345d2..68a81ed 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -125,6 +125,9 @@
     // might be needed to perform first-stage mounts.
     static bool IsSnapshotManagerNeeded();
 
+    // Helper function for second stage init to restorecon on the rollback indicator.
+    static std::string GetGlobalRollbackIndicatorPath();
+
     // Begin an update. This must be called before creating any snapshots. It
     // will fail if GetUpdateState() != None.
     bool BeginUpdate();
@@ -175,16 +178,6 @@
     UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
                                    const std::function<bool()>& before_cancel = {});
 
-    // Initiate the merge if necessary, then wait for the merge to finish.
-    // See InitiateMerge() and ProcessUpdateState() for details.
-    // Returns:
-    //   - None if no merge to initiate
-    //   - Unverified if called on the source slot
-    //   - MergeCompleted if merge is completed
-    //   - other states indicating an error has occurred
-    UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
-                                     const std::function<bool()>& before_cancel = {});
-
     // Find the status of the current update, if any.
     //
     // |progress| depends on the returned status:
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 7f9c7f1..ed052b1 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,7 +21,6 @@
 #include <sys/unistd.h>
 
 #include <optional>
-#include <sstream>
 #include <thread>
 #include <unordered_set>
 
@@ -38,10 +37,6 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
-#include <utils/CallStack.h>
-#endif
-
 #include <android/snapshot/snapshot.pb.h>
 #include <libsnapshot/snapshot_stats.h>
 #include "device_info.h"
@@ -81,6 +76,7 @@
 using namespace std::string_literals;
 
 static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
+static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
 static constexpr auto kUpdateStateCheckInterval = 2s;
 
 // Note: IImageManager is an incomplete type in the header, so the default
@@ -227,25 +223,6 @@
 
     LOG(INFO) << "Removing all update state.";
 
-#ifdef LIBSNAPSHOT_USE_CALLSTACK
-    LOG(WARNING) << "Logging stack; see b/148818798.";
-    // Do not use CallStack's log functions because snapshotctl relies on
-    // android-base/logging to save log to files.
-    // TODO(b/148818798): remove this before we ship.
-    CallStack callstack;
-    callstack.update();
-    auto callstack_str = callstack.toString();
-    LOG(WARNING) << callstack_str.c_str();
-    std::stringstream path;
-    path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
-    std::string path_str = path.str();
-    android::base::WriteStringToFile(callstack_str.c_str(), path_str);
-    if (chmod(path_str.c_str(), 0644) == -1) {
-        PLOG(WARNING) << "Unable to chmod 0644 "
-                      << ", file maybe dropped from bugreport:" << path_str;
-    }
-#endif
-
     if (!RemoveAllSnapshots(lock)) {
         LOG(ERROR) << "Could not remove all snapshots";
         return false;
@@ -1012,7 +989,7 @@
 }
 
 std::string SnapshotManager::GetRollbackIndicatorPath() {
-    return metadata_dir_ + "/rollback-indicator";
+    return metadata_dir_ + "/" + android::base::Basename(kRollbackIndicatorPath);
 }
 
 void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
@@ -1469,6 +1446,10 @@
     return access(kBootIndicatorPath, F_OK) == 0;
 }
 
+std::string SnapshotManager::GetGlobalRollbackIndicatorPath() {
+    return kRollbackIndicatorPath;
+}
+
 bool SnapshotManager::NeedSnapshotsInFirstStageMount() {
     // If we fail to read, we'll wind up using CreateLogicalPartitions, which
     // will create devices that look like the old slot, except with extra
@@ -2493,68 +2474,6 @@
     return AutoUnmountDevice::New(device_->GetMetadataDir());
 }
 
-UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
-                                                  const std::function<bool()>& before_cancel) {
-    {
-        auto lock = LockExclusive();
-        // Sync update state from file with bootloader.
-        if (!WriteUpdateState(lock.get(), ReadUpdateState(lock.get()))) {
-            LOG(WARNING) << "Unable to sync write update state, fastboot may "
-                         << "reject / accept wipes incorrectly!";
-        }
-    }
-
-    auto merge_stats = SnapshotMergeStats::GetInstance(*this);
-
-    unsigned int last_progress = 0;
-    auto callback = [&]() -> bool {
-        double progress;
-        GetUpdateState(&progress);
-        if (last_progress < static_cast<unsigned int>(progress)) {
-            last_progress = progress;
-            LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
-        }
-        return true;  // continue
-    };
-
-    LOG(INFO) << "Waiting for any previous merge request to complete. "
-              << "This can take up to several minutes.";
-    merge_stats->Start();
-    auto state = ProcessUpdateState(callback, before_cancel);
-    merge_stats->set_state(state);
-    if (state == UpdateState::None) {
-        LOG(INFO) << "Can't find any snapshot to merge.";
-        return state;
-    }
-    if (state == UpdateState::Unverified) {
-        if (GetCurrentSlot() != Slot::Target) {
-            LOG(INFO) << "Cannot merge until device reboots.";
-            return state;
-        }
-
-        if (!InitiateMerge()) {
-            LOG(ERROR) << "Failed to initiate merge.";
-            return state;
-        }
-        // All other states can be handled by ProcessUpdateState.
-        LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
-        last_progress = 0;
-        state = ProcessUpdateState(callback, before_cancel);
-        merge_stats->set_state(state);
-    }
-
-    LOG(INFO) << "Merge finished with state \"" << state << "\".";
-    if (stats_report) {
-        auto result = merge_stats->Finish();
-        if (result) {
-            *stats_report = result->report();
-        } else {
-            LOG(WARNING) << "SnapshotMergeStatus::Finish failed.";
-        }
-    }
-    return state;
-}
-
 bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callback) {
     if (!device_->IsRecovery()) {
         LOG(ERROR) << "Data wipes are only allowed in recovery.";
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 7d16ec2..855451d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1027,7 +1027,8 @@
     }
 
     // Initiate the merge and wait for it to be completed.
-    ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+    ASSERT_TRUE(init->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
 
     // Check that the target partitions have the same content after the merge.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1201,7 +1202,8 @@
 
     // Initiate the merge and wait for it to be completed.
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
-    ASSERT_EQ(UpdateState::MergeCompleted, new_sm->InitiateMergeAndWait());
+    ASSERT_TRUE(new_sm->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeCompleted, new_sm->ProcessUpdateState());
 
     // Execute the second update.
     ASSERT_TRUE(new_sm->BeginUpdate());
@@ -1341,7 +1343,8 @@
     ASSERT_GE(fd, 0);
 
     // COW cannot be removed due to open fd, so expect a soft failure.
-    ASSERT_EQ(UpdateState::MergeNeedsReboot, init->InitiateMergeAndWait());
+    ASSERT_TRUE(init->InitiateMerge());
+    ASSERT_EQ(UpdateState::MergeNeedsReboot, init->ProcessUpdateState());
 
     // Simulate shutting down the device.
     fd.reset();
@@ -1354,7 +1357,7 @@
     ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
 
     // Merge should be able to complete now.
-    ASSERT_EQ(UpdateState::MergeCompleted, init->InitiateMergeAndWait());
+    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
 }
 
 class MetadataMountedTest : public SnapshotUpdateTest {
@@ -1691,7 +1694,8 @@
 
     // There should be no snapshot to merge.
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, flashed_slot_suffix));
-    ASSERT_EQ(UpdateState::Cancelled, new_sm->InitiateMergeAndWait());
+    // update_enigne calls ProcessUpdateState first -- should see Cancelled.
+    ASSERT_EQ(UpdateState::Cancelled, new_sm->ProcessUpdateState());
 
     // Next OTA calls CancelUpdate no matter what.
     ASSERT_TRUE(new_sm->CancelUpdate());
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index aa5e9c1..a44de84 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -24,12 +24,8 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
-#include <android/snapshot/snapshot.pb.h>
-#include <libsnapshot/snapshot.h>
-#include <libsnapshot/snapshot_stats.h>
-#include <statslog.h>
 
-#include "utility.h"
+#include <libsnapshot/snapshot.h>
 
 using namespace std::string_literals;
 
@@ -39,146 +35,22 @@
                  "Actions:\n"
                  "  dump\n"
                  "    Print snapshot states.\n"
-                 "  merge [--logcat] [--log-to-file] [--report] [--dry-run]\n"
-                 "    Initialize merge and wait for it to be completed.\n"
-                 "    If --logcat is specified, log to logcat.\n"
-                 "    If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
-                 "    If both specified, log to both. If none specified, log to stdout.\n"
-                 "    If --report is specified, send merge statistics to statsd.\n"
-                 "    If --dry-run flag, no real merge operation is is triggered, and\n"
-                 "      sample statistics are sent to statsd for testing purpose.\n";
+                 "  merge\n"
+                 "    Deprecated.\n";
     return EX_USAGE;
 }
 
 namespace android {
 namespace snapshot {
 
-static SnapshotMergeReport GetDummySnapshotMergeReport() {
-    SnapshotMergeReport fake_report;
-
-    fake_report.set_state(UpdateState::MergeCompleted);
-    fake_report.set_resume_count(56);
-
-    return fake_report;
-}
-
 bool DumpCmdHandler(int /*argc*/, char** argv) {
     android::base::InitLogging(argv, &android::base::StderrLogger);
     return SnapshotManager::New()->Dump(std::cout);
 }
 
-class FileLogger {
-  public:
-    FileLogger() {
-        static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
-        std::stringstream ss;
-        ss << kLogFilePath << "snapshotctl." << Now() << ".log";
-        fd_.reset(TEMP_FAILURE_RETRY(
-                open(ss.str().c_str(),
-                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0644)));
-        if (fd_ == -1) {
-            PLOG(ERROR) << "Cannot open persistent log " << ss.str();
-            return;
-        }
-        // Explicitly chmod again because mode in open() may be masked by umask.
-        if (fchmod(fd_.get(), 0644) == -1) {
-            PLOG(ERROR) << "Cannot chmod 0644 persistent log " << ss.str();
-            return;
-        }
-    }
-    // Copy-contuctor needed to be converted to std::function.
-    FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
-    void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
-                    const char* /*file*/, unsigned int /*line*/, const char* message) {
-        if (fd_ == -1) return;
-        std::stringstream ss;
-        ss << Now() << ":" << message << "\n";
-        (void)android::base::WriteStringToFd(ss.str(), fd_);
-    }
-
-  private:
-    android::base::unique_fd fd_;
-};
-
-class MergeCmdLogger {
-  public:
-    MergeCmdLogger(int argc, char** argv) {
-        for (int i = 0; i < argc; ++i) {
-            if (argv[i] == "--logcat"s) {
-                loggers_.push_back(android::base::LogdLogger());
-            }
-            if (argv[i] == "--log-to-file"s) {
-                loggers_.push_back(std::move(FileLogger()));
-            }
-        }
-        if (loggers_.empty()) {
-            loggers_.push_back(&android::base::StdioLogger);
-        }
-    }
-    void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
-                    const char* file, unsigned int line, const char* message) {
-        for (auto&& logger : loggers_) {
-            logger(id, severity, tag, file, line, message);
-        }
-    }
-
-  private:
-    std::vector<android::base::LogFunction> loggers_;
-};
-
-bool MergeCmdHandler(int argc, char** argv) {
-    std::chrono::milliseconds passed_ms;
-
-    bool report_to_statsd = false;
-    bool dry_run = false;
-    for (int i = 2; i < argc; ++i) {
-        if (argv[i] == "--report"s) {
-            report_to_statsd = true;
-        } else if (argv[i] == "--dry-run"s) {
-            dry_run = true;
-        }
-    }
-
-    // 'snapshotctl merge' is stripped away from arguments to
-    // Logger.
-    android::base::InitLogging(argv);
-    android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
-
-    UpdateState state;
-    SnapshotMergeReport merge_report;
-    if (dry_run) {
-        merge_report = GetDummySnapshotMergeReport();
-        state = merge_report.state();
-        passed_ms = std::chrono::milliseconds(1234);
-    } else {
-        auto begin = std::chrono::steady_clock::now();
-
-        state = SnapshotManager::New()->InitiateMergeAndWait(&merge_report);
-
-        // We could wind up in the Unverified state if the device rolled back or
-        // hasn't fully rebooted. Ignore this.
-        if (state == UpdateState::None || state == UpdateState::Unverified) {
-            return true;
-        }
-
-        auto end = std::chrono::steady_clock::now();
-        passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
-    }
-
-    if (report_to_statsd) {
-        android::util::stats_write(android::util::SNAPSHOT_MERGE_REPORTED,
-                                   static_cast<int32_t>(merge_report.state()),
-                                   static_cast<int64_t>(passed_ms.count()),
-                                   static_cast<int32_t>(merge_report.resume_count()));
-    }
-
-    if (state == UpdateState::MergeCompleted) {
-        LOG(INFO) << "Snapshot merged in " << passed_ms.count() << " ms.";
-        return true;
-    }
-
-    LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
-
+bool MergeCmdHandler(int /*argc*/, char** argv) {
+    android::base::InitLogging(argv, &android::base::StderrLogger);
+    LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
     return false;
 }
 
diff --git a/init/Android.bp b/init/Android.bp
index 52628f3..3bb08db 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -28,7 +28,6 @@
     "rlimit_parser.cpp",
     "service.cpp",
     "service_list.cpp",
-    "service_lock.cpp",
     "service_parser.cpp",
     "service_utils.cpp",
     "subcontext.cpp",
@@ -82,7 +81,6 @@
         "-Wextra",
         "-Wno-unused-parameter",
         "-Werror",
-        "-Wthread-safety",
         "-DALLOW_FIRST_STAGE_CONSOLE=0",
         "-DALLOW_LOCAL_PROP_OVERRIDE=0",
         "-DALLOW_PERMISSIVE_SELINUX=0",
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index b45f5cd..ebca762 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -41,12 +41,10 @@
 }
 
 void ActionManager::QueueEventTrigger(const std::string& trigger) {
-    auto lock = std::lock_guard{event_queue_lock_};
     event_queue_.emplace(trigger);
 }
 
 void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
-    auto lock = std::lock_guard{event_queue_lock_};
     event_queue_.emplace(std::make_pair(name, value));
 }
 
@@ -55,7 +53,6 @@
 }
 
 void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
-    auto lock = std::lock_guard{event_queue_lock_};
     auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
                                            std::map<std::string, std::string>{});
     action->AddCommand(std::move(func), {name}, 0);
@@ -65,18 +62,15 @@
 }
 
 void ActionManager::ExecuteOneCommand() {
-    {
-        auto lock = std::lock_guard{event_queue_lock_};
-        // Loop through the event queue until we have an action to execute
-        while (current_executing_actions_.empty() && !event_queue_.empty()) {
-            for (const auto& action : actions_) {
-                if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
-                               event_queue_.front())) {
-                    current_executing_actions_.emplace(action.get());
-                }
+    // Loop through the event queue until we have an action to execute
+    while (current_executing_actions_.empty() && !event_queue_.empty()) {
+        for (const auto& action : actions_) {
+            if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
+                           event_queue_.front())) {
+                current_executing_actions_.emplace(action.get());
             }
-            event_queue_.pop();
         }
+        event_queue_.pop();
     }
 
     if (current_executing_actions_.empty()) {
@@ -109,7 +103,6 @@
 }
 
 bool ActionManager::HasMoreCommands() const {
-    auto lock = std::lock_guard{event_queue_lock_};
     return !current_executing_actions_.empty() || !event_queue_.empty();
 }
 
@@ -120,7 +113,6 @@
 }
 
 void ActionManager::ClearQueue() {
-    auto lock = std::lock_guard{event_queue_lock_};
     // We are shutting down so don't claim the oneshot builtin actions back
     current_executing_actions_ = {};
     event_queue_ = {};
diff --git a/init/action_manager.h b/init/action_manager.h
index b6f93d9..a2b95ac 100644
--- a/init/action_manager.h
+++ b/init/action_manager.h
@@ -16,12 +16,9 @@
 
 #pragma once
 
-#include <mutex>
 #include <string>
 #include <vector>
 
-#include <android-base/thread_annotations.h>
-
 #include "action.h"
 #include "builtins.h"
 
@@ -51,9 +48,7 @@
     void operator=(ActionManager const&) = delete;
 
     std::vector<std::unique_ptr<Action>> actions_;
-    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_
-            GUARDED_BY(event_queue_lock_);
-    mutable std::mutex event_queue_lock_;
+    std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
     std::queue<const Action*> current_executing_actions_;
     std::size_t current_command_;
 };
diff --git a/init/builtins.cpp b/init/builtins.cpp
index dd5af72..200bfff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -151,7 +151,6 @@
 
 template <typename F>
 static void ForEachServiceInClass(const std::string& classname, F function) {
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(classname)) std::invoke(function, service);
     }
@@ -163,7 +162,6 @@
         return {};
     // Starting a class does not start services which are explicitly disabled.
     // They must  be started individually.
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfNotDisabled(); !result.ok()) {
@@ -186,7 +184,6 @@
         // stopped either.
         return {};
     }
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfPostData(); !result.ok()) {
@@ -237,7 +234,6 @@
 }
 
 static Result<void> do_enable(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "Could not find service";
 
@@ -249,7 +245,6 @@
 }
 
 static Result<void> do_exec(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec service: " << service.error();
@@ -263,7 +258,6 @@
 }
 
 static Result<void> do_exec_background(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     auto service = Service::MakeTemporaryOneshotService(args.args);
     if (!service.ok()) {
         return Error() << "Could not create exec background service: " << service.error();
@@ -277,7 +271,6 @@
 }
 
 static Result<void> do_exec_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* service = ServiceList::GetInstance().FindService(args[1]);
     if (!service) {
         return Error() << "Service not found";
@@ -347,7 +340,6 @@
 }
 
 static Result<void> do_interface_restart(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Restart();
@@ -355,7 +347,6 @@
 }
 
 static Result<void> do_interface_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -365,7 +356,6 @@
 }
 
 static Result<void> do_interface_stop(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
     svc->Stop();
@@ -750,7 +740,6 @@
 }
 
 static Result<void> do_start(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     if (auto result = svc->Start(); !result.ok()) {
@@ -760,7 +749,6 @@
 }
 
 static Result<void> do_stop(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Stop();
@@ -768,7 +756,6 @@
 }
 
 static Result<void> do_restart(const BuiltinArguments& args) {
-    auto lock = std::lock_guard{service_lock};
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
     svc->Restart();
@@ -1124,7 +1111,6 @@
             function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
         }
     });
-    auto lock = std::lock_guard{service_lock};
     if (auto result = (*service)->ExecStart(); !result.ok()) {
         function("ExecStart failed: " + result.error().message());
     }
@@ -1264,7 +1250,6 @@
         }
         success &= parser.ParseConfigFile(c);
     }
-    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().MarkServicesUpdate();
     if (success) {
         return {};
diff --git a/init/init.cpp b/init/init.cpp
index 63aefc1..a7518fc 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,9 +33,7 @@
 #include <functional>
 #include <map>
 #include <memory>
-#include <mutex>
 #include <optional>
-#include <thread>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -97,148 +95,15 @@
 static int signal_fd = -1;
 static int property_fd = -1;
 
+static std::unique_ptr<Timer> waiting_for_prop(nullptr);
+static std::string wait_prop_name;
+static std::string wait_prop_value;
+static std::string shutdown_command;
+static bool do_shutdown = false;
+
 static std::unique_ptr<Subcontext> subcontext;
 
-// Init epolls various FDs to wait for various inputs.  It previously waited on property changes
-// with a blocking socket that contained the information related to the change, however, it was easy
-// to fill that socket and deadlock the system.  Now we use locks to handle the property changes
-// directly in the property thread, however we still must wake the epoll to inform init that there
-// is a change to process, so we use this FD.  It is non-blocking, since we do not care how many
-// times WakeEpoll() is called, only that the epoll will wake.
-static int wake_epoll_fd = -1;
-static void InstallInitNotifier(Epoll* epoll) {
-    int sockets[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sockets) != 0) {
-        PLOG(FATAL) << "Failed to socketpair() between property_service and init";
-    }
-    int epoll_fd = sockets[0];
-    wake_epoll_fd = sockets[1];
-
-    auto drain_socket = [epoll_fd] {
-        char buf[512];
-        while (read(epoll_fd, buf, sizeof(buf)) > 0) {
-        }
-    };
-
-    if (auto result = epoll->RegisterHandler(epoll_fd, drain_socket); !result.ok()) {
-        LOG(FATAL) << result.error();
-    }
-}
-
-static void WakeEpoll() {
-    constexpr char value[] = "1";
-    write(wake_epoll_fd, value, sizeof(value));
-}
-
-static class PropWaiterState {
-  public:
-    bool StartWaiting(const char* name, const char* value) {
-        auto lock = std::lock_guard{lock_};
-        if (waiting_for_prop_) {
-            return false;
-        }
-        if (GetProperty(name, "") != value) {
-            // Current property value is not equal to expected value
-            wait_prop_name_ = name;
-            wait_prop_value_ = value;
-            waiting_for_prop_.reset(new Timer());
-        } else {
-            LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value
-                      << "\"): already set";
-        }
-        return true;
-    }
-
-    void ResetWaitForProp() {
-        auto lock = std::lock_guard{lock_};
-        ResetWaitForPropLocked();
-    }
-
-    void CheckAndResetWait(const std::string& name, const std::string& value) {
-        auto lock = std::lock_guard{lock_};
-        // We always record how long init waited for ueventd to tell us cold boot finished.
-        // If we aren't waiting on this property, it means that ueventd finished before we even
-        // started to wait.
-        if (name == kColdBootDoneProp) {
-            auto time_waited = waiting_for_prop_ ? waiting_for_prop_->duration().count() : 0;
-            std::thread([time_waited] {
-                SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
-            }).detach();
-        }
-
-        if (waiting_for_prop_) {
-            if (wait_prop_name_ == name && wait_prop_value_ == value) {
-                LOG(INFO) << "Wait for property '" << wait_prop_name_ << "=" << wait_prop_value_
-                          << "' took " << *waiting_for_prop_;
-                ResetWaitForPropLocked();
-                WakeEpoll();
-            }
-        }
-    }
-
-    // This is not thread safe because it releases the lock when it returns, so the waiting state
-    // may change.  However, we only use this function to prevent running commands in the main
-    // thread loop when we are waiting, so we do not care about false positives; only false
-    // negatives.  StartWaiting() and this function are always called from the same thread, so false
-    // negatives are not possible and therefore we're okay.
-    bool MightBeWaiting() {
-        auto lock = std::lock_guard{lock_};
-        return static_cast<bool>(waiting_for_prop_);
-    }
-
-  private:
-    void ResetWaitForPropLocked() {
-        wait_prop_name_.clear();
-        wait_prop_value_.clear();
-        waiting_for_prop_.reset();
-    }
-
-    std::mutex lock_;
-    std::unique_ptr<Timer> waiting_for_prop_{nullptr};
-    std::string wait_prop_name_;
-    std::string wait_prop_value_;
-
-} prop_waiter_state;
-
-bool start_waiting_for_property(const char* name, const char* value) {
-    return prop_waiter_state.StartWaiting(name, value);
-}
-
-void ResetWaitForProp() {
-    prop_waiter_state.ResetWaitForProp();
-}
-
-static class ShutdownState {
-  public:
-    void TriggerShutdown(const std::string& command) {
-        // We can't call HandlePowerctlMessage() directly in this function,
-        // because it modifies the contents of the action queue, which can cause the action queue
-        // to get into a bad state if this function is called from a command being executed by the
-        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
-        // command is run in the main init loop.
-        auto lock = std::lock_guard{shutdown_command_lock_};
-        shutdown_command_ = command;
-        do_shutdown_ = true;
-        WakeEpoll();
-    }
-
-    std::optional<std::string> CheckShutdown() {
-        auto lock = std::lock_guard{shutdown_command_lock_};
-        if (do_shutdown_ && !IsShuttingDown()) {
-            do_shutdown_ = false;
-            return shutdown_command_;
-        }
-        return {};
-    }
-
-  private:
-    std::mutex shutdown_command_lock_;
-    std::string shutdown_command_;
-    bool do_shutdown_ = false;
-} shutdown_state;
-
 void DumpState() {
-    auto lock = std::lock_guard{service_lock};
     ServiceList::GetInstance().DumpState();
     ActionManager::GetInstance().DumpState();
 }
@@ -291,7 +156,39 @@
     }
 }
 
-void PropertyChanged(const std::string& name, const std::string& value) {
+bool start_waiting_for_property(const char* name, const char* value) {
+    if (waiting_for_prop) {
+        return false;
+    }
+    if (GetProperty(name, "") != value) {
+        // Current property value is not equal to expected value
+        wait_prop_name = name;
+        wait_prop_value = value;
+        waiting_for_prop.reset(new Timer());
+    } else {
+        LOG(INFO) << "start_waiting_for_property(\"" << name << "\", \"" << value
+                  << "\"): already set";
+    }
+    return true;
+}
+
+void ResetWaitForProp() {
+    wait_prop_name.clear();
+    wait_prop_value.clear();
+    waiting_for_prop.reset();
+}
+
+static void TriggerShutdown(const std::string& command) {
+    // We can't call HandlePowerctlMessage() directly in this function,
+    // because it modifies the contents of the action queue, which can cause the action queue
+    // to get into a bad state if this function is called from a command being executed by the
+    // action queue.  Instead we set this flag and ensure that shutdown happens before the next
+    // command is run in the main init loop.
+    shutdown_command = command;
+    do_shutdown = true;
+}
+
+void property_changed(const std::string& name, const std::string& value) {
     // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
     // This is to ensure that init will always and immediately shutdown/reboot, regardless of
     // if there are other pending events to process or if init is waiting on an exec service or
@@ -299,20 +196,30 @@
     // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
     // commands to be executed.
     if (name == "sys.powerctl") {
-        trigger_shutdown(value);
+        TriggerShutdown(value);
     }
 
-    if (property_triggers_enabled) {
-        ActionManager::GetInstance().QueuePropertyChange(name, value);
-        WakeEpoll();
+    if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
+
+    // We always record how long init waited for ueventd to tell us cold boot finished.
+    // If we aren't waiting on this property, it means that ueventd finished before we even started
+    // to wait.
+    if (name == kColdBootDoneProp) {
+        auto time_waited = waiting_for_prop ? waiting_for_prop->duration().count() : 0;
+        SetProperty("ro.boottime.init.cold_boot_wait", std::to_string(time_waited));
     }
 
-    prop_waiter_state.CheckAndResetWait(name, value);
+    if (waiting_for_prop) {
+        if (wait_prop_name == name && wait_prop_value == value) {
+            LOG(INFO) << "Wait for property '" << wait_prop_name << "=" << wait_prop_value
+                      << "' took " << *waiting_for_prop;
+            ResetWaitForProp();
+        }
+    }
 }
 
 static std::optional<boot_clock::time_point> HandleProcessActions() {
     std::optional<boot_clock::time_point> next_process_action_time;
-    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         if ((s->flags() & SVC_RUNNING) && s->timeout_period()) {
             auto timeout_time = s->time_started() + *s->timeout_period();
@@ -341,7 +248,7 @@
     return next_process_action_time;
 }
 
-static Result<void> DoControlStart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlStart(Service* service) {
     return service->Start();
 }
 
@@ -350,7 +257,7 @@
     return {};
 }
 
-static Result<void> DoControlRestart(Service* service) REQUIRES(service_lock) {
+static Result<void> DoControlRestart(Service* service) {
     service->Restart();
     return {};
 }
@@ -384,7 +291,7 @@
     return control_message_functions;
 }
 
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid) {
+bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t pid) {
     const auto& map = get_control_message_map();
     const auto it = map.find(msg);
 
@@ -393,7 +300,7 @@
         return false;
     }
 
-    std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
+    std::string cmdline_path = StringPrintf("proc/%d/cmdline", pid);
     std::string process_cmdline;
     if (ReadFileToString(cmdline_path, &process_cmdline)) {
         std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' ');
@@ -404,8 +311,6 @@
 
     const ControlMessageFunction& function = it->second;
 
-    auto lock = std::lock_guard{service_lock};
-
     Service* svc = nullptr;
 
     switch (function.target) {
@@ -423,24 +328,23 @@
 
     if (svc == nullptr) {
         LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << msg
-                   << " from pid: " << from_pid << " (" << process_cmdline << ")";
+                   << " from pid: " << pid << " (" << process_cmdline << ")";
         return false;
     }
 
     if (auto result = function.action(svc); !result.ok()) {
         LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
-                   << "' from pid: " << from_pid << " (" << process_cmdline
-                   << "): " << result.error();
+                   << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
         return false;
     }
 
     LOG(INFO) << "Control message: Processed ctl." << msg << " for '" << name
-              << "' from pid: " << from_pid << " (" << process_cmdline << ")";
+              << "' from pid: " << pid << " (" << process_cmdline << ")";
     return true;
 }
 
 static Result<void> wait_for_coldboot_done_action(const BuiltinArguments& args) {
-    if (!prop_waiter_state.StartWaiting(kColdBootDoneProp, "true")) {
+    if (!start_waiting_for_property(kColdBootDoneProp, "true")) {
         LOG(FATAL) << "Could not wait for '" << kColdBootDoneProp << "'";
     }
 
@@ -588,7 +492,6 @@
     }
 
     auto found = false;
-    auto lock = std::lock_guard{service_lock};
     for (const auto& service : ServiceList::GetInstance()) {
         auto svc = service.get();
         if (svc->keycodes() == keycodes) {
@@ -675,6 +578,44 @@
     }
 }
 
+static void HandlePropertyFd() {
+    auto message = ReadMessage(property_fd);
+    if (!message.ok()) {
+        LOG(ERROR) << "Could not read message from property service: " << message.error();
+        return;
+    }
+
+    auto property_message = PropertyMessage{};
+    if (!property_message.ParseFromString(*message)) {
+        LOG(ERROR) << "Could not parse message from property service";
+        return;
+    }
+
+    switch (property_message.msg_case()) {
+        case PropertyMessage::kControlMessage: {
+            auto& control_message = property_message.control_message();
+            bool success = HandleControlMessage(control_message.msg(), control_message.name(),
+                                                control_message.pid());
+
+            uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+            if (control_message.has_fd()) {
+                int fd = control_message.fd();
+                TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
+                close(fd);
+            }
+            break;
+        }
+        case PropertyMessage::kChangedMessage: {
+            auto& changed_message = property_message.changed_message();
+            property_changed(changed_message.name(), changed_message.value());
+            break;
+        }
+        default:
+            LOG(ERROR) << "Unknown message type from property service: "
+                       << property_message.msg_case();
+    }
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -682,7 +623,7 @@
 
     boot_clock::time_point start_time = boot_clock::now();
 
-    trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
+    trigger_shutdown = TriggerShutdown;
 
     SetStdioToDevNull(argv);
     InitKernelLogging(argv);
@@ -742,8 +683,11 @@
     }
 
     InstallSignalFdHandler(&epoll);
-    InstallInitNotifier(&epoll);
+
     StartPropertyService(&property_fd);
+    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) {
+        LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
+    }
 
     // Make the time that init stages started available for bootstat to log.
     RecordStageBoottimes(start_time);
@@ -796,7 +740,6 @@
     Keychords keychords;
     am.QueueBuiltinAction(
             [&epoll, &keychords](const BuiltinArguments& args) -> Result<void> {
-                auto lock = std::lock_guard{service_lock};
                 for (const auto& svc : ServiceList::GetInstance()) {
                     keychords.Register(svc->keycodes());
                 }
@@ -827,12 +770,12 @@
         // By default, sleep until something happens.
         auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
 
-        auto shutdown_command = shutdown_state.CheckShutdown();
-        if (shutdown_command) {
-            HandlePowerctlMessage(*shutdown_command);
+        if (do_shutdown && !IsShuttingDown()) {
+            do_shutdown = false;
+            HandlePowerctlMessage(shutdown_command);
         }
 
-        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
+        if (!(waiting_for_prop || Service::is_exec_service_running())) {
             am.ExecuteOneCommand();
         }
         if (!IsShuttingDown()) {
@@ -846,7 +789,7 @@
             }
         }
 
-        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
+        if (!(waiting_for_prop || Service::is_exec_service_running())) {
             // If there's more work to do, wake up again immediately.
             if (am.HasMoreCommands()) epoll_timeout = 0ms;
         }
diff --git a/init/init.h b/init/init.h
index bcf24e7..4bbca6f 100644
--- a/init/init.h
+++ b/init/init.h
@@ -41,9 +41,6 @@
 void SendStopSendingMessagesMessage();
 void SendStartSendingMessagesMessage();
 
-void PropertyChanged(const std::string& name, const std::string& value);
-bool HandleControlMessage(const std::string& msg, const std::string& name, pid_t from_pid);
-
 int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 3053bd8..caf3e03 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -167,7 +167,6 @@
 
     ServiceList service_list;
     TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
-    auto lock = std::lock_guard{service_lock};
     ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
 
     auto service = service_list.begin()->get();
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
index a531d0a..dd1ab4d 100644
--- a/init/lmkd_service.cpp
+++ b/init/lmkd_service.cpp
@@ -79,8 +79,7 @@
 }
 
 static void RegisterServices(pid_t exclude_pid) {
-    auto lock = std::lock_guard{service_lock};
-    for (const auto& service : ServiceList::GetInstance()) {
+    for (const auto& service : ServiceList::GetInstance().services()) {
         auto svc = service.get();
         if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
             // skip if process is excluded or not yet forked (pid==0)
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 2175075..0749fe3 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -29,7 +29,6 @@
 #include <android-base/unique_fd.h>
 #include <apex_manifest.pb.h>
 
-#include "property_service.h"
 #include "util.h"
 
 namespace android {
@@ -291,14 +290,6 @@
         return true;
     }
     if (default_ns_id != GetMountNamespaceId()) {
-        // The property service thread and its descendent threads must be in the correct mount
-        // namespace to call Service::Start(), however setns() only operates on a single thread and
-        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
-        // must join the property service thread and its descendents before the setns() call.  Those
-        // threads are then started again after the setns() call, and they'll be in the proper
-        // namespace.
-        PausePropertyService();
-
         if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
             return false;
@@ -308,8 +299,6 @@
             LOG(ERROR) << result.error();
             return false;
         }
-
-        ResumePropertyService();
     }
 
     LOG(INFO) << "Switched to default mount namespace";
@@ -323,20 +312,10 @@
     }
     if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
         IsApexUpdatable()) {
-        // The property service thread and its descendent threads must be in the correct mount
-        // namespace to call Service::Start(), however setns() only operates on a single thread and
-        // fails when secondary threads attempt to join the same mount namespace.  Therefore, we
-        // must join the property service thread and its descendents before the setns() call.  Those
-        // threads are then started again after the setns() call, and they'll be in the proper
-        // namespace.
-        PausePropertyService();
-
         if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
             PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
             return false;
         }
-
-        ResumePropertyService();
     }
     return true;
 }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 319a241..730bf6d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -92,10 +92,8 @@
 static bool persistent_properties_loaded = false;
 
 static int property_set_fd = -1;
-static int from_init_socket = -1;
 static int init_socket = -1;
 static bool accept_messages = false;
-static std::thread property_service_thread;
 
 static PropertyInfoAreaFile property_info_area;
 
@@ -149,6 +147,17 @@
     return has_access;
 }
 
+static void SendPropertyChanged(const std::string& name, const std::string& value) {
+    auto property_msg = PropertyMessage{};
+    auto* changed_message = property_msg.mutable_changed_message();
+    changed_message->set_name(name);
+    changed_message->set_value(value);
+
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
+        LOG(ERROR) << "Failed to send property changed message: " << result.error();
+    }
+}
+
 static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
     size_t valuelen = value.size();
 
@@ -187,137 +196,47 @@
     // If init hasn't started its main loop, then it won't be handling property changed messages
     // anyway, so there's no need to try to send them.
     if (accept_messages) {
-        PropertyChanged(name, value);
+        SendPropertyChanged(name, value);
     }
     return PROP_SUCCESS;
 }
 
-template <typename T>
-class SingleThreadExecutor {
+class AsyncRestorecon {
   public:
-    virtual ~SingleThreadExecutor() {}
-
-    template <typename F = T>
-    void Run(F&& item) {
+    void TriggerRestorecon(const std::string& path) {
         auto guard = std::lock_guard{mutex_};
-        items_.emplace(std::forward<F>(item));
+        paths_.emplace(path);
 
-        if (thread_state_ == ThreadState::kRunning || thread_state_ == ThreadState::kStopped) {
-            return;
-        }
-
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        }
-
-        StartThread();
-    }
-
-    void StopAndJoin() {
-        auto lock = std::unique_lock{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-        } else if (thread_state_ == ThreadState::kRunning) {
-            thread_state_ = ThreadState::kStopped;
-            lock.unlock();
-            thread_.join();
-            lock.lock();
-        }
-
-        thread_state_ = ThreadState::kStopped;
-    }
-
-    void Restart() {
-        auto guard = std::lock_guard{mutex_};
-        if (items_.empty()) {
-            thread_state_ = ThreadState::kNotStarted;
-        } else {
-            StartThread();
-        }
-    }
-
-    void MaybeJoin() {
-        auto guard = std::lock_guard{mutex_};
-        if (thread_state_ == ThreadState::kPendingJoin) {
-            thread_.join();
-            thread_state_ = ThreadState::kNotStarted;
+        if (!thread_started_) {
+            thread_started_ = true;
+            std::thread{&AsyncRestorecon::ThreadFunction, this}.detach();
         }
     }
 
   private:
-    virtual void Execute(T&& item) = 0;
-
-    void StartThread() {
-        thread_state_ = ThreadState::kRunning;
-        auto thread = std::thread{&SingleThreadExecutor::ThreadFunction, this};
-        std::swap(thread_, thread);
-    }
-
     void ThreadFunction() {
         auto lock = std::unique_lock{mutex_};
 
-        while (!items_.empty()) {
-            auto item = items_.front();
-            items_.pop();
+        while (!paths_.empty()) {
+            auto path = paths_.front();
+            paths_.pop();
 
             lock.unlock();
-            Execute(std::move(item));
+            if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+                LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
+            }
+            android::base::SetProperty(kRestoreconProperty, path);
             lock.lock();
         }
 
-        if (thread_state_ != ThreadState::kStopped) {
-            thread_state_ = ThreadState::kPendingJoin;
-        }
+        thread_started_ = false;
     }
 
     std::mutex mutex_;
-    std::queue<T> items_;
-    enum class ThreadState {
-        kNotStarted,  // Initial state when starting the program or when restarting with no items to
-                      // process.
-        kRunning,     // The thread is running and is in a state that it will process new items if
-                      // are run.
-        kPendingJoin,  // The thread has run to completion and is pending join().  A new thread must
-                       // be launched for new items to be processed.
-        kStopped,  // This executor has stopped and will not process more items until Restart() is
-                   // called.  Currently pending items will be processed and the thread will be
-                   // joined.
-    };
-    ThreadState thread_state_ = ThreadState::kNotStarted;
-    std::thread thread_;
+    std::queue<std::string> paths_;
+    bool thread_started_ = false;
 };
 
-class RestoreconThread : public SingleThreadExecutor<std::string> {
-    virtual void Execute(std::string&& path) override {
-        if (selinux_android_restorecon(path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
-            LOG(ERROR) << "Asynchronous restorecon of '" << path << "' failed'";
-        }
-        android::base::SetProperty(kRestoreconProperty, path);
-    }
-};
-
-struct ControlMessageInfo {
-    std::string message;
-    std::string name;
-    pid_t pid;
-    int fd;
-};
-
-class ControlMessageThread : public SingleThreadExecutor<ControlMessageInfo> {
-    virtual void Execute(ControlMessageInfo&& info) override {
-        bool success = HandleControlMessage(info.message, info.name, info.pid);
-
-        uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE;
-        if (info.fd != -1) {
-            TEMP_FAILURE_RETRY(send(info.fd, &response, sizeof(response), 0));
-            close(info.fd);
-        }
-    }
-};
-
-static RestoreconThread restorecon_thread;
-static ControlMessageThread control_message_thread;
-
 class SocketConnection {
   public:
     SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
@@ -459,17 +378,29 @@
         return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
     }
 
-    // We must release the fd before spawning the thread, otherwise there will be a race with the
-    // thread. If the thread calls close() before this function calls Release(), then fdsan will see
-    // the wrong tag and abort().
+    auto property_msg = PropertyMessage{};
+    auto* control_message = property_msg.mutable_control_message();
+    control_message->set_msg(msg);
+    control_message->set_name(name);
+    control_message->set_pid(pid);
+
+    // We must release the fd before sending it to init, otherwise there will be a race with init.
+    // If init calls close() before Release(), then fdsan will see the wrong tag and abort().
     int fd = -1;
     if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__) {
         fd = socket->Release();
+        control_message->set_fd(fd);
     }
 
-    // Handling a control message likely calls SetProperty, which we must synchronously handle,
-    // therefore we must fork a thread to handle it.
-    control_message_thread.Run({msg, name, pid, fd});
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
+        // We've already released the fd above, so if we fail to send the message to init, we need
+        // to manually free it here.
+        if (fd != -1) {
+            close(fd);
+        }
+        *error = "Failed to send control message: " + result.error().message();
+        return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
+    }
 
     return PROP_SUCCESS;
 }
@@ -571,7 +502,8 @@
     // We use a thread to do this restorecon operation to prevent holding up init, as it may take
     // a long time to complete.
     if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
-        restorecon_thread.Run(value);
+        static AsyncRestorecon async_restorecon;
+        async_restorecon.TriggerRestorecon(value);
         return PROP_SUCCESS;
     }
 
@@ -1152,8 +1084,6 @@
     PropertyLoadBootDefaults();
 }
 
-static bool pause_property_service = false;
-
 static void HandleInitSocket() {
     auto message = ReadMessage(init_socket);
     if (!message.ok()) {
@@ -1188,10 +1118,6 @@
             accept_messages = true;
             break;
         }
-        case InitMessage::kPausePropertyService: {
-            pause_property_service = true;
-            break;
-        }
         default:
             LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
     }
@@ -1212,7 +1138,7 @@
         LOG(FATAL) << result.error();
     }
 
-    while (!pause_property_service) {
+    while (true) {
         auto pending_functions = epoll.Wait(std::nullopt);
         if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
@@ -1221,34 +1147,9 @@
                 (*function)();
             }
         }
-        control_message_thread.MaybeJoin();
-        restorecon_thread.MaybeJoin();
     }
 }
 
-void SendStopPropertyServiceMessage() {
-    auto init_message = InitMessage{};
-    init_message.set_pause_property_service(true);
-    if (auto result = SendMessage(from_init_socket, init_message); !result.ok()) {
-        LOG(ERROR) << "Failed to send stop property service message: " << result.error();
-    }
-}
-
-void PausePropertyService() {
-    control_message_thread.StopAndJoin();
-    restorecon_thread.StopAndJoin();
-    SendStopPropertyServiceMessage();
-    property_service_thread.join();
-}
-
-void ResumePropertyService() {
-    pause_property_service = false;
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
-    restorecon_thread.Restart();
-    control_message_thread.Restart();
-}
-
 void StartPropertyService(int* epoll_socket) {
     InitPropertySet("ro.property_service.version", "2");
 
@@ -1256,7 +1157,7 @@
     if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
         PLOG(FATAL) << "Failed to socketpair() between property_service and init";
     }
-    *epoll_socket = from_init_socket = sockets[0];
+    *epoll_socket = sockets[0];
     init_socket = sockets[1];
     accept_messages = true;
 
@@ -1270,8 +1171,7 @@
 
     listen(property_set_fd, 8);
 
-    auto new_thread = std::thread{PropertyServiceThread};
-    property_service_thread.swap(new_thread);
+    std::thread{PropertyServiceThread}.detach();
 }
 
 }  // namespace init
diff --git a/init/property_service.h b/init/property_service.h
index e921326..506d116 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -31,8 +31,6 @@
 
 void PropertyInit();
 void StartPropertyService(int* epoll_socket);
-void ResumePropertyService();
-void PausePropertyService();
 
 }  // namespace init
 }  // namespace android
diff --git a/init/property_service.proto b/init/property_service.proto
index 36245b2..08268d9 100644
--- a/init/property_service.proto
+++ b/init/property_service.proto
@@ -41,6 +41,5 @@
         bool load_persistent_properties = 1;
         bool stop_sending_messages = 2;
         bool start_sending_messages = 3;
-        bool pause_property_service = 4;
     };
 }
diff --git a/init/reboot.cpp b/init/reboot.cpp
index cad192d..8d8bd8e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -85,7 +85,7 @@
 
 static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
 
-static std::vector<Service*> GetDebuggingServices(bool only_post_data) REQUIRES(service_lock) {
+static std::vector<Service*> GetDebuggingServices(bool only_post_data) {
     std::vector<Service*> ret;
     ret.reserve(kDebuggingServices.size());
     for (const auto& s : ServiceList::GetInstance()) {
@@ -181,7 +181,7 @@
 };
 
 // Turn off backlight while we are performing power down cleanup activities.
-static void TurnOffBacklight() REQUIRES(service_lock) {
+static void TurnOffBacklight() {
     Service* service = ServiceList::GetInstance().FindService("blank_screen");
     if (service == nullptr) {
         LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
@@ -589,7 +589,6 @@
     // Start reboot monitor thread
     sem_post(&reboot_semaphore);
 
-    auto lock = std::lock_guard{service_lock};
     // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
     const std::set<std::string> to_starts{"watchdogd"};
     std::vector<Service*> stop_first;
@@ -709,7 +708,6 @@
     // Skip wait for prop if it is in progress
     ResetWaitForProp();
     // Clear EXEC flag if there is one pending
-    auto lock = std::lock_guard{service_lock};
     for (const auto& s : ServiceList::GetInstance()) {
         s->UnSetExec();
     }
@@ -753,7 +751,6 @@
         return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
     }
     EnterShutdown();
-    auto lock = std::lock_guard{service_lock};
     if (!SetProperty("sys.powerctl", "")) {
         return Error() << "Failed to reset sys.powerctl property";
     }
@@ -914,7 +911,6 @@
                 run_fsck = true;
             } else if (cmd_params[1] == "thermal") {
                 // Turn off sources of heat immediately.
-                auto lock = std::lock_guard{service_lock};
                 TurnOffBacklight();
                 // run_fsck is false to avoid delay
                 cmd = ANDROID_RB_THERMOFF;
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2faa167..acbcbd6 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -66,6 +66,7 @@
 #include <android-base/unique_fd.h>
 #include <fs_avb/fs_avb.h>
 #include <libgsi/libgsi.h>
+#include <libsnapshot/snapshot.h>
 #include <selinux/android.h>
 
 #include "debug_ramdisk.h"
@@ -78,6 +79,7 @@
 using android::base::Timer;
 using android::base::unique_fd;
 using android::fs_mgr::AvbHandle;
+using android::snapshot::SnapshotManager;
 
 namespace android {
 namespace init {
@@ -538,6 +540,8 @@
     // adb remount, snapshot-based updates, and DSUs all create files during
     // first-stage init.
     selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
+
+    selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.h b/init/service.h
index d2a4462..cf3f0c2 100644
--- a/init/service.h
+++ b/init/service.h
@@ -27,14 +27,12 @@
 #include <vector>
 
 #include <android-base/chrono_utils.h>
-#include <android-base/thread_annotations.h>
 #include <cutils/iosched_policy.h>
 
 #include "action.h"
 #include "capabilities.h"
 #include "keyword_map.h"
 #include "parser.h"
-#include "service_lock.h"
 #include "service_utils.h"
 #include "subcontext.h"
 
@@ -79,17 +77,17 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool IsEnabled() { return (flags_ & SVC_DISABLED) == 0; }
-    Result<void> ExecStart() REQUIRES(service_lock);
-    Result<void> Start() REQUIRES(service_lock);
-    Result<void> StartIfNotDisabled() REQUIRES(service_lock);
-    Result<void> StartIfPostData() REQUIRES(service_lock);
-    Result<void> Enable() REQUIRES(service_lock);
+    Result<void> ExecStart();
+    Result<void> Start();
+    Result<void> StartIfNotDisabled();
+    Result<void> StartIfPostData();
+    Result<void> Enable();
     void Reset();
     void ResetIfPostData();
     void Stop();
     void Terminate();
     void Timeout();
-    void Restart() REQUIRES(service_lock);
+    void Restart();
     void Reap(const siginfo_t& siginfo);
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
diff --git a/init/service_list.h b/init/service_list.h
index 280a228..3b9018b 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -17,13 +17,9 @@
 #pragma once
 
 #include <memory>
-#include <mutex>
 #include <vector>
 
-#include <android-base/thread_annotations.h>
-
 #include "service.h"
-#include "service_lock.h"
 
 namespace android {
 namespace init {
@@ -36,16 +32,16 @@
     ServiceList();
     size_t CheckAllCommands();
 
-    void AddService(std::unique_ptr<Service> service) REQUIRES(service_lock);
-    void RemoveService(const Service& svc) REQUIRES(service_lock);
+    void AddService(std::unique_ptr<Service> service);
+    void RemoveService(const Service& svc);
     template <class UnaryPredicate>
-    void RemoveServiceIf(UnaryPredicate predicate) REQUIRES(service_lock) {
+    void RemoveServiceIf(UnaryPredicate predicate) {
         services_.erase(std::remove_if(services_.begin(), services_.end(), predicate),
                         services_.end());
     }
 
     template <typename T, typename F = decltype(&Service::name)>
-    Service* FindService(T value, F function = &Service::name) const REQUIRES(service_lock) {
+    Service* FindService(T value, F function = &Service::name) const {
         auto svc = std::find_if(services_.begin(), services_.end(),
                                 [&function, &value](const std::unique_ptr<Service>& s) {
                                     return std::invoke(function, s) == value;
@@ -56,7 +52,7 @@
         return nullptr;
     }
 
-    Service* FindInterface(const std::string& interface_name) REQUIRES(service_lock) {
+    Service* FindInterface(const std::string& interface_name) {
         for (const auto& svc : services_) {
             if (svc->interfaces().count(interface_name) > 0) {
                 return svc.get();
@@ -66,20 +62,18 @@
         return nullptr;
     }
 
-    void DumpState() const REQUIRES(service_lock);
+    void DumpState() const;
 
-    auto begin() const REQUIRES(service_lock) { return services_.begin(); }
-    auto end() const REQUIRES(service_lock) { return services_.end(); }
-    const std::vector<std::unique_ptr<Service>>& services() const REQUIRES(service_lock) {
-        return services_;
-    }
-    const std::vector<Service*> services_in_shutdown_order() const REQUIRES(service_lock);
+    auto begin() const { return services_.begin(); }
+    auto end() const { return services_.end(); }
+    const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
+    const std::vector<Service*> services_in_shutdown_order() const;
 
     void MarkPostData();
     bool IsPostData();
-    void MarkServicesUpdate() REQUIRES(service_lock);
+    void MarkServicesUpdate();
     bool IsServicesUpdated() const { return services_update_finished_; }
-    void DelayService(const Service& service) REQUIRES(service_lock);
+    void DelayService(const Service& service);
 
     void ResetState() {
         post_data_ = false;
diff --git a/init/service_lock.h b/init/service_lock.h
deleted file mode 100644
index 6b94271..0000000
--- a/init/service_lock.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <mutex>
-
-#include <android-base/thread_annotations.h>
-
-namespace android {
-namespace init {
-
-// This class exists to add thread annotations, since they're absent from std::recursive_mutex.
-
-class CAPABILITY("mutex") RecursiveMutex {
-  public:
-    void lock() ACQUIRE() { mutex_.lock(); }
-    void unlock() RELEASE() { mutex_.unlock(); }
-
-  private:
-    std::recursive_mutex mutex_;
-};
-
-extern RecursiveMutex service_lock;
-
-}  // namespace init
-}  // namespace android
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 51f4c97..560f693 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -168,7 +168,6 @@
 
     const std::string fullname = interface_name + "/" + instance_name;
 
-    auto lock = std::lock_guard{service_lock};
     for (const auto& svc : *service_list_) {
         if (svc->interfaces().count(fullname) > 0) {
             return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
@@ -599,7 +598,6 @@
         }
     }
 
-    auto lock = std::lock_guard{service_lock};
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 064d64d..9b2c7d9 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -64,8 +64,6 @@
     std::string wait_string;
     Service* service = nullptr;
 
-    auto lock = std::lock_guard{service_lock};
-
     if (SubcontextChildReap(pid)) {
         name = "Subcontext";
     } else {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 565f2c3..57531c8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -44,12 +44,20 @@
     recovery_available: true,
     native_bridge_supported: true,
     export_include_dirs: ["include"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
 }
 
 cc_library {
     name: "libbacktrace",
     vendor_available: false,
     recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     vndk: {
         enabled: true,
         support_system_process: true,
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index e47560f..d7175e0 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -38,4 +38,8 @@
             enabled: true,
         },
     },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.adbd",
+    ],
 }
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8e90ddf..dccf588 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -29,6 +29,10 @@
     vendor_available: true,
     recovery_available: true,
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     target: {
@@ -45,13 +49,9 @@
 }
 
 // Socket specific parts of libcutils that are safe to statically link into an APEX.
-cc_library_static {
+cc_library {
     name: "libcutils_sockets",
     vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
@@ -62,6 +62,7 @@
 
     export_include_dirs: ["include"],
 
+    shared_libs: ["liblog"],
     srcs: ["sockets.cpp"],
     target: {
         linux_bionic: {
@@ -137,6 +138,10 @@
     },
     recovery_available: true,
     host_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     srcs: [
         "config_utils.cpp",
diff --git a/liblog/Android.bp b/liblog/Android.bp
index f1e5118..50faa2a 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -38,6 +38,10 @@
     vendor_available: true,
     ramdisk_available: true,
     recovery_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index b9839d6..15c7963 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -56,6 +56,11 @@
 
 #include <stdarg.h>
 #include <stddef.h>
+#include <sys/cdefs.h>
+
+#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(x)
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -191,6 +196,18 @@
 };
 
 /**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+                                          const char* message);
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+#if __ANDROID_API__ >= 30 || !defined(__ANDROID__)
+/**
  * Writes the log message specified with logger_data and msg to the log.  logger_data includes
  * additional file name and line number information that a logger may use.  logger_data is versioned
  * for backwards compatibility.
@@ -199,54 +216,44 @@
  * buffers, then pass the message to liblog via this function, and therefore we do not want to
  * duplicate the loggability check here.
  */
-void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
-
-/**
- * Prototype for the 'logger' function that is called for every log message.
- */
-typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
-                                          const char* message);
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg)
+    __INTRODUCED_IN(30);
 
 /**
  * Sets a user defined logger function.  All log messages sent to liblog will be set to the
  * function pointer specified by logger for processing.
  */
-void __android_log_set_logger(__android_logger_function logger);
+void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to logd.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on a device.
  */
-void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg)
+    __INTRODUCED_IN(30);
 
 /**
  * Writes the log message to stderr.  This is an __android_logger_function and can be provided to
  * __android_log_set_logger().  It is the default logger when running liblog on host.
  */
 void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
-                                 const char* message);
-
-/**
- * Prototype for the 'abort' function that is called when liblog will abort due to
- * __android_log_assert() failures.
- */
-typedef void (*__android_aborter_function)(const char* abort_message);
+                                 const char* message) __INTRODUCED_IN(30);
 
 /**
  * Sets a user defined aborter function that is called for __android_log_assert() failures.
  */
-void __android_log_set_aborter(__android_aborter_function aborter);
+void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
 
 /**
  * Calls the stored aborter function.  This allows for other logging libraries to use the same
  * aborter function by calling this function in liblog.
  */
-void __android_log_call_aborter(const char* abort_message);
+void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
 
 /**
  * Sets android_set_abort_message() on device then aborts().  This is the default aborter.
  */
-void __android_log_default_aborter(const char* abort_message);
+void __android_log_default_aborter(const char* abort_message) __INTRODUCED_IN(30);
 
 /**
  * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
@@ -260,28 +267,30 @@
  *
  * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
  */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
+    __INTRODUCED_IN(30);
 
 /**
  * Sets the minimum priority that will be logged for this process.
  *
  * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
  */
-int __android_log_set_minimum_priority(int priority);
+int __android_log_set_minimum_priority(int priority) __INTRODUCED_IN(30);
 
 /**
  * Gets the minimum priority that will be logged for this process.  If none has been set by a
  * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
  */
-int __android_log_get_minimum_priority(void);
+int __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
 
 /**
  * Sets the default tag if no tag is provided when writing a log message.  Defaults to
  * getprogname().  This truncates tag to the maximum log message size, though appropriate tags
  * should be much smaller.
  */
-void __android_log_set_default_tag(const char* tag);
+void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 1b6b0c6..0dbb94f 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -27,6 +27,7 @@
 #include <android/set_abort_message.h>
 #endif
 
+#include <atomic>
 #include <shared_mutex>
 
 #include <android-base/errno_restorer.h>
@@ -148,11 +149,9 @@
   GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
 }
 
-static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+static std::atomic_int minimum_log_priority = ANDROID_LOG_DEFAULT;
 int __android_log_set_minimum_priority(int priority) {
-  int old_minimum_log_priority = minimum_log_priority;
-  minimum_log_priority = priority;
-  return old_minimum_log_priority;
+  return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
 }
 
 int __android_log_get_minimum_priority() {
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index e05a690..12474f1 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -106,3 +106,7 @@
         },
     },
 }
+
+vts_config {
+    name: "VtsProcessgroupValidateTest",
+}
diff --git a/libprocessgroup/profiles/Android.mk b/libprocessgroup/profiles/Android.mk
deleted file mode 100644
index eab96d4..0000000
--- a/libprocessgroup/profiles/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Copyright (C) 2019 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := VtsProcessgroupValidateTest
--include test/vts/tools/build/Android.host_config.mk
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
index b265b61..ff886fd 100644
--- a/libsystem/Android.bp
+++ b/libsystem/Android.bp
@@ -4,6 +4,10 @@
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
     export_include_dirs: ["include"],
 
     target: {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 3695f72..36449eb 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -116,12 +116,6 @@
         x86_64: {
             srcs: ["AsmGetRegsX86_64.S"],
         },
-        mips: {
-            srcs: ["AsmGetRegsMips.S"],
-        },
-        mips64: {
-            srcs: ["AsmGetRegsMips64.S"],
-        },
     },
 
     static_libs: [
diff --git a/libunwindstack/AsmGetRegsMips.S b/libunwindstack/AsmGetRegsMips.S
deleted file mode 100644
index 183d0a9..0000000
--- a/libunwindstack/AsmGetRegsMips.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-  .text
-  .type     AsmGetRegs, %function
-  .globl    AsmGetRegs
-  .ent      AsmGetRegs
-  .balign   16
-AsmGetRegs:
-  .cfi_startproc
-  .cfi_def_cfa $sp, 0
-  .set push
-  .set noreorder
-  .cpload $t9
-  sw   $zero, 0($a0)
-  .set noat
-  sw   $at, 4($a0)
-  .set at
-  sw   $v0, 8($a0)
-  sw   $v1, 12($a0)
-  sw   $a0, 16($a0)
-  sw   $a1, 20($a0)
-  sw   $a2, 24($a0)
-  sw   $a3, 28($a0)
-  sw   $t0, 32($a0)
-  sw   $t1, 36($a0)
-  sw   $t2, 40($a0)
-  sw   $t3, 44($a0)
-  sw   $t4, 48($a0)
-  sw   $t5, 52($a0)
-  sw   $t6, 56($a0)
-  sw   $t7, 60($a0)
-  sw   $s0, 64($a0)
-  sw   $s1, 68($a0)
-  sw   $s2, 72($a0)
-  sw   $s3, 76($a0)
-  sw   $s4, 80($a0)
-  sw   $s5, 84($a0)
-  sw   $s6, 88($a0)
-  sw   $s7, 92($a0)
-  sw   $t8, 96($a0)
-  sw   $t9, 100($a0)
-  sw   $k0, 104($a0)
-  sw   $k1, 108($a0)
-  sw   $gp, 112($a0)
-  sw   $sp, 116($a0)
-  sw   $s8, 120($a0)
-  sw   $ra, 124($a0)
-  jalr $zero, $ra
-  sw   $ra, 128($a0)   // set PC to the calling function
-
-  .set pop
-  .cfi_endproc
-  .size     AsmGetRegs, .-AsmGetRegs
-  .end      AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsMips64.S b/libunwindstack/AsmGetRegsMips64.S
deleted file mode 100644
index 7a244f6..0000000
--- a/libunwindstack/AsmGetRegsMips64.S
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-  .text
-  .type     AsmGetRegs, %function
-  .globl    AsmGetRegs
-  .ent      AsmGetRegs
-  .balign    16
-AsmGetRegs:
-  .cfi_startproc
-  .cfi_def_cfa $sp, 0
-  .set push
-  .set noreorder
-  .cpload $t9
-  sd   $zero, 0($a0)
-  .set noat
-  sd   $at, 8($a0)
-  .set at
-  sd   $v0, 16($a0)
-  sd   $v1, 24($a0)
-  sd   $a0, 32($a0)
-  sd   $a1, 40($a0)
-  sd   $a2, 48($a0)
-  sd   $a3, 56($a0)
-  sd   $a4, 64($a0)
-  sd   $a5, 72($a0)
-  sd   $a6, 80($a0)
-  sd   $a7, 88($a0)
-  sd   $t0, 96($a0)
-  sd   $t1, 104($a0)
-  sd   $t2, 112($a0)
-  sd   $t3, 120($a0)
-  sd   $s0, 128($a0)
-  sd   $s1, 136($a0)
-  sd   $s2, 144($a0)
-  sd   $s3, 152($a0)
-  sd   $s4, 160($a0)
-  sd   $s5, 168($a0)
-  sd   $s6, 176($a0)
-  sd   $s7, 184($a0)
-  sd   $t8, 192($a0)
-  sd   $t9, 200($a0)
-  sd   $k0, 208($a0)
-  sd   $k1, 216($a0)
-  sd   $gp, 224($a0)
-  sd   $sp, 232($a0)
-  sd   $s8, 240($a0)
-  sd   $ra, 248($a0)
-  jalr $zero, $ra
-  sd   $ra, 256($a0)   // set PC to the calling function
-
-  .set pop
-  .cfi_endproc
-  .size AsmGetRegs, .-AsmGetRegs
-  .end      AsmGetRegs
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index c7dec52..e0a785b 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -100,10 +100,6 @@
   return ARCH_X86;
 #elif defined(__x86_64__)
   return ARCH_X86_64;
-#elif defined(__mips__) && !defined(__LP64__)
-  return ARCH_MIPS;
-#elif defined(__mips__) && defined(__LP64__)
-  return ARCH_MIPS64;
 #else
   abort();
 #endif
@@ -119,10 +115,6 @@
   regs = new RegsX86();
 #elif defined(__x86_64__)
   regs = new RegsX86_64();
-#elif defined(__mips__) && !defined(__LP64__)
-  regs = new RegsMips();
-#elif defined(__mips__) && defined(__LP64__)
-  regs = new RegsMips64();
 #else
   abort();
 #endif
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index f0b5e3a..300a3ec 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -81,7 +81,7 @@
       : "x12", "x13", "memory");
 }
 
-#elif defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+#elif defined(__i386__) || defined(__x86_64__)
 
 extern "C" void AsmGetRegs(void* regs);
 
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 9ddbedf..3ab619b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,6 +18,10 @@
     recovery_available: true,
     host_supported: true,
     native_bridge_supported: true,
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
 
     header_libs: [
         "liblog_headers",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 01b7ca3..fdc9d32 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -731,9 +731,10 @@
     mkdir /data/incremental 0771 system system encryption=Require
 
     # Create directories for statsd
-    mkdir /data/misc/stats-data/ 0770 statsd system
-    mkdir /data/misc/stats-service/ 0770 statsd system
     mkdir /data/misc/stats-active-metric/ 0770 statsd system
+    mkdir /data/misc/stats-data/ 0770 statsd system
+    mkdir /data/misc/stats-metadata/ 0770 statsd system
+    mkdir /data/misc/stats-service/ 0770 statsd system
     mkdir /data/misc/train-info/ 0770 statsd system
 
     # Wait for apexd to finish activating APEXes before starting more processes.