Merge "StatsEventCompat"
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 703eb2f..fbfeb53 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -52,6 +52,8 @@
 #include <android-base/strings.h>
 #include <android-base/stringprintf.h>
 
+typedef void(sync_ls_cb)(unsigned mode, uint64_t size, uint64_t time, const char* name);
+
 struct syncsendbuf {
     unsigned id;
     unsigned size;
@@ -210,6 +212,7 @@
             Error("failed to get feature set: %s", error.c_str());
         } else {
             have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
+            have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
             fd.reset(adb_connect("sync:", &error));
             if (fd < 0) {
                 Error("connect failed: %s", error.c_str());
@@ -357,7 +360,7 @@
                             << msg.stat_v1.id;
             }
 
-            if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
+            if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.mtime == 0) {
                 // There's no way for us to know what the error was.
                 errno = ENOPROTOOPT;
                 return false;
@@ -365,13 +368,52 @@
 
             st->st_mode = msg.stat_v1.mode;
             st->st_size = msg.stat_v1.size;
-            st->st_ctime = msg.stat_v1.time;
-            st->st_mtime = msg.stat_v1.time;
+            st->st_ctime = msg.stat_v1.mtime;
+            st->st_mtime = msg.stat_v1.mtime;
         }
 
         return true;
     }
 
+    bool SendLs(const char* path) {
+        return SendRequest(have_ls_v2_ ? ID_LIST_V2 : ID_LIST_V1, path);
+    }
+
+  private:
+    template <bool v2>
+    static bool FinishLsImpl(borrowed_fd fd, const std::function<sync_ls_cb>& callback) {
+        using dent_type =
+                std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
+
+        while (true) {
+            dent_type dent;
+            if (!ReadFdExactly(fd, &dent, sizeof(dent))) return false;
+
+            uint32_t expected_id = v2 ? ID_DENT_V2 : ID_DENT_V1;
+            if (dent.id == ID_DONE) return true;
+            if (dent.id != expected_id) return false;
+
+            // Maximum length of a file name excluding null terminator (NAME_MAX) on Linux is 255.
+            char buf[256];
+            size_t len = dent.namelen;
+            if (len > 255) return false;
+
+            if (!ReadFdExactly(fd, buf, len)) return false;
+            buf[len] = 0;
+
+            callback(dent.mode, dent.size, dent.mtime, buf);
+        }
+    }
+
+  public:
+    bool FinishLs(const std::function<sync_ls_cb>& callback) {
+        if (have_ls_v2_) {
+            return FinishLsImpl<true>(this->fd, callback);
+        } else {
+            return FinishLsImpl<false>(this->fd, callback);
+        }
+    }
+
     // Sending header, payload, and footer in a single write makes a huge
     // difference to "adb sync" performance.
     bool SendSmallFile(const char* path_and_mode,
@@ -578,6 +620,7 @@
     bool expect_done_;
     FeatureSet features_;
     bool have_stat_v2_;
+    bool have_ls_v2_;
 
     TransferLedger global_ledger_;
     TransferLedger current_ledger_;
@@ -609,28 +652,9 @@
     }
 };
 
-typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
-
 static bool sync_ls(SyncConnection& sc, const char* path,
                     const std::function<sync_ls_cb>& func) {
-    if (!sc.SendRequest(ID_LIST, path)) return false;
-
-    while (true) {
-        syncmsg msg;
-        if (!ReadFdExactly(sc.fd, &msg.dent, sizeof(msg.dent))) return false;
-
-        if (msg.dent.id == ID_DONE) return true;
-        if (msg.dent.id != ID_DENT) return false;
-
-        size_t len = msg.dent.namelen;
-        if (len > 256) return false; // TODO: resize buffer? continue?
-
-        char buf[257];
-        if (!ReadFdExactly(sc.fd, buf, len)) return false;
-        buf[len] = 0;
-
-        func(msg.dent.mode, msg.dent.size, msg.dent.time, buf);
-    }
+    return sc.SendLs(path) && sc.FinishLs(func);
 }
 
 static bool sync_stat(SyncConnection& sc, const char* path, struct stat* st) {
@@ -787,9 +811,8 @@
     SyncConnection sc;
     if (!sc.IsValid()) return false;
 
-    return sync_ls(sc, path, [](unsigned mode, unsigned size, unsigned time,
-                                const char* name) {
-        printf("%08x %08x %08x %s\n", mode, size, time, name);
+    return sync_ls(sc, path, [](unsigned mode, uint64_t size, uint64_t time, const char* name) {
+        printf("%08x %08" PRIx64 " %08" PRIx64 " %s\n", mode, size, time, name);
     });
 }
 
@@ -1062,7 +1085,7 @@
     file_list->push_back(ci);
 
     // Put the files/dirs in rpath on the lists.
-    auto callback = [&](unsigned mode, unsigned size, unsigned time, const char* name) {
+    auto callback = [&](unsigned mode, uint64_t size, uint64_t time, const char* name) {
         if (IsDotOrDotDot(name)) {
             return;
         }
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 0e70d47..d6af708 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -139,7 +139,7 @@
     lstat(path, &st);
     msg.stat_v1.mode = st.st_mode;
     msg.stat_v1.size = st.st_size;
-    msg.stat_v1.time = st.st_mtime;
+    msg.stat_v1.mtime = st.st_mtime;
     return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1));
 }
 
@@ -174,40 +174,73 @@
     return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
 }
 
+template <bool v2>
 static bool do_list(int s, const char* path) {
     dirent* de;
 
-    syncmsg msg;
-    msg.dent.id = ID_DENT;
+    using MessageType =
+            std::conditional_t<v2, decltype(syncmsg::dent_v2), decltype(syncmsg::dent_v1)>;
+    MessageType msg;
+    uint32_t msg_id;
+    if constexpr (v2) {
+        msg_id = ID_DENT_V2;
+    } else {
+        msg_id = ID_DENT_V1;
+    }
 
     std::unique_ptr<DIR, int(*)(DIR*)> d(opendir(path), closedir);
     if (!d) goto done;
 
     while ((de = readdir(d.get()))) {
+        memset(&msg, 0, sizeof(msg));
+        msg.id = msg_id;
+
         std::string filename(StringPrintf("%s/%s", path, de->d_name));
 
         struct stat st;
         if (lstat(filename.c_str(), &st) == 0) {
-            size_t d_name_length = strlen(de->d_name);
-            msg.dent.mode = st.st_mode;
-            msg.dent.size = st.st_size;
-            msg.dent.time = st.st_mtime;
-            msg.dent.namelen = d_name_length;
+            msg.mode = st.st_mode;
+            msg.size = st.st_size;
+            msg.mtime = st.st_mtime;
 
-            if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
-                    !WriteFdExactly(s, de->d_name, d_name_length)) {
-                return false;
+            if constexpr (v2) {
+                msg.dev = st.st_dev;
+                msg.ino = st.st_ino;
+                msg.nlink = st.st_nlink;
+                msg.uid = st.st_uid;
+                msg.gid = st.st_gid;
+                msg.atime = st.st_atime;
+                msg.ctime = st.st_ctime;
             }
+        } else {
+            if constexpr (v2) {
+                msg.error = errno;
+            } else {
+                continue;
+            }
+        }
+
+        size_t d_name_length = strlen(de->d_name);
+        msg.namelen = d_name_length;
+
+        if (!WriteFdExactly(s, &msg, sizeof(msg)) ||
+            !WriteFdExactly(s, de->d_name, d_name_length)) {
+            return false;
         }
     }
 
 done:
-    msg.dent.id = ID_DONE;
-    msg.dent.mode = 0;
-    msg.dent.size = 0;
-    msg.dent.time = 0;
-    msg.dent.namelen = 0;
-    return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
+    memset(&msg, 0, sizeof(msg));
+    msg.id = ID_DONE;
+    return WriteFdExactly(s, &msg, sizeof(msg));
+}
+
+static bool do_list_v1(int s, const char* path) {
+    return do_list<false>(s, path);
+}
+
+static bool do_list_v2(int s, const char* path) {
+    return do_list<true>(s, path);
 }
 
 // Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
@@ -499,8 +532,10 @@
       return "lstat_v2";
     case ID_STAT_V2:
       return "stat_v2";
-    case ID_LIST:
-      return "list";
+    case ID_LIST_V1:
+      return "list_v1";
+    case ID_LIST_V2:
+      return "list_v2";
     case ID_SEND:
       return "send";
     case ID_RECV:
@@ -546,8 +581,11 @@
         case ID_STAT_V2:
             if (!do_stat_v2(fd, request.id, name)) return false;
             break;
-        case ID_LIST:
-            if (!do_list(fd, name)) return false;
+        case ID_LIST_V1:
+            if (!do_list_v1(fd, name)) return false;
+            break;
+        case ID_LIST_V2:
+            if (!do_list_v2(fd, name)) return false;
             break;
         case ID_SEND:
             if (!do_send(fd, name, buffer)) return false;
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
index 338d776..b19fa5d 100644
--- a/adb/daemon/usb_ffs.cpp
+++ b/adb/daemon/usb_ffs.cpp
@@ -84,7 +84,7 @@
 using usb_os_desc_guid_t = usb_os_desc_ext_prop<20, 39>;
 usb_os_desc_guid_t os_desc_guid = {
     .bPropertyName = "DeviceInterfaceGUID",
-    .bProperty = "{64379D6C-D531-4BED-BBEC-5A16FC07D6BC}",
+    .bProperty = "{F72FE0D4-CBCB-407D-8814-9ED673D0DD6B}",
 };
 
 struct usb_ext_prop_values {
diff --git a/adb/file_sync_protocol.h b/adb/file_sync_protocol.h
index 108639a..508c138 100644
--- a/adb/file_sync_protocol.h
+++ b/adb/file_sync_protocol.h
@@ -21,10 +21,14 @@
 #define ID_LSTAT_V1 MKID('S', 'T', 'A', 'T')
 #define ID_STAT_V2 MKID('S', 'T', 'A', '2')
 #define ID_LSTAT_V2 MKID('L', 'S', 'T', '2')
-#define ID_LIST MKID('L', 'I', 'S', 'T')
+
+#define ID_LIST_V1 MKID('L', 'I', 'S', 'T')
+#define ID_LIST_V2 MKID('L', 'I', 'S', '2')
+#define ID_DENT_V1 MKID('D', 'E', 'N', 'T')
+#define ID_DENT_V2 MKID('D', 'N', 'T', '2')
+
 #define ID_SEND MKID('S', 'E', 'N', 'D')
 #define ID_RECV MKID('R', 'E', 'C', 'V')
-#define ID_DENT MKID('D', 'E', 'N', 'T')
 #define ID_DONE MKID('D', 'O', 'N', 'E')
 #define ID_DATA MKID('D', 'A', 'T', 'A')
 #define ID_OKAY MKID('O', 'K', 'A', 'Y')
@@ -42,7 +46,7 @@
         uint32_t id;
         uint32_t mode;
         uint32_t size;
-        uint32_t time;
+        uint32_t mtime;
     } stat_v1;
     struct __attribute__((packed)) {
         uint32_t id;
@@ -62,17 +66,32 @@
         uint32_t id;
         uint32_t mode;
         uint32_t size;
-        uint32_t time;
+        uint32_t mtime;
         uint32_t namelen;
-    } dent;
+    } dent_v1; // followed by `namelen` bytes of the name.
+    struct __attribute__((packed)) {
+        uint32_t id;
+        uint32_t error;
+        uint64_t dev;
+        uint64_t ino;
+        uint32_t mode;
+        uint32_t nlink;
+        uint32_t uid;
+        uint32_t gid;
+        uint64_t size;
+        int64_t atime;
+        int64_t mtime;
+        int64_t ctime;
+        uint32_t namelen;
+    } dent_v2; // followed by `namelen` bytes of the name.
     struct __attribute__((packed)) {
         uint32_t id;
         uint32_t size;
-    } data;
+    } data; // followed by `size` bytes of data.
     struct __attribute__((packed)) {
         uint32_t id;
         uint32_t msglen;
-    } status;
+    } status; // followed by `msglen` bytes of error message, if id == ID_FAIL.
 };
 
 #define SYNC_DATA_MAX (64 * 1024)
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d9749ac..9dd6ec6 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -55,7 +55,7 @@
 using android::base::ScopedLockAssertion;
 
 static void remove_transport(atransport* transport);
-static void transport_unref(atransport* transport);
+static void transport_destroy(atransport* transport);
 
 // TODO: unordered_map<TransportId, atransport*>
 static auto& transport_list = *new std::list<atransport*>();
@@ -66,6 +66,7 @@
 const char* const kFeatureShell2 = "shell_v2";
 const char* const kFeatureCmd = "cmd";
 const char* const kFeatureStat2 = "stat_v2";
+const char* const kFeatureLs2 = "ls_v2";
 const char* const kFeatureLibusb = "libusb";
 const char* const kFeaturePushSync = "push_sync";
 const char* const kFeatureApex = "apex";
@@ -676,7 +677,6 @@
     if (t->GetConnectionState() != kCsNoPerm) {
         // The connection gets a reference to the atransport. It will release it
         // upon a read/write error.
-        t->ref_count++;
         t->connection()->SetTransportName(t->serial_name());
         t->connection()->SetReadCallback([t](Connection*, std::unique_ptr<apacket> p) {
             if (!check_header(p.get(), t)) {
@@ -695,7 +695,7 @@
             LOG(INFO) << t->serial_name() << ": connection terminated: " << error;
             fdevent_run_on_main_thread([t]() {
                 handle_offline(t);
-                transport_unref(t);
+                transport_destroy(t);
             });
         });
 
@@ -771,36 +771,27 @@
     }
 }
 
-static void transport_unref(atransport* t) {
+static void transport_destroy(atransport* t) {
     check_main_thread();
     CHECK(t != nullptr);
 
     std::lock_guard<std::recursive_mutex> lock(transport_lock);
-    CHECK_GT(t->ref_count, 0u);
-    t->ref_count--;
-    if (t->ref_count == 0) {
-        LOG(INFO) << "destroying transport " << t->serial_name();
-        t->connection()->Stop();
+    LOG(INFO) << "destroying transport " << t->serial_name();
+    t->connection()->Stop();
 #if ADB_HOST
-        if (t->IsTcpDevice() && !t->kicked()) {
-            D("transport: %s unref (attempting reconnection)", t->serial.c_str());
+    if (t->IsTcpDevice() && !t->kicked()) {
+        D("transport: %s destroy (attempting reconnection)", t->serial.c_str());
 
-            // We need to clear the transport's keys, so that on the next connection, it tries
-            // again from the beginning.
-            t->ResetKeys();
-            reconnect_handler.TrackTransport(t);
-        } else {
-            D("transport: %s unref (kicking and closing)", t->serial.c_str());
-            remove_transport(t);
-        }
-#else
-        D("transport: %s unref (kicking and closing)", t->serial.c_str());
-        remove_transport(t);
+        // We need to clear the transport's keys, so that on the next connection, it tries
+        // again from the beginning.
+        t->ResetKeys();
+        reconnect_handler.TrackTransport(t);
+        return;
+    }
 #endif
 
-    } else {
-        D("transport: %s unref (count=%zu)", t->serial.c_str(), t->ref_count);
-    }
+    D("transport: %s destroy (kicking and closing)", t->serial.c_str());
+    remove_transport(t);
 }
 
 static int qual_match(const std::string& to_test, const char* prefix, const std::string& qual,
@@ -1045,6 +1036,7 @@
             kFeatureShell2,
             kFeatureCmd,
             kFeatureStat2,
+            kFeatureLs2,
             kFeatureFixedPushMkdir,
             kFeatureApex,
             kFeatureAbb,
diff --git a/adb/transport.h b/adb/transport.h
index 89d76b8..ea77117 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -57,6 +57,7 @@
 // The 'cmd' command is available
 extern const char* const kFeatureCmd;
 extern const char* const kFeatureStat2;
+extern const char* const kFeatureLs2;
 // The server is running with libusb enabled.
 extern const char* const kFeatureLibusb;
 // adbd supports `push --sync`.
@@ -266,7 +267,7 @@
     usb_handle* GetUsbHandle() { return usb_handle_; }
 
     const TransportId id;
-    size_t ref_count = 0;
+
     bool online = false;
     TransportType type = kTransportAny;
 
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index b20f278..f3d7cb0 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -53,30 +53,34 @@
   CapturedStdout() : CapturedStdFd(STDOUT_FILENO) {}
 };
 
-#define ASSERT_MATCH(str, pattern)                                             \
-  do {                                                                         \
-    if (!std::regex_search((str), std::regex((pattern)))) {                    \
-      FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << (str); \
-    }                                                                          \
+#define ASSERT_MATCH(str, pattern)                                           \
+  do {                                                                       \
+    auto __s = (str);                                                        \
+    if (!std::regex_search(__s, std::regex((pattern)))) {                    \
+      FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
+    }                                                                        \
   } while (0)
 
-#define ASSERT_NOT_MATCH(str, pattern)                                                     \
-  do {                                                                                     \
-    if (std::regex_search((str), std::regex((pattern)))) {                                 \
-      FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << (str); \
-    }                                                                                      \
+#define ASSERT_NOT_MATCH(str, pattern)                                                   \
+  do {                                                                                   \
+    auto __s = (str);                                                                    \
+    if (std::regex_search(__s, std::regex((pattern)))) {                                 \
+      FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
+    }                                                                                    \
   } while (0)
 
-#define EXPECT_MATCH(str, pattern)                                                    \
-  do {                                                                                \
-    if (!std::regex_search((str), std::regex((pattern)))) {                           \
-      ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << (str); \
-    }                                                                                 \
+#define EXPECT_MATCH(str, pattern)                                                  \
+  do {                                                                              \
+    auto __s = (str);                                                               \
+    if (!std::regex_search(__s, std::regex((pattern)))) {                           \
+      ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \
+    }                                                                               \
   } while (0)
 
-#define EXPECT_NOT_MATCH(str, pattern)                                                            \
-  do {                                                                                            \
-    if (std::regex_search((str), std::regex((pattern)))) {                                        \
-      ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << (str); \
-    }                                                                                             \
+#define EXPECT_NOT_MATCH(str, pattern)                                                          \
+  do {                                                                                          \
+    auto __s = (str);                                                                           \
+    if (std::regex_search(__s, std::regex((pattern)))) {                                        \
+      ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \
+    }                                                                                           \
   } while (0)
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index e279af9..a9342d8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -577,8 +577,7 @@
 }  // namespace
 
 void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
-    static constexpr char kGsiKeys[] =
-            "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey";
+    static constexpr char kDsuKeysDir[] = "/avb";
     // Convert userdata
     // Inherit fstab properties for userdata.
     FstabEntry userdata;
@@ -624,29 +623,18 @@
                     .fs_type = "ext4",
                     .flags = MS_RDONLY,
                     .fs_options = "barrier=1",
-                    .avb_keys = kGsiKeys,
+                    .avb_keys = kDsuKeysDir,
             };
             entry.fs_mgr_flags.wait = true;
             entry.fs_mgr_flags.logical = true;
             entry.fs_mgr_flags.first_stage_mount = true;
-            // Use the system key which may be in the vbmeta or vbmeta_system
-            // TODO: b/141284191
-            entry.vbmeta_partition = "vbmeta";
-            fstab->emplace_back(entry);
-            entry.vbmeta_partition = "vbmeta_system";
-            fstab->emplace_back(entry);
         } else {
             // If the corresponding partition exists, transform all its Fstab
             // by pointing .blk_device to the DSU partition.
             for (auto&& entry : entries) {
                 entry->blk_device = partition;
-                if (entry->avb_keys.size() > 0) {
-                    entry->avb_keys += ":";
-                }
-                // If the DSU is signed by OEM, the original Fstab already has the information
-                // required by avb, otherwise the DSU is GSI and will need the avb_keys as listed
-                // below.
-                entry->avb_keys += kGsiKeys;
+                // AVB keys for DSU should always be under kDsuKeysDir.
+                entry->avb_keys += kDsuKeysDir;
             }
             // Make sure the ext4 is included to support GSI.
             auto partition_ext4 =
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 0579a3d..2337065 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -815,26 +815,72 @@
     return "auto";
 }
 
-std::string fs_mgr_overlayfs_scratch_device() {
-    if (!scratch_device_cache.empty()) return scratch_device_cache;
+enum class ScratchStrategy {
+    kNone,
+    // DAP device, use logical partitions.
+    kDynamicPartition,
+    // Retrofit DAP device, use super_<other>.
+    kSuperOther,
+    // Pre-DAP device, uses the other slot.
+    kSystemOther
+};
 
-    // Is this a multiple super device (retrofit)?
+static ScratchStrategy GetScratchStrategy(std::string* backing_device) {
     auto slot_number = fs_mgr_overlayfs_slot_number();
     auto super_device = fs_mgr_overlayfs_super_device(slot_number);
     auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
-    if (super_device == path) {
-        // Create from within single super device;
-        auto& dm = DeviceMapper::Instance();
-        const auto partition_name = android::base::Basename(kScratchMountPoint);
-        if (!dm.GetDmDevicePathByName(partition_name, &path)) {
-            // non-DAP A/B device?
-            if (fs_mgr_access(super_device)) return "";
-            auto other_slot = fs_mgr_get_other_slot_suffix();
-            if (other_slot.empty()) return "";
-            path = kPhysicalDevice + "system" + other_slot;
+    if (super_device != path) {
+        // Note: we do not check access() here, since in first-stage init we
+        // wouldn't have registed by-name symlinks for the device as it's
+        // normally not needed. The access checks elsewhere in this function
+        // are safe because system/super are always required.
+        *backing_device = path;
+        return ScratchStrategy::kSuperOther;
+    }
+    if (fs_mgr_access(super_device)) {
+        *backing_device = super_device;
+        return ScratchStrategy::kDynamicPartition;
+    }
+
+    auto other_slot = fs_mgr_get_other_slot_suffix();
+    if (!other_slot.empty()) {
+        path = kPhysicalDevice + "system" + other_slot;
+        if (fs_mgr_access(path)) {
+            *backing_device = path;
+            return ScratchStrategy::kSystemOther;
         }
     }
-    return scratch_device_cache = path;
+    return ScratchStrategy::kNone;
+}
+
+// Return the scratch device if it exists.
+static std::string GetScratchDevice() {
+    std::string device;
+    ScratchStrategy strategy = GetScratchStrategy(&device);
+
+    switch (strategy) {
+        case ScratchStrategy::kSuperOther:
+        case ScratchStrategy::kSystemOther:
+            return device;
+        case ScratchStrategy::kDynamicPartition: {
+            auto& dm = DeviceMapper::Instance();
+            auto partition_name = android::base::Basename(kScratchMountPoint);
+            if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
+                dm.GetDmDevicePathByName(partition_name, &device)) {
+                return device;
+            }
+            return "";
+        }
+        default:
+            return "";
+    }
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+    if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+    scratch_device_cache = GetScratchDevice();
+    return scratch_device_cache;
 }
 
 bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {
@@ -1066,6 +1112,25 @@
     return candidates;
 }
 
+static void TryMountScratch() {
+    auto scratch_device = fs_mgr_overlayfs_scratch_device();
+    if (!fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device)) {
+        return;
+    }
+    if (!WaitForFile(scratch_device, 10s)) {
+        return;
+    }
+    const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
+    if (!fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type, true /* readonly */)) {
+        return;
+    }
+    auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
+    fs_mgr_overlayfs_umount_scratch();
+    if (has_overlayfs_dir) {
+        fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+    }
+}
+
 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
     auto ret = false;
     if (fs_mgr_overlayfs_invalid()) return ret;
@@ -1080,19 +1145,7 @@
         }
         if (scratch_can_be_mounted) {
             scratch_can_be_mounted = false;
-            auto scratch_device = fs_mgr_overlayfs_scratch_device();
-            if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) &&
-                WaitForFile(scratch_device, 10s)) {
-                const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
-                if (fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type,
-                                                   true /* readonly */)) {
-                    auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
-                    fs_mgr_overlayfs_umount_scratch();
-                    if (has_overlayfs_dir) {
-                        fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
-                    }
-                }
-            }
+            TryMountScratch();
         }
         if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
     }
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 656d4dd..de0c636 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -17,7 +17,6 @@
 liblog_sources = [
     "log_event_list.cpp",
     "log_event_write.cpp",
-    "logger_lock.cpp",
     "logger_name.cpp",
     "logger_read.cpp",
     "logger_write.cpp",
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 4143fa6..fb3b9bc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -48,21 +48,16 @@
 #define TRACE(...) ((void)0)
 #endif
 
-static int FakeAvailable(log_id_t);
-static int FakeOpen();
 static void FakeClose();
 static int FakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr);
 
 struct android_log_transport_write fakeLoggerWrite = {
-    .name = "fake",
-    .logMask = 0,
-    .available = FakeAvailable,
-    .open = FakeOpen,
     .close = FakeClose,
     .write = FakeWrite,
 };
 
 typedef struct LogState {
+  bool initialized = false;
   /* global minimum priority */
   int global_min_priority;
 
@@ -76,19 +71,8 @@
   } tagSet[kTagSetSize];
 } LogState;
 
-/*
- * Locking.  Since we're emulating a device, we need to be prepared
- * to have multiple callers at the same time.  This lock is used
- * to both protect the fd list and to prevent LogStates from being
- * freed out from under a user.
- */
-std::mutex mutex;
-
 static LogState log_state;
-
-static int FakeAvailable(log_id_t) {
-  return 0;
-}
+static std::mutex fake_log_mutex;
 
 /*
  * Configure logging based on ANDROID_LOG_TAGS environment variable.  We
@@ -103,8 +87,8 @@
  * We also want to check ANDROID_PRINTF_LOG to determine how the output
  * will look.
  */
-int FakeOpen() {
-  std::lock_guard guard{mutex};
+void InitializeLogStateLocked() {
+  log_state.initialized = true;
 
   /* global min priority defaults to "info" level */
   log_state.global_min_priority = ANDROID_LOG_INFO;
@@ -129,7 +113,7 @@
       }
       if (i == kMaxTagLen) {
         TRACE("ERROR: env tag too long (%d chars max)\n", kMaxTagLen - 1);
-        return 0;
+        return;
       }
       tagName[i] = '\0';
 
@@ -180,7 +164,7 @@
         if (*tags != '\0' && !isspace(*tags)) {
           TRACE("ERROR: garbage in tag env; expected whitespace\n");
           TRACE("       env='%s'\n", tags);
-          return 0;
+          return;
         }
       }
 
@@ -224,7 +208,6 @@
   }
 
   log_state.output_format = format;
-  return 0;
 }
 
 /*
@@ -474,7 +457,11 @@
    * Also guarantees that only one thread is in showLog() at a given
    * time (if it matters).
    */
-  std::lock_guard guard{mutex};
+  auto lock = std::lock_guard{fake_log_mutex};
+
+  if (!log_state.initialized) {
+    InitializeLogStateLocked();
+  }
 
   if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY) {
     TRACE("%s: ignoring binary log\n", android_log_id_to_name(log_id));
@@ -532,7 +519,7 @@
  * help debug HOST tools ...
  */
 static void FakeClose() {
-  std::lock_guard guard{mutex};
+  auto lock = std::lock_guard{fake_log_mutex};
 
   memset(&log_state, 0, sizeof(log_state));
 }
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index a22c3be..3c6eb69 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -30,97 +30,76 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <shared_mutex>
+
 #include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "log_portability.h"
 #include "logger.h"
+#include "rwlock.h"
 #include "uio.h"
 
-static int logdAvailable(log_id_t LogId);
-static int logdOpen();
-static void logdClose();
-static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static void LogdClose();
 
 struct android_log_transport_write logdLoggerWrite = {
-    .name = "logd",
-    .logMask = 0,
-    .context.sock = -EBADF,
-    .available = logdAvailable,
-    .open = logdOpen,
-    .close = logdClose,
-    .write = logdWrite,
+    .close = LogdClose,
+    .write = LogdWrite,
 };
 
-/* log_init_lock assumed */
-static int logdOpen() {
-  int i, ret = 0;
+static int logd_socket;
+static RwLock logd_socket_lock;
 
-  i = atomic_load(&logdLoggerWrite.context.sock);
-  if (i < 0) {
-    int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-    if (sock < 0) {
-      ret = -errno;
-    } else {
-      struct sockaddr_un un;
-      memset(&un, 0, sizeof(struct sockaddr_un));
-      un.sun_family = AF_UNIX;
-      strcpy(un.sun_path, "/dev/socket/logdw");
-
-      if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) <
-          0) {
-        ret = -errno;
-        switch (ret) {
-          case -ENOTCONN:
-          case -ECONNREFUSED:
-          case -ENOENT:
-            i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
-            [[fallthrough]];
-          default:
-            break;
-        }
-        close(sock);
-      } else {
-        ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
-        if ((ret >= 0) && (ret != sock)) {
-          close(ret);
-        }
-        ret = 0;
-      }
-    }
+static void OpenSocketLocked() {
+  logd_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  if (logd_socket <= 0) {
+    return;
   }
 
-  return ret;
-}
+  sockaddr_un un = {};
+  un.sun_family = AF_UNIX;
+  strcpy(un.sun_path, "/dev/socket/logdw");
 
-static void __logdClose(int negative_errno) {
-  int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
-  if (sock >= 0) {
-    close(sock);
+  if (TEMP_FAILURE_RETRY(
+          connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))) < 0) {
+    close(logd_socket);
+    logd_socket = 0;
   }
 }
 
-static void logdClose() {
-  __logdClose(-EBADF);
+static void OpenSocket() {
+  auto lock = std::unique_lock{logd_socket_lock};
+  if (logd_socket > 0) {
+    // Someone raced us and opened the socket already.
+    return;
+  }
+
+  OpenSocketLocked();
 }
 
-static int logdAvailable(log_id_t logId) {
-  if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
-    return -EINVAL;
+static void ResetSocket(int old_socket) {
+  auto lock = std::unique_lock{logd_socket_lock};
+  if (old_socket != logd_socket) {
+    // Someone raced us and reset the socket already.
+    return;
   }
-  if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
-    if (access("/dev/socket/logdw", W_OK) == 0) {
-      return 0;
-    }
-    return -EBADF;
-  }
-  return 1;
+  close(logd_socket);
+  logd_socket = 0;
+  OpenSocketLocked();
 }
 
-static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+static void LogdClose() {
+  auto lock = std::unique_lock{logd_socket_lock};
+  if (logd_socket > 0) {
+    close(logd_socket);
+  }
+  logd_socket = 0;
+}
+
+static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
   ssize_t ret;
-  int sock;
   static const unsigned headerLength = 1;
   struct iovec newVec[nr + headerLength];
   android_log_header_t header;
@@ -128,15 +107,16 @@
   static atomic_int dropped;
   static atomic_int droppedSecurity;
 
-  sock = atomic_load(&logdLoggerWrite.context.sock);
-  if (sock < 0) switch (sock) {
-      case -ENOTCONN:
-      case -ECONNREFUSED:
-      case -ENOENT:
-        break;
-      default:
-        return -EBADF;
-    }
+  auto lock = std::shared_lock{logd_socket_lock};
+  if (logd_socket <= 0) {
+    lock.unlock();
+    OpenSocket();
+    lock.lock();
+  }
+
+  if (logd_socket <= 0) {
+    return -EBADF;
+  }
 
   /* logd, after initialization and priv drop */
   if (__android_log_uid() == AID_LOGD) {
@@ -155,41 +135,39 @@
   newVec[0].iov_base = (unsigned char*)&header;
   newVec[0].iov_len = sizeof(header);
 
-  if (sock >= 0) {
-    int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
-    if (snapshot) {
-      android_log_event_int_t buffer;
+  int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
+  if (snapshot) {
+    android_log_event_int_t buffer;
 
-      header.id = LOG_ID_SECURITY;
-      buffer.header.tag = LIBLOG_LOG_TAG;
-      buffer.payload.type = EVENT_TYPE_INT;
-      buffer.payload.data = snapshot;
+    header.id = LOG_ID_SECURITY;
+    buffer.header.tag = LIBLOG_LOG_TAG;
+    buffer.payload.type = EVENT_TYPE_INT;
+    buffer.payload.data = snapshot;
 
-      newVec[headerLength].iov_base = &buffer;
-      newVec[headerLength].iov_len = sizeof(buffer);
+    newVec[headerLength].iov_base = &buffer;
+    newVec[headerLength].iov_len = sizeof(buffer);
 
-      ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
-      if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-        atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
-      }
+    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
+    if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+      atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
     }
-    snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-    if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
-                                                  ANDROID_LOG_VERBOSE)) {
-      android_log_event_int_t buffer;
+  }
+  snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+  if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
+                                                ANDROID_LOG_VERBOSE)) {
+    android_log_event_int_t buffer;
 
-      header.id = LOG_ID_EVENTS;
-      buffer.header.tag = LIBLOG_LOG_TAG;
-      buffer.payload.type = EVENT_TYPE_INT;
-      buffer.payload.data = snapshot;
+    header.id = LOG_ID_EVENTS;
+    buffer.header.tag = LIBLOG_LOG_TAG;
+    buffer.payload.type = EVENT_TYPE_INT;
+    buffer.payload.data = snapshot;
 
-      newVec[headerLength].iov_base = &buffer;
-      newVec[headerLength].iov_len = sizeof(buffer);
+    newVec[headerLength].iov_base = &buffer;
+    newVec[headerLength].iov_len = sizeof(buffer);
 
-      ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
-      if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-        atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
-      }
+    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
+    if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+      atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
     }
   }
 
@@ -208,49 +186,26 @@
     }
   }
 
-  /*
-   * The write below could be lost, but will never block.
-   *
-   * ENOTCONN occurs if logd has died.
-   * ENOENT occurs if logd is not running and socket is missing.
-   * ECONNREFUSED occurs if we can not reconnect to logd.
-   * EAGAIN occurs if logd is overloaded.
-   */
-  if (sock < 0) {
-    ret = sock;
-  } else {
-    ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
-    if (ret < 0) {
-      ret = -errno;
-    }
+  // The write below could be lost, but will never block.
+  // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
+  // the connection, so we reset it and try again.
+  ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
+  if (ret < 0 && errno != EAGAIN) {
+    int old_socket = logd_socket;
+    lock.unlock();
+    ResetSocket(old_socket);
+    lock.lock();
+
+    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
   }
-  switch (ret) {
-    case -ENOTCONN:
-    case -ECONNREFUSED:
-    case -ENOENT:
-      if (__android_log_trylock()) {
-        return ret; /* in a signal handler? try again when less stressed */
-      }
-      __logdClose(ret);
-      ret = logdOpen();
-      __android_log_unlock();
 
-      if (ret < 0) {
-        return ret;
-      }
-
-      ret = TEMP_FAILURE_RETRY(writev(atomic_load(&logdLoggerWrite.context.sock), newVec, i));
-      if (ret < 0) {
-        ret = -errno;
-      }
-      [[fallthrough]];
-    default:
-      break;
+  if (ret < 0) {
+    ret = -errno;
   }
 
   if (ret > (ssize_t)sizeof(header)) {
     ret -= sizeof(header);
-  } else if (ret == -EAGAIN) {
+  } else if (ret < 0) {
     atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
     if (logId == LOG_ID_SECURITY) {
       atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
diff --git a/liblog/logger.h b/liblog/logger.h
index 9d74d29..40d5fe5 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -26,20 +26,7 @@
 
 __BEGIN_DECLS
 
-/* Union, sock or fd of zero is not allowed unless static initialized */
-union android_log_context_union {
-  void* priv;
-  atomic_int sock;
-  atomic_int fd;
-};
-
 struct android_log_transport_write {
-  const char* name;                  /* human name to describe the transport */
-  unsigned logMask;                  /* mask cache of available() success */
-  union android_log_context_union context; /* Initialized by static allocation */
-
-  int (*available)(log_id_t logId); /* Does not cause resources to be taken */
-  int (*open)();   /* can be called multiple times, reusing current resources */
   void (*close)(); /* free up resources */
   /* write log to transport, returns number of bytes propagated, or -errno */
   int (*write)(log_id_t logId, struct timespec* ts, struct iovec* vec,
@@ -83,8 +70,4 @@
 }
 #endif
 
-void __android_log_lock();
-int __android_log_trylock();
-void __android_log_unlock();
-
 __END_DECLS
diff --git a/liblog/logger_lock.cpp b/liblog/logger_lock.cpp
deleted file mode 100644
index 4636b00..0000000
--- a/liblog/logger_lock.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007-2016 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.
- */
-
-/*
- * Some OS specific dribs and drabs (locking etc).
- */
-
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-
-#include "logger.h"
-
-#if !defined(_WIN32)
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-void __android_log_lock() {
-#if !defined(_WIN32)
-  /*
-   * If we trigger a signal handler in the middle of locked activity and the
-   * signal handler logs a message, we could get into a deadlock state.
-   */
-  pthread_mutex_lock(&log_init_lock);
-#endif
-}
-
-int __android_log_trylock() {
-#if !defined(_WIN32)
-  return pthread_mutex_trylock(&log_init_lock);
-#else
-  return 0;
-#endif
-}
-
-void __android_log_unlock() {
-#if !defined(_WIN32)
-  pthread_mutex_unlock(&log_init_lock);
-#endif
-}
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index e1772f1..d38b402 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -24,7 +24,6 @@
 #include <android/set_abort_message.h>
 #endif
 
-#include <log/event_tag_map.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -47,11 +46,8 @@
 android_log_transport_write* android_log_persist_write = nullptr;
 #endif
 
-static int __write_to_log_init(log_id_t, struct iovec* vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec* vec, size_t nr) = __write_to_log_init;
-
-static int check_log_uid_permissions() {
 #if defined(__ANDROID__)
+static int check_log_uid_permissions() {
   uid_t uid = __android_log_uid();
 
   /* Matches clientHasLogCredentials() in logd */
@@ -88,51 +84,14 @@
       }
     }
   }
-#endif
   return 0;
 }
-
-static void __android_log_cache_available(struct android_log_transport_write* node) {
-  uint32_t i;
-
-  if (node->logMask) {
-    return;
-  }
-
-  for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
-    if (i != LOG_ID_KERNEL && (i != LOG_ID_SECURITY || check_log_uid_permissions() == 0) &&
-        (*node->available)(static_cast<log_id_t>(i)) >= 0) {
-      node->logMask |= 1 << i;
-    }
-  }
-}
-
-#if defined(__ANDROID__)
-static atomic_uintptr_t tagMap;
 #endif
 
 /*
  * Release any logger resources. A new log write will immediately re-acquire.
  */
 void __android_log_close() {
-#if defined(__ANDROID__)
-  EventTagMap* m;
-#endif
-
-  __android_log_lock();
-
-  write_to_log = __write_to_log_init;
-
-  /*
-   * Threads that are actively writing at this point are not held back
-   * by a lock and are at risk of dropping the messages with a return code
-   * -EBADF. Prefer to return error code than add the overhead of a lock to
-   * each log writing call to guarantee delivery. In addition, anyone
-   * calling this is doing so to release the logging resources and shut down,
-   * for them to do so with outstanding log requests in other threads is a
-   * disengenuous use of this function.
-   */
-
   if (android_log_write != nullptr) {
     android_log_write->close();
   }
@@ -141,64 +100,18 @@
     android_log_persist_write->close();
   }
 
-#if defined(__ANDROID__)
-  /*
-   * Additional risk here somewhat mitigated by immediately unlock flushing
-   * the processor cache. The multi-threaded race that we choose to accept,
-   * to minimize locking, is an atomic_load in a writer picking up a value
-   * just prior to entering this routine. There will be an use after free.
-   *
-   * Again, anyone calling this is doing so to release the logging resources
-   * is most probably going to quiesce then shut down; or to restart after
-   * a fork so the risk should be non-existent. For this reason we
-   * choose a mitigation stance for efficiency instead of incuring the cost
-   * of a lock for every log write.
-   */
-  m = (EventTagMap*)atomic_exchange(&tagMap, (uintptr_t)0);
-#endif
-
-  __android_log_unlock();
-
-#if defined(__ANDROID__)
-  if (m != (EventTagMap*)(uintptr_t)-1LL) android_closeEventTagMap(m);
-#endif
 }
 
-static bool transport_initialize(android_log_transport_write* transport) {
-  if (transport == nullptr) {
-    return false;
-  }
-
-  __android_log_cache_available(transport);
-  if (!transport->logMask) {
-    return false;
-  }
-
-  // TODO: Do we actually need to call close() if open() fails?
-  if (transport->open() < 0) {
-    transport->close();
-    return false;
-  }
-
-  return true;
-}
-
-/* log_init_lock assumed */
-static int __write_to_log_initialize() {
-  if (!transport_initialize(android_log_write)) {
-    return -ENODEV;
-  }
-
-  transport_initialize(android_log_persist_write);
-
-  return 1;
-}
-
-static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
+static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
   int ret, save_errno;
   struct timespec ts;
 
   save_errno = errno;
+
+  if (log_id == LOG_ID_KERNEL) {
+    return -EINVAL;
+  }
+
 #if defined(__ANDROID__)
   clock_gettime(android_log_clockid(), &ts);
 
@@ -219,49 +132,10 @@
       return -EPERM;
     }
   } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
-    const char* tag;
-    size_t len;
-    EventTagMap *m, *f;
-
     if (vec[0].iov_len < 4) {
       errno = save_errno;
       return -EINVAL;
     }
-
-    tag = NULL;
-    len = 0;
-    f = NULL;
-    m = (EventTagMap*)atomic_load(&tagMap);
-
-    if (!m) {
-      ret = __android_log_trylock();
-      m = (EventTagMap*)atomic_load(&tagMap); /* trylock flush cache */
-      if (!m) {
-        m = android_openEventTagMap(NULL);
-        if (ret) { /* trylock failed, use local copy, mark for close */
-          f = m;
-        } else {
-          if (!m) { /* One chance to open map file */
-            m = (EventTagMap*)(uintptr_t)-1LL;
-          }
-          atomic_store(&tagMap, (uintptr_t)m);
-        }
-      }
-      if (!ret) { /* trylock succeeded, unlock */
-        __android_log_unlock();
-      }
-    }
-    if (m && (m != (EventTagMap*)(uintptr_t)-1LL)) {
-      tag = android_lookupEventTag_len(m, &len, *static_cast<uint32_t*>(vec[0].iov_base));
-    }
-    ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len, ANDROID_LOG_VERBOSE);
-    if (f) { /* local copy marked for close */
-      android_closeEventTagMap(f);
-    }
-    if (!ret) {
-      errno = save_errno;
-      return -EPERM;
-    }
   } else {
     int prio = *static_cast<int*>(vec[0].iov_base);
     const char* tag = static_cast<const char*>(vec[1].iov_base);
@@ -283,9 +157,8 @@
 #endif
 
   ret = 0;
-  size_t i = 1 << log_id;
 
-  if (android_log_write != nullptr && (android_log_write->logMask & i)) {
+  if (android_log_write != nullptr) {
     ssize_t retval;
     retval = android_log_write->write(log_id, &ts, vec, nr);
     if (ret >= 0) {
@@ -293,7 +166,7 @@
     }
   }
 
-  if (android_log_persist_write != nullptr && (android_log_persist_write->logMask & i)) {
+  if (android_log_persist_write != nullptr) {
     android_log_persist_write->write(log_id, &ts, vec, nr);
   }
 
@@ -301,29 +174,6 @@
   return ret;
 }
 
-static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
-  int ret, save_errno = errno;
-
-  __android_log_lock();
-
-  if (write_to_log == __write_to_log_init) {
-    ret = __write_to_log_initialize();
-    if (ret < 0) {
-      __android_log_unlock();
-      errno = save_errno;
-      return ret;
-    }
-
-    write_to_log = __write_to_log_daemon;
-  }
-
-  __android_log_unlock();
-
-  ret = write_to_log(log_id, vec, nr);
-  errno = save_errno;
-  return ret;
-}
-
 int __android_log_write(int prio, const char* tag, const char* msg) {
   return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 54980d9..4f45780 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -25,68 +25,47 @@
 #include <sys/types.h>
 #include <time.h>
 
+#include <shared_mutex>
+
 #include <log/log_properties.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "log_portability.h"
 #include "logger.h"
+#include "rwlock.h"
 #include "uio.h"
 
-static int pmsgOpen();
-static void pmsgClose();
-static int pmsgAvailable(log_id_t logId);
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+static void PmsgClose();
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
 
 struct android_log_transport_write pmsgLoggerWrite = {
-    .name = "pmsg",
-    .logMask = 0,
-    .context.fd = -1,
-    .available = pmsgAvailable,
-    .open = pmsgOpen,
-    .close = pmsgClose,
-    .write = pmsgWrite,
+    .close = PmsgClose,
+    .write = PmsgWrite,
 };
 
-static int pmsgOpen() {
-  int fd = atomic_load(&pmsgLoggerWrite.context.fd);
-  if (fd < 0) {
-    int i;
+static int pmsg_fd;
+static RwLock pmsg_fd_lock;
 
-    fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
-    i = atomic_exchange(&pmsgLoggerWrite.context.fd, fd);
-    if ((i >= 0) && (i != fd)) {
-      close(i);
-    }
+static void PmsgOpen() {
+  auto lock = std::unique_lock{pmsg_fd_lock};
+  if (pmsg_fd > 0) {
+    // Someone raced us and opened the socket already.
+    return;
   }
 
-  return fd;
+  pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
 }
 
-static void pmsgClose() {
-  int fd = atomic_exchange(&pmsgLoggerWrite.context.fd, -1);
-  if (fd >= 0) {
-    close(fd);
+static void PmsgClose() {
+  auto lock = std::unique_lock{pmsg_fd_lock};
+  if (pmsg_fd > 0) {
+    close(pmsg_fd);
   }
+  pmsg_fd = 0;
 }
 
-static int pmsgAvailable(log_id_t logId) {
-  if (logId > LOG_ID_SECURITY) {
-    return -EINVAL;
-  }
-  if ((logId != LOG_ID_SECURITY) && (logId != LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
-    return -EINVAL;
-  }
-  if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
-    if (access("/dev/pmsg0", W_OK) == 0) {
-      return 0;
-    }
-    return -EBADF;
-  }
-  return 1;
-}
-
-static int pmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
   static const unsigned headerLength = 2;
   struct iovec newVec[nr + headerLength];
   android_log_header_t header;
@@ -94,17 +73,31 @@
   size_t i, payloadSize;
   ssize_t ret;
 
-  if ((logId == LOG_ID_EVENTS) && !__android_log_is_debuggable()) {
-    if (vec[0].iov_len < 4) {
-      return -EINVAL;
+  if (!__android_log_is_debuggable()) {
+    if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
+      return -1;
     }
 
-    if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
-      return -EPERM;
+    if (logId == LOG_ID_EVENTS) {
+      if (vec[0].iov_len < 4) {
+        return -EINVAL;
+      }
+
+      if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
+        return -EPERM;
+      }
     }
   }
 
-  if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
+  auto lock = std::shared_lock{pmsg_fd_lock};
+
+  if (pmsg_fd <= 0) {
+    lock.unlock();
+    PmsgOpen();
+    lock.lock();
+  }
+
+  if (pmsg_fd <= 0) {
     return -EBADF;
   }
 
@@ -158,7 +151,7 @@
   }
   pmsgHeader.len += payloadSize;
 
-  ret = TEMP_FAILURE_RETRY(writev(atomic_load(&pmsgLoggerWrite.context.fd), newVec, i));
+  ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
   if (ret < 0) {
     ret = errno ? -errno : -ENOTCONN;
   }
@@ -193,7 +186,6 @@
 /* Write a buffer as filename references (tag = <basedir>:<basename>) */
 ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
                                       const char* buf, size_t len) {
-  bool weOpened;
   size_t length, packet_len;
   const char* tag;
   char *cp, *slash;
@@ -233,7 +225,6 @@
   vec[1].iov_base = (unsigned char*)tag;
   vec[1].iov_len = length;
 
-  weOpened = false;
   for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
     ssize_t ret;
     size_t transfer;
@@ -254,37 +245,15 @@
     vec[2].iov_base = (unsigned char*)buf;
     vec[2].iov_len = transfer;
 
-    if (atomic_load(&pmsgLoggerWrite.context.fd) < 0) {
-      if (!weOpened) { /* Impossible for weOpened = true here */
-        __android_log_lock();
-      }
-      weOpened = atomic_load(&pmsgLoggerWrite.context.fd) < 0;
-      if (!weOpened) {
-        __android_log_unlock();
-      } else if (pmsgOpen() < 0) {
-        __android_log_unlock();
-        free(cp);
-        return -EBADF;
-      }
-    }
-
-    ret = pmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
+    ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
 
     if (ret <= 0) {
-      if (weOpened) {
-        pmsgClose();
-        __android_log_unlock();
-      }
       free(cp);
       return ret ? ret : (len - length);
     }
     length -= transfer;
     buf += transfer;
   }
-  if (weOpened) {
-    pmsgClose();
-    __android_log_unlock();
-  }
   free(cp);
   return len;
 }
diff --git a/liblog/rwlock.h b/liblog/rwlock.h
new file mode 100644
index 0000000..00f1806
--- /dev/null
+++ b/liblog/rwlock.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+// As of the end of Dec 2019, std::shared_mutex is *not* simply a pthread_rwlock, but rather a
+// combination of std::mutex and std::condition variable, which is obviously less efficient.  This
+// immitates what std::shared_mutex should be doing and is compatible with std::shared_lock and
+// std::unique_lock.
+
+class RwLock {
+ public:
+  RwLock() {}
+  ~RwLock() {}
+
+  void lock() { pthread_rwlock_wrlock(&rwlock_); }
+  void unlock() { pthread_rwlock_unlock(&rwlock_); }
+
+  void lock_shared() { pthread_rwlock_rdlock(&rwlock_); }
+  void unlock_shared() { pthread_rwlock_unlock(&rwlock_); }
+
+ private:
+  pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER;
+};
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 99df4ca..f58c524 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -62,6 +62,7 @@
         "log_time_test.cpp",
         "log_wrap_test.cpp",
         "logprint_test.cpp",
+        "rwlock_test.cpp",
     ],
     shared_libs: [
         "libcutils",
diff --git a/liblog/tests/rwlock_test.cpp b/liblog/tests/rwlock_test.cpp
new file mode 100644
index 0000000..617d5c4
--- /dev/null
+++ b/liblog/tests/rwlock_test.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include "../rwlock.h"
+
+#include <chrono>
+#include <shared_mutex>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+using namespace std::literals;
+
+TEST(rwlock, reader_then_reader_lock) {
+  RwLock lock;
+
+  bool thread_ran = false;
+  auto read_guard = std::shared_lock{lock};
+
+  auto reader_thread = std::thread([&] {
+    auto read_guard = std::shared_lock{lock};
+    thread_ran = true;
+  });
+
+  auto end_time = std::chrono::steady_clock::now() + 1s;
+
+  while (std::chrono::steady_clock::now() < end_time) {
+    if (thread_ran) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(true, thread_ran);
+
+  // Unlock the lock in case something went wrong, to ensure that we can still join() the thread.
+  read_guard.unlock();
+  reader_thread.join();
+}
+
+template <template <typename> typename L1, template <typename> typename L2>
+void TestBlockingLocks() {
+  RwLock lock;
+
+  bool thread_ran = false;
+  auto read_guard = L1{lock};
+
+  auto reader_thread = std::thread([&] {
+    auto read_guard = L2{lock};
+    thread_ran = true;
+  });
+
+  auto end_time = std::chrono::steady_clock::now() + 1s;
+
+  while (std::chrono::steady_clock::now() < end_time) {
+    if (thread_ran) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(false, thread_ran);
+
+  read_guard.unlock();
+  reader_thread.join();
+
+  EXPECT_EQ(true, thread_ran);
+}
+
+TEST(rwlock, reader_then_writer_lock) {
+  TestBlockingLocks<std::shared_lock, std::unique_lock>();
+}
+
+TEST(rwlock, writer_then_reader_lock) {
+  TestBlockingLocks<std::unique_lock, std::shared_lock>();
+}
+
+TEST(rwlock, writer_then_writer_lock) {
+  TestBlockingLocks<std::unique_lock, std::unique_lock>();
+}
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
index 011ab76..177bbba 100644
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -22,7 +22,7 @@
 
 #include <android/os/BnPullAtomCallback.h>
 #include <android/os/IPullAtomResultReceiver.h>
-#include <android/os/IStatsManager.h>
+#include <android/os/IStatsd.h>
 #include <android/util/StatsEventParcel.h>
 #include <binder/IServiceManager.h>
 #include "include/stats_pull_atom_callback.h"
@@ -90,10 +90,10 @@
 };
 
 static std::mutex pullAtomMutex;
-static android::sp<android::os::IStatsManager> sStatsd = nullptr;
+static android::sp<android::os::IStatsd> sStatsd = nullptr;
 
 static std::map<int32_t, android::sp<StatsPullAtomCallbackInternal>> mPullers;
-static android::sp<android::os::IStatsManager> getStatsServiceLocked();
+static android::sp<android::os::IStatsd> getStatsServiceLocked();
 
 class StatsDeathRecipient : public android::IBinder::DeathRecipient {
   public:
@@ -106,7 +106,7 @@
         if (sStatsd) {
             sStatsd = nullptr;
         }
-        android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+        android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
         if (statsService == nullptr) {
             return;
         }
@@ -120,7 +120,7 @@
 
 static android::sp<StatsDeathRecipient> statsDeathRecipient = new StatsDeathRecipient();
 
-static android::sp<android::os::IStatsManager> getStatsServiceLocked() {
+static android::sp<android::os::IStatsd> getStatsServiceLocked() {
     if (!sStatsd) {
         // Fetch statsd.
         const android::sp<android::IBinder> binder =
@@ -129,7 +129,7 @@
             return nullptr;
         }
         binder->linkToDeath(statsDeathRecipient);
-        sStatsd = android::interface_cast<android::os::IStatsManager>(binder);
+        sStatsd = android::interface_cast<android::os::IStatsd>(binder);
     }
     return sStatsd;
 }
@@ -146,7 +146,7 @@
     }
 
     std::lock_guard<std::mutex> lg(pullAtomMutex);
-    const android::sp<android::os::IStatsManager> statsService = getStatsServiceLocked();
+    const android::sp<android::os::IStatsd> statsService = getStatsServiceLocked();
     if (statsService == nullptr) {
         // Error - statsd not available
         return;
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index 9dd0cdd..def4088 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -774,6 +774,6 @@
                             cfa_gnu_negative_offset_extended, cfa_register_override);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfCfaLogTest, DwarfCfaLogTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaLogTest, DwarfCfaLogTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index dd71490..9c6ab05 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -963,6 +963,6 @@
                             cfa_register_override);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfCfaTest, DwarfCfaTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaTest, DwarfCfaTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 2b36f17..b6f574a 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -825,6 +825,6 @@
     GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 4792fb5..46a25a4 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -128,6 +128,6 @@
 REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameTest, DwarfEhFrameTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 768a808..6aa3867 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -552,6 +552,6 @@
                             GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index f4ade5d..8dbf6e8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -68,6 +68,6 @@
 REGISTER_TYPED_TEST_SUITE_P(DwarfOpLogTest, multiple_ops);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfOpLogTest, DwarfOpLogTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpLogTest, DwarfOpLogTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 0898ec0..0e2d91a 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -1581,6 +1581,6 @@
                             is_dex_pc);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfOpTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfOpTest, DwarfOpTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpTest, DwarfOpTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index a9d6dad..cac59b7 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -583,6 +583,6 @@
                             GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfSectionImplTest, DwarfSectionImplTestTypes);
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
index ae3c349..c58aeff 100644
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ b/libunwindstack/tests/SymbolsTest.cpp
@@ -367,6 +367,6 @@
                             symtab_read_cached, get_global);
 
 typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(, SymbolsTest, SymbolsTestTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, SymbolsTest, SymbolsTestTypes);
 
 }  // namespace unwindstack
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ebc0cde..2dbdb60 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -72,7 +72,7 @@
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk \
+    dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
     linkerconfig $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index 5dc019c..80573fb 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -16,6 +16,21 @@
 include $(BUILD_PREBUILT)
 
 #######################################
+# q-developer-gsi.avbpubkey
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := q-developer-gsi.avbpubkey
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else
+LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
+endif
+
+include $(BUILD_PREBUILT)
+
+#######################################
 # r-gsi.avbpubkey
 include $(CLEAR_VARS)
 
diff --git a/rootdir/avb/q-developer-gsi.avbpubkey b/rootdir/avb/q-developer-gsi.avbpubkey
new file mode 100644
index 0000000..0ace69d
--- /dev/null
+++ b/rootdir/avb/q-developer-gsi.avbpubkey
Binary files differ
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2ec0669..b89c45e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -650,12 +650,35 @@
 
     mkdir /data/user 0711 system system encryption=None
     mkdir /data/user_de 0711 system system encryption=None
-    symlink /data/data /data/user/0
+
+    # Unlink /data/user/0 if we previously symlink it to /data/data
+    rm /data/user/0
+
+    # Bind mount /data/user/0 to /data/data
+    mkdir /data/user/0 0700 system system encryption=None
+    mount none /data/data /data/user/0 bind rec
 
     # Special-case /data/media/obb per b/64566063
     mkdir /data/media 0770 media_rw media_rw encryption=None
     mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
 
+    # A tmpfs directory, which will contain all apps CE DE data directory that
+    # bind mount from the original source.
+    chown root root /data_mirror
+    chmod 0700 /data_mirror
+    mount tmpfs tmpfs /data_mirror mode=0700,uid=0,gid=1000 nodev noexec nosuid
+    restorecon /data_mirror
+    mkdir /data_mirror/data_ce 0700 root root
+    mkdir /data_mirror/data_de 0700 root root
+
+    # Create CE and DE data directory for default volume
+    mkdir /data_mirror/data_ce/null 0700 root root
+    mkdir /data_mirror/data_de/null 0700 root root
+
+    # Bind mount CE and DE data directory to mirror's default volume directory
+    mount none /data/user /data_mirror/data_ce/null bind rec
+    mount none /data/user_de /data_mirror/data_de/null bind rec
+
     mkdir /data/cache 0770 system cache encryption=Require
     mkdir /data/cache/recovery 0770 system cache
     mkdir /data/cache/backup_stage 0700 system system
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index a1888fc..02d34ba 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -19,7 +19,9 @@
     updatable
     seclabel u:r:adbd:s0
 
-on boot
+# Set default value on sys.usb.configfs early in boot sequence. It will be
+# overridden in `on boot` action of init.hardware.rc.
+on init
     setprop sys.usb.configfs 0
 
 # Used to disable USB when switching states
@@ -133,3 +135,8 @@
 on property:sys.usb.typec.power_role=sink
     write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}
     setprop sys.usb.typec.state ${sys.usb.typec.power_role}
+
+on userspace-reboot-requested
+  setprop sys.usb.config ""
+  setprop sys.usb.configfs ""
+  setprop sys.usb.state ""
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index ec4f6ab..b5a5fb6 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -12,6 +12,7 @@
     required: [
         "auditctl",
         "awk",
+        "bc",
         "bzip2",
         "ldd",
         "logwrapper",