Merge "Optimize Memory::ReadString"
diff --git a/adb/Android.bp b/adb/Android.bp
index 6386a78..19e921f 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -695,6 +695,7 @@
         "daemon/shell_service_test.cpp",
         "shell_service_protocol.cpp",
         "shell_service_protocol_test.cpp",
+        "mdns_test.cpp",
     ],
 
     shared_libs: [
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 08d3904..06fdb69 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -149,7 +149,7 @@
     case A_WRTE: tag = "WRTE"; break;
     case A_AUTH: tag = "AUTH"; break;
     case A_STLS:
-        tag = "ATLS";
+        tag = "STLS";
         break;
     default: tag = "????"; break;
     }
diff --git a/adb/adb_mdns.h b/adb/adb_mdns.h
index 6b37355..3111248 100644
--- a/adb/adb_mdns.h
+++ b/adb/adb_mdns.h
@@ -19,9 +19,14 @@
 
 #include <android-base/macros.h>
 
-const char* kADBServiceType = "_adb._tcp";
-const char* kADBSecurePairingServiceType = "_adb_secure_pairing._tcp";
-const char* kADBSecureConnectServiceType = "_adb_secure_connect._tcp";
+// The rules for Service Names [RFC6335] state that they may be no more
+// than fifteen characters long (not counting the mandatory underscore),
+// consisting of only letters, digits, and hyphens, must begin and end
+// with a letter or digit, must not contain consecutive hyphens, and
+// must contain at least one letter.
+#define ADB_MDNS_SERVICE_TYPE "adb"
+#define ADB_MDNS_TLS_PAIRING_TYPE "adb-tls-pairing"
+#define ADB_MDNS_TLS_CONNECT_TYPE "adb-tls-connect"
 
 const int kADBTransportServiceRefIndex = 0;
 const int kADBSecurePairingServiceRefIndex = 1;
@@ -71,11 +76,10 @@
 const char* kADBSecureConnectServiceTxtRecord =
         ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);
 
-const char* kADBDNSServices[] = {
-        kADBServiceType,
-        kADBSecurePairingServiceType,
-        kADBSecureConnectServiceType,
-};
+#define ADB_FULL_MDNS_SERVICE_TYPE(atype) ("_" atype "._tcp")
+const char* kADBDNSServices[] = {ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_SERVICE_TYPE),
+                                 ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_PAIRING_TYPE),
+                                 ADB_FULL_MDNS_SERVICE_TYPE(ADB_MDNS_TLS_CONNECT_TYPE)};
 
 const char* kADBDNSServiceTxtRecords[] = {
         nullptr,
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 0ad0465..31c938c 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -416,14 +416,18 @@
     return android::base::StringPrintf("%s:%s", prefix, command);
 }
 
-const FeatureSet& adb_get_feature_set() {
-    static const android::base::NoDestructor<FeatureSet> features([] {
-        std::string result;
-        if (!adb_query(format_host_command("features"), &result, &result)) {
-            fprintf(stderr, "failed to get feature set: %s\n", result.c_str());
-            return FeatureSet{};
-        }
-        return StringToFeatureSet(result);
-    }());
-    return *features;
+const std::optional<FeatureSet>& adb_get_feature_set(std::string* error) {
+    static std::string cached_error [[clang::no_destroy]];
+    static const std::optional<FeatureSet> features
+            [[clang::no_destroy]] ([]() -> std::optional<FeatureSet> {
+                std::string result;
+                if (adb_query(format_host_command("features"), &result, &cached_error)) {
+                    return StringToFeatureSet(result);
+                }
+                return std::nullopt;
+            }());
+    if (!features && error) {
+        *error = cached_error;
+    }
+    return features;
 }
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
index bf0be40..27be28f 100644
--- a/adb/client/adb_client.h
+++ b/adb/client/adb_client.h
@@ -76,7 +76,7 @@
 std::string format_host_command(const char* _Nonnull command);
 
 // Get the feature set of the current preferred transport.
-const FeatureSet& adb_get_feature_set();
+const std::optional<FeatureSet>& adb_get_feature_set(std::string* _Nullable error);
 
 #if defined(__linux__)
 // Get the path of a file containing the path to the server executable, if the socket spec set via
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 3810cc8..59c8563 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -57,11 +57,12 @@
 }
 
 static bool can_use_feature(const char* feature) {
-    auto&& features = adb_get_feature_set();
-    if (features.empty()) {
+    // We ignore errors here, if the device is missing, we'll notice when we try to push install.
+    auto&& features = adb_get_feature_set(nullptr);
+    if (!features) {
         return false;
     }
-    return CanUseFeature(features, feature);
+    return CanUseFeature(*features, feature);
 }
 
 static InstallMode best_install_mode() {
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 4b2fa04..b674a81 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -504,6 +504,12 @@
     }).detach();
 }
 
+// Callback given to SSL_set_cert_cb to select a certificate when server requests
+// for a certificate. This is where the server will give us a CA-issuer list, and
+// figure out if the server knows any of our public keys. We currently always return
+// 1 here to indicate success, since we always try a key here (in the case of no auth).
+// See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_cert_cb
+// for more details.
 int adb_tls_set_certificate(SSL* ssl) {
     LOG(INFO) << __func__;
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 6a7493f..29f9dc1 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -672,16 +672,17 @@
 }
 
 static int adb_shell(int argc, const char** argv) {
-    auto&& features = adb_get_feature_set();
-    if (features.empty()) {
-        return 1;
+    std::string error;
+    auto&& features = adb_get_feature_set(&error);
+    if (!features) {
+        error_exit("%s", error.c_str());
     }
 
     enum PtyAllocationMode { kPtyAuto, kPtyNo, kPtyYes, kPtyDefinitely };
 
     // Defaults.
-    char escape_char = '~'; // -e
-    bool use_shell_protocol = CanUseFeature(features, kFeatureShell2); // -x
+    char escape_char = '~';                                                 // -e
+    bool use_shell_protocol = CanUseFeature(*features, kFeatureShell2);     // -x
     PtyAllocationMode tty = use_shell_protocol ? kPtyAuto : kPtyDefinitely; // -t/-T
 
     // Parse shell-specific command-line options.
@@ -757,7 +758,7 @@
     if (!use_shell_protocol) {
         if (shell_type_arg != kShellServiceArgPty) {
             fprintf(stderr, "error: %s only supports allocating a pty\n",
-                    !CanUseFeature(features, kFeatureShell2) ? "device" : "-x");
+                    !CanUseFeature(*features, kFeatureShell2) ? "device" : "-x");
             return 1;
         } else {
             // If we're not using the shell protocol, the type argument must be empty.
@@ -777,11 +778,13 @@
 }
 
 static int adb_abb(int argc, const char** argv) {
-    auto&& features = adb_get_feature_set();
-    if (features.empty()) {
+    std::string error;
+    auto&& features = adb_get_feature_set(&error);
+    if (!features) {
+        error_exit("%s", error.c_str());
         return 1;
     }
-    if (!CanUseFeature(features, kFeatureAbb)) {
+    if (!CanUseFeature(*features, kFeatureAbb)) {
         error_exit("abb is not supported by the device");
     }
 
@@ -1159,9 +1162,9 @@
         // Use shell protocol if it's supported and the caller doesn't explicitly
         // disable it.
         if (!disable_shell_protocol) {
-            auto&& features = adb_get_feature_set();
-            if (!features.empty()) {
-                use_shell_protocol = CanUseFeature(features, kFeatureShell2);
+            auto&& features = adb_get_feature_set(nullptr);
+            if (features) {
+                use_shell_protocol = CanUseFeature(*features, kFeatureShell2);
             } else {
                 // Device was unreachable.
                 attempt_connection = false;
@@ -1810,12 +1813,13 @@
         }
         return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
     } else if (!strcmp(argv[0], "remount")) {
-        auto&& features = adb_get_feature_set();
-        if (features.empty()) {
-            return 1;
+        std::string error;
+        auto&& features = adb_get_feature_set(&error);
+        if (!features) {
+            error_exit("%s", error.c_str());
         }
 
-        if (CanUseFeature(features, kFeatureRemountShell)) {
+        if (CanUseFeature(*features, kFeatureRemountShell)) {
             std::vector<const char*> args = {"shell"};
             args.insert(args.cend(), argv, argv + argc);
             return adb_shell_noinput(args.size(), args.data());
@@ -2034,11 +2038,12 @@
     } else if (!strcmp(argv[0], "track-jdwp")) {
         return adb_connect_command("track-jdwp");
     } else if (!strcmp(argv[0], "track-app")) {
-        auto&& features = adb_get_feature_set();
-        if (features.empty()) {
-            return 1;
+        std::string error;
+        auto&& features = adb_get_feature_set(&error);
+        if (!features) {
+            error_exit("%s", error.c_str());
         }
-        if (!CanUseFeature(features, kFeatureTrackApp)) {
+        if (!CanUseFeature(*features, kFeatureTrackApp)) {
             error_exit("track-app is not supported by the device");
         }
         TrackAppStreamsCallback callback;
@@ -2064,13 +2069,14 @@
         return 0;
     } else if (!strcmp(argv[0], "features")) {
         // Only list the features common to both the adb client and the device.
-        auto&& features = adb_get_feature_set();
-        if (features.empty()) {
-            return 1;
+        std::string error;
+        auto&& features = adb_get_feature_set(&error);
+        if (!features) {
+            error_exit("%s", error.c_str());
         }
 
-        for (const std::string& name : features) {
-            if (CanUseFeature(features, name)) {
+        for (const std::string& name : *features) {
+            if (CanUseFeature(*features, name)) {
                 printf("%s\n", name.c_str());
             }
         }
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index f2c673a..7185939 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -225,21 +225,22 @@
 
 class SyncConnection {
   public:
-    SyncConnection()
-        : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX),
-          features_(adb_get_feature_set()) {
+    SyncConnection() : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) {
         acknowledgement_buffer_.resize(0);
         max = SYNC_DATA_MAX; // TODO: decide at runtime.
 
-        if (features_.empty()) {
-            Error("failed to get feature set");
+        std::string error;
+        auto&& features = adb_get_feature_set(&error);
+        if (!features) {
+            Error("failed to get feature set: %s", error.c_str());
         } else {
-            have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
-            have_ls_v2_ = CanUseFeature(features_, kFeatureLs2);
-            have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2);
-            have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli);
-            have_sendrecv_v2_lz4_ = CanUseFeature(features_, kFeatureSendRecv2LZ4);
-            have_sendrecv_v2_dry_run_send_ = CanUseFeature(features_, kFeatureSendRecv2DryRunSend);
+            features_ = &*features;
+            have_stat_v2_ = CanUseFeature(*features, kFeatureStat2);
+            have_ls_v2_ = CanUseFeature(*features, kFeatureLs2);
+            have_sendrecv_v2_ = CanUseFeature(*features, kFeatureSendRecv2);
+            have_sendrecv_v2_brotli_ = CanUseFeature(*features, kFeatureSendRecv2Brotli);
+            have_sendrecv_v2_lz4_ = CanUseFeature(*features, kFeatureSendRecv2LZ4);
+            have_sendrecv_v2_dry_run_send_ = CanUseFeature(*features, kFeatureSendRecv2DryRunSend);
             std::string error;
             fd.reset(adb_connect("sync:", &error));
             if (fd < 0) {
@@ -283,7 +284,7 @@
         return compression;
     }
 
-    const FeatureSet& Features() const { return features_; }
+    const FeatureSet& Features() const { return *features_; }
 
     bool IsValid() { return fd >= 0; }
 
@@ -921,7 +922,7 @@
   private:
     std::deque<std::pair<std::string, std::string>> deferred_acknowledgements_;
     Block acknowledgement_buffer_;
-    const FeatureSet& features_;
+    const FeatureSet* features_ = nullptr;
     bool have_stat_v2_;
     bool have_ls_v2_;
     bool have_sendrecv_v2_;
diff --git a/adb/client/incremental_server.cpp b/adb/client/incremental_server.cpp
index 1a1361c..bfe18c0 100644
--- a/adb/client/incremental_server.cpp
+++ b/adb/client/incremental_server.cpp
@@ -264,7 +264,7 @@
     char* pendingBlocks_ = nullptr;
 
     // True when client notifies that all the data has been received
-    bool servingComplete_;
+    bool servingComplete_ = false;
 };
 
 bool IncrementalServer::SkipToRequest(void* buffer, size_t* size, bool blocking) {
diff --git a/adb/libs/adbconnection/adbconnection_client.cpp b/adb/libs/adbconnection/adbconnection_client.cpp
index b569421..7e16148 100644
--- a/adb/libs/adbconnection/adbconnection_client.cpp
+++ b/adb/libs/adbconnection/adbconnection_client.cpp
@@ -122,16 +122,7 @@
     return nullptr;
   }
 
-#if defined(__APPLE__)
-  ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET, 0));
-  // TODO: find a better home for all these copies of the mac CLOEXEC workaround.
-  if (int fd = ctx->control_socket_.get(), flags = fcntl(fd, F_GETFD);
-      flags != -1 && (flags & FD_CLOEXEC) == 0) {
-    fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
-  }
-#else
   ctx->control_socket_.reset(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
-#endif
   if (ctx->control_socket_ < 0) {
     PLOG(ERROR) << "failed to create Unix domain socket";
     return nullptr;
@@ -149,7 +140,13 @@
 
   int rc = connect(ctx->control_socket_.get(), reinterpret_cast<sockaddr*>(&addr), addr_len);
   if (rc != 0) {
-    PLOG(ERROR) << "failed to connect to jdwp control socket";
+    if (errno == ECONNREFUSED) {
+      // On userdebug devices, every Java process is debuggable, so if adbd is explicitly turned
+      // off, this would spew enormous amounts of red-herring errors.
+      LOG(DEBUG) << "failed to connect to jdwp control socket, adbd not running?";
+    } else {
+      PLOG(ERROR) << "failed to connect to jdwp control socket";
+    }
     return nullptr;
   }
 
diff --git a/adb/mdns_test.cpp b/adb/mdns_test.cpp
new file mode 100644
index 0000000..1f662c1
--- /dev/null
+++ b/adb/mdns_test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "adb_mdns.h"
+
+static bool isValidMdnsServiceName(std::string_view name) {
+    // The rules for Service Names [RFC6335] state that they may be no more
+    // than fifteen characters long (not counting the mandatory underscore),
+    // consisting of only letters, digits, and hyphens, must begin and end
+    // with a letter or digit, must not contain consecutive hyphens, and
+    // must contain at least one letter.
+
+    // No more than 15 characters long
+    if (name.empty() || name.size() > 15) {
+        return false;
+    }
+
+    bool hasAtLeastOneLetter = false;
+    bool sawHyphen = false;
+    for (size_t i = 0; i < name.size(); ++i) {
+        // Must contain at least one letter
+        // Only contains letters, digits and hyphens
+        if (name[i] == '-') {
+            // Cannot be at beginning or end
+            if (i == 0 || i == name.size() - 1) {
+                return false;
+            }
+            if (sawHyphen) {
+                // Consecutive hyphen found
+                return false;
+            }
+            sawHyphen = true;
+            continue;
+        }
+
+        sawHyphen = false;
+        if ((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z')) {
+            hasAtLeastOneLetter = true;
+            continue;
+        }
+
+        if (name[i] >= '0' && name[i] <= '9') {
+            continue;
+        }
+
+        // Invalid character
+        return false;
+    }
+
+    return hasAtLeastOneLetter;
+}
+
+TEST(mdns, test_isValidMdnsServiceName) {
+    // Longer than 15 characters
+    EXPECT_FALSE(isValidMdnsServiceName("abcd1234abcd1234"));
+
+    // Contains invalid characters
+    EXPECT_FALSE(isValidMdnsServiceName("a*a"));
+    EXPECT_FALSE(isValidMdnsServiceName("a_a"));
+    EXPECT_FALSE(isValidMdnsServiceName("_a"));
+
+    // Does not begin or end with letter or digit
+    EXPECT_FALSE(isValidMdnsServiceName(""));
+    EXPECT_FALSE(isValidMdnsServiceName("-"));
+    EXPECT_FALSE(isValidMdnsServiceName("-a"));
+    EXPECT_FALSE(isValidMdnsServiceName("-1"));
+    EXPECT_FALSE(isValidMdnsServiceName("a-"));
+    EXPECT_FALSE(isValidMdnsServiceName("1-"));
+
+    // Contains consecutive hyphens
+    EXPECT_FALSE(isValidMdnsServiceName("a--a"));
+
+    // Does not contain at least one letter
+    EXPECT_FALSE(isValidMdnsServiceName("1"));
+    EXPECT_FALSE(isValidMdnsServiceName("12"));
+    EXPECT_FALSE(isValidMdnsServiceName("1-2"));
+
+    // Some valid names
+    EXPECT_TRUE(isValidMdnsServiceName("a"));
+    EXPECT_TRUE(isValidMdnsServiceName("a1"));
+    EXPECT_TRUE(isValidMdnsServiceName("1A"));
+    EXPECT_TRUE(isValidMdnsServiceName("aZ"));
+    EXPECT_TRUE(isValidMdnsServiceName("a-Z"));
+    EXPECT_TRUE(isValidMdnsServiceName("a-b-Z"));
+    EXPECT_TRUE(isValidMdnsServiceName("abc-def-123-456"));
+}
+
+TEST(mdns, ServiceName_RFC6335) {
+    EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_SERVICE_TYPE));
+    EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_PAIRING_TYPE));
+    EXPECT_TRUE(isValidMdnsServiceName(ADB_MDNS_TLS_CONNECT_TYPE));
+}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 963c3c1..25ed366 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -505,11 +505,10 @@
 
     int osh = cast_handle_to_int(adb_get_os_handle(fd_));
 #if ADB_HOST
-    tls_ = TlsConnection::Create(TlsConnection::Role::Client,
+    tls_ = TlsConnection::Create(TlsConnection::Role::Client, x509_str, evp_str, osh);
 #else
-    tls_ = TlsConnection::Create(TlsConnection::Role::Server,
+    tls_ = TlsConnection::Create(TlsConnection::Role::Server, x509_str, evp_str, osh);
 #endif
-                                 x509_str, evp_str, osh);
     CHECK(tls_);
 #if ADB_HOST
     // TLS 1.3 gives the client no message if the server rejected the
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 884856d..3a2deb7 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -145,6 +145,7 @@
     static_libs: [
         "libhealthhalutils",
         "libsnapshot_nobinder",
+        "update_metadata-protos",
     ],
 
     header_libs: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 0c2569d..d2daaa1 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -62,6 +62,7 @@
 #include <fs_mgr_overlayfs.h>
 #include <fscrypt/fscrypt.h>
 #include <libdm/dm.h>
+#include <libdm/loop_control.h>
 #include <liblp/metadata_format.h>
 #include <linux/fs.h>
 #include <linux/loop.h>
@@ -105,6 +106,7 @@
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
 using android::dm::DmTargetLinear;
+using android::dm::LoopControl;
 
 // Realistically, this file should be part of the android::fs_mgr namespace;
 using namespace android::fs_mgr;
@@ -1908,19 +1910,6 @@
         return InstallZramDevice(bdev);
     }
 
-    // Get free loopback
-    unique_fd loop_fd(TEMP_FAILURE_RETRY(open("/dev/loop-control", O_RDWR | O_CLOEXEC)));
-    if (loop_fd.get() == -1) {
-        PERROR << "Cannot open loop-control";
-        return false;
-    }
-
-    int num = ioctl(loop_fd.get(), LOOP_CTL_GET_FREE);
-    if (num == -1) {
-        PERROR << "Cannot get free loop slot";
-        return false;
-    }
-
     // Prepare target path
     unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
     if (target_fd.get() == -1) {
@@ -1932,25 +1921,21 @@
         return false;
     }
 
-    // Connect loopback (device_fd) to target path (target_fd)
-    std::string device = android::base::StringPrintf("/dev/block/loop%d", num);
-    unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
-    if (device_fd.get() == -1) {
-        PERROR << "Cannot open /dev/block/loop" << num;
-        return false;
-    }
-
-    if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get())) {
-        PERROR << "Cannot set loopback to target path";
+    // Allocate loop device and attach it to file_path.
+    LoopControl loop_control;
+    std::string device;
+    if (!loop_control.Attach(target_fd.get(), 5s, &device)) {
         return false;
     }
 
     // set block size & direct IO
-    if (ioctl(device_fd.get(), LOOP_SET_BLOCK_SIZE, 4096)) {
-        PWARNING << "Cannot set 4KB blocksize to /dev/block/loop" << num;
+    unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
+    if (device_fd.get() == -1) {
+        PERROR << "Cannot open " << device;
+        return false;
     }
-    if (ioctl(device_fd.get(), LOOP_SET_DIRECT_IO, 1)) {
-        PWARNING << "Cannot set direct_io to /dev/block/loop" << num;
+    if (!LoopControl::EnableDirectIo(device_fd.get())) {
+        return false;
     }
 
     return InstallZramDevice(device);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 4e3984c..384595d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -26,7 +26,6 @@
         "libbase",
         "libcutils",
         "liblog",
-        "liblp",
     ],
     static_libs: [
         "libdm",
@@ -73,6 +72,7 @@
         "device_info.cpp",
         "snapshot.cpp",
         "snapshot_stats.cpp",
+        "snapshot_stub.cpp",
         "snapshot_metadata_updater.cpp",
         "partition_cow_creator.cpp",
         "return.cpp",
@@ -209,6 +209,7 @@
     static_libs: [
         "libfstab",
         "libsnapshot",
+        "update_metadata-protos",
     ],
     shared_libs: [
         "android.hardware.boot@1.0",
@@ -234,6 +235,7 @@
     ],
     static_libs: [
         "libsnapshot",
+        "update_metadata-protos",
     ],
     shared_libs: [
         "libbase",
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
new file mode 100644
index 0000000..ef9d648
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
@@ -0,0 +1,37 @@
+// 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 <libsnapshot/snapshot.h>
+
+#include <gmock/gmock.h>
+
+namespace android::snapshot {
+
+class MockDeviceInfo : public SnapshotManager::IDeviceInfo {
+  public:
+    MOCK_METHOD(std::string, GetGsidDir, (), (const, override));
+    MOCK_METHOD(std::string, GetMetadataDir, (), (const, override));
+    MOCK_METHOD(std::string, GetSlotSuffix, (), (const, override));
+    MOCK_METHOD(std::string, GetOtherSlotSuffix, (), (const, override));
+    MOCK_METHOD(std::string, GetSuperDevice, (uint32_t slot), (const, override));
+    MOCK_METHOD(const android::fs_mgr::IPartitionOpener&, GetPartitionOpener, (), (const));
+    MOCK_METHOD(bool, IsOverlayfsSetup, (), (const, override));
+    MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
+    MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
+    MOCK_METHOD(bool, IsRecovery, (), (const, override));
+};
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
new file mode 100644
index 0000000..758d66c
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -0,0 +1,54 @@
+// 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 <libsnapshot/snapshot.h>
+
+#include <gmock/gmock.h>
+
+namespace android::snapshot {
+
+class MockSnapshotManager : public ISnapshotManager {
+  public:
+    MOCK_METHOD(bool, BeginUpdate, (), (override));
+    MOCK_METHOD(bool, CancelUpdate, (), (override));
+    MOCK_METHOD(bool, FinishedSnapshotWrites, (bool wipe), (override));
+    MOCK_METHOD(bool, InitiateMerge, (), (override));
+
+    MOCK_METHOD(UpdateState, ProcessUpdateState,
+                (const std::function<bool()>& callback, const std::function<bool()>& before_cancel),
+                (override));
+    MOCK_METHOD(UpdateState, GetUpdateState, (double* progress), (override));
+    MOCK_METHOD(Return, CreateUpdateSnapshots,
+                (const chromeos_update_engine::DeltaArchiveManifest& manifest), (override));
+    MOCK_METHOD(bool, MapUpdateSnapshot,
+                (const android::fs_mgr::CreateLogicalPartitionParams& params,
+                 std::string* snapshot_path),
+                (override));
+    MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
+    MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
+    MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
+                (const std::string& super_device, const std::chrono::milliseconds& timeout_ms),
+                (override));
+    MOCK_METHOD(bool, HandleImminentDataWipe, (const std::function<void()>& callback), (override));
+    MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices, (), (override));
+    MOCK_METHOD(CreateResult, RecoveryCreateSnapshotDevices,
+                (const std::unique_ptr<AutoDevice>& metadata_device), (override));
+    MOCK_METHOD(bool, Dump, (std::ostream & os), (override));
+    MOCK_METHOD(std::unique_ptr<AutoDevice>, EnsureMetadataMounted, (), (override));
+    MOCK_METHOD(ISnapshotMergeStats*, GetSnapshotMergeStatsInstance, (), (override));
+};
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1daa83b..fff667e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -70,6 +70,8 @@
 struct AutoDeleteSnapshot;
 struct AutoDeviceList;
 struct PartitionCowCreator;
+class ISnapshotMergeStats;
+class SnapshotMergeStats;
 class SnapshotStatus;
 
 static constexpr const std::string_view kCowGroupName = "cow";
@@ -83,17 +85,7 @@
     NOT_CREATED,
 };
 
-class SnapshotManager final {
-    using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
-    using IPartitionOpener = android::fs_mgr::IPartitionOpener;
-    using LpMetadata = android::fs_mgr::LpMetadata;
-    using MetadataBuilder = android::fs_mgr::MetadataBuilder;
-    using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
-    using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
-    using FiemapStatus = android::fiemap::FiemapStatus;
-
-    friend class SnapshotMergeStats;
-
+class ISnapshotManager {
   public:
     // Dependency injection for testing.
     class IDeviceInfo {
@@ -104,39 +96,23 @@
         virtual std::string GetSlotSuffix() const = 0;
         virtual std::string GetOtherSlotSuffix() const = 0;
         virtual std::string GetSuperDevice(uint32_t slot) const = 0;
-        virtual const IPartitionOpener& GetPartitionOpener() const = 0;
+        virtual const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const = 0;
         virtual bool IsOverlayfsSetup() const = 0;
-        virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
+        virtual bool SetBootControlMergeStatus(
+                android::hardware::boot::V1_1::MergeStatus status) = 0;
         virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
         virtual bool IsRecovery() const = 0;
     };
-
-    ~SnapshotManager();
-
-    // Return a new SnapshotManager instance, or null on error. The device
-    // pointer is owned for the lifetime of SnapshotManager. If null, a default
-    // instance will be created.
-    static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);
-
-    // This is similar to New(), except designed specifically for first-stage
-    // init or recovery.
-    static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);
-
-    // Helper function for first-stage init to check whether a SnapshotManager
-    // 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();
+    virtual ~ISnapshotManager() = default;
 
     // Begin an update. This must be called before creating any snapshots. It
     // will fail if GetUpdateState() != None.
-    bool BeginUpdate();
+    virtual bool BeginUpdate() = 0;
 
     // Cancel an update; any snapshots will be deleted. This is allowed if the
     // state == Initiated, None, or Unverified (before rebooting to the new
     // slot).
-    bool CancelUpdate();
+    virtual bool CancelUpdate() = 0;
 
     // Mark snapshot writes as having completed. After this, new snapshots cannot
     // be created, and the device must either cancel the OTA (either before
@@ -144,11 +120,11 @@
     // Before calling this function, all snapshots must be mapped.
     // If |wipe| is set to true, wipe is scheduled after reboot, and snapshots
     // may need to be merged before wiping.
-    bool FinishedSnapshotWrites(bool wipe);
+    virtual bool FinishedSnapshotWrites(bool wipe) = 0;
 
     // Initiate a merge on all snapshot devices. This should only be used after an
     // update has been marked successful after booting.
-    bool InitiateMerge();
+    virtual bool InitiateMerge() = 0;
 
     // Perform any necessary post-boot actions. This should be run soon after
     // /data is mounted.
@@ -178,8 +154,8 @@
     //
     // The optional callback allows the caller to periodically check the
     // progress with GetUpdateState().
-    UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
-                                   const std::function<bool()>& before_cancel = {});
+    virtual UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+                                           const std::function<bool()>& before_cancel = {}) = 0;
 
     // Find the status of the current update, if any.
     //
@@ -187,28 +163,30 @@
     //   Merging: Value in the range [0, 100]
     //   MergeCompleted: 100
     //   Other: 0
-    UpdateState GetUpdateState(double* progress = nullptr);
+    virtual UpdateState GetUpdateState(double* progress = nullptr) = 0;
 
     // Create necessary COW device / files for OTA clients. New logical partitions will be added to
     // group "cow" in target_metadata. Regions of partitions of current_metadata will be
     // "write-protected" and snapshotted.
-    Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest);
+    virtual Return CreateUpdateSnapshots(
+            const chromeos_update_engine::DeltaArchiveManifest& manifest) = 0;
 
     // Map a snapshotted partition for OTA clients to write to. Write-protected regions are
     // determined previously in CreateSnapshots.
-    bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params, std::string* snapshot_path);
+    virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
+                                   std::string* snapshot_path) = 0;
 
     // Unmap a snapshot device that's previously mapped with MapUpdateSnapshot.
-    bool UnmapUpdateSnapshot(const std::string& target_partition_name);
+    virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;
 
     // If this returns true, first-stage mount must call
     // CreateLogicalAndSnapshotPartitions rather than CreateLogicalPartitions.
-    bool NeedSnapshotsInFirstStageMount();
+    virtual bool NeedSnapshotsInFirstStageMount() = 0;
 
     // Perform first-stage mapping of snapshot targets. This replaces init's
     // call to CreateLogicalPartitions when snapshots are present.
-    bool CreateLogicalAndSnapshotPartitions(const std::string& super_device,
-                                            const std::chrono::milliseconds& timeout_ms = {});
+    virtual bool CreateLogicalAndSnapshotPartitions(
+            const std::string& super_device, const std::chrono::milliseconds& timeout_ms = {}) = 0;
 
     // This method should be called preceding any wipe or flash of metadata or
     // userdata. It is only valid in recovery or fastbootd, and it ensures that
@@ -221,7 +199,7 @@
     //
     // Returns true on success (or nothing to do), false on failure. The
     // optional callback fires periodically to query progress via GetUpdateState.
-    bool HandleImminentDataWipe(const std::function<void()>& callback = {});
+    virtual bool HandleImminentDataWipe(const std::function<void()>& callback = {}) = 0;
 
     // This method is only allowed in recovery and is used as a helper to
     // initialize the snapshot devices as a requirement to mount a snapshotted
@@ -234,14 +212,15 @@
     // be aborted.
     // This function mounts /metadata when called, and unmounts /metadata upon
     // return.
-    CreateResult RecoveryCreateSnapshotDevices();
+    virtual CreateResult RecoveryCreateSnapshotDevices() = 0;
 
     // Same as RecoveryCreateSnapshotDevices(), but does not auto mount/umount
     // /metadata.
-    CreateResult RecoveryCreateSnapshotDevices(const std::unique_ptr<AutoDevice>& metadata_device);
+    virtual CreateResult RecoveryCreateSnapshotDevices(
+            const std::unique_ptr<AutoDevice>& metadata_device) = 0;
 
     // Dump debug information.
-    bool Dump(std::ostream& os);
+    virtual bool Dump(std::ostream& os) = 0;
 
     // Ensure metadata directory is mounted in recovery. When the returned
     // AutoDevice is destroyed, the metadata directory is automatically
@@ -257,7 +236,65 @@
     //   auto b = mgr->EnsureMetadataMounted(); // does nothing
     //   b.reset() // unmounts
     //   a.reset() // does nothing
-    std::unique_ptr<AutoDevice> EnsureMetadataMounted();
+    virtual std::unique_ptr<AutoDevice> EnsureMetadataMounted() = 0;
+
+    // Return the associated ISnapshotMergeStats instance. Never null.
+    virtual ISnapshotMergeStats* GetSnapshotMergeStatsInstance() = 0;
+};
+
+class SnapshotManager final : public ISnapshotManager {
+    using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
+    using IPartitionOpener = android::fs_mgr::IPartitionOpener;
+    using LpMetadata = android::fs_mgr::LpMetadata;
+    using MetadataBuilder = android::fs_mgr::MetadataBuilder;
+    using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
+    using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
+    using FiemapStatus = android::fiemap::FiemapStatus;
+
+    friend class SnapshotMergeStats;
+
+  public:
+    ~SnapshotManager();
+
+    // Return a new SnapshotManager instance, or null on error. The device
+    // pointer is owned for the lifetime of SnapshotManager. If null, a default
+    // instance will be created.
+    static std::unique_ptr<SnapshotManager> New(IDeviceInfo* device = nullptr);
+
+    // This is similar to New(), except designed specifically for first-stage
+    // init or recovery.
+    static std::unique_ptr<SnapshotManager> NewForFirstStageMount(IDeviceInfo* device = nullptr);
+
+    // Helper function for first-stage init to check whether a SnapshotManager
+    // 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();
+
+    // ISnapshotManager overrides.
+    bool BeginUpdate() override;
+    bool CancelUpdate() override;
+    bool FinishedSnapshotWrites(bool wipe) override;
+    bool InitiateMerge() override;
+    UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+                                   const std::function<bool()>& before_cancel = {}) override;
+    UpdateState GetUpdateState(double* progress = nullptr) override;
+    Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
+    bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
+                           std::string* snapshot_path) override;
+    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
+    bool NeedSnapshotsInFirstStageMount() override;
+    bool CreateLogicalAndSnapshotPartitions(
+            const std::string& super_device,
+            const std::chrono::milliseconds& timeout_ms = {}) override;
+    bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+    CreateResult RecoveryCreateSnapshotDevices() override;
+    CreateResult RecoveryCreateSnapshotDevices(
+            const std::unique_ptr<AutoDevice>& metadata_device) override;
+    bool Dump(std::ostream& os) override;
+    std::unique_ptr<AutoDevice> EnsureMetadataMounted() override;
+    ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
 
   private:
     FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 91dd34f..4caf632 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -23,14 +23,12 @@
 namespace android {
 namespace snapshot {
 
-class SnapshotMergeStats {
+class ISnapshotMergeStats {
   public:
-    // Not thread safe.
-    static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
-
+    virtual ~ISnapshotMergeStats() = default;
     // Called when merge starts or resumes.
-    bool Start();
-    void set_state(android::snapshot::UpdateState state);
+    virtual bool Start() = 0;
+    virtual void set_state(android::snapshot::UpdateState state) = 0;
 
     // Called when merge ends. Properly clean up permanent storage.
     class Result {
@@ -40,7 +38,19 @@
         // Time between successful Start() / Resume() to Finish().
         virtual std::chrono::steady_clock::duration merge_time() const = 0;
     };
-    std::unique_ptr<Result> Finish();
+    // Return nullptr if any failure.
+    virtual std::unique_ptr<Result> Finish() = 0;
+};
+
+class SnapshotMergeStats : public ISnapshotMergeStats {
+  public:
+    // Not thread safe.
+    static SnapshotMergeStats* GetInstance(SnapshotManager& manager);
+
+    // ISnapshotMergeStats overrides
+    bool Start() override;
+    void set_state(android::snapshot::UpdateState state) override;
+    std::unique_ptr<Result> Finish() override;
 
   private:
     bool ReadState();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
new file mode 100644
index 0000000..9b2590c
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -0,0 +1,52 @@
+// 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 <libsnapshot/snapshot.h>
+
+namespace android::snapshot {
+
+class SnapshotManagerStub : public ISnapshotManager {
+  public:
+    // Create a stubbed snapshot manager. All calls into the stub fails.
+    static std::unique_ptr<ISnapshotManager> New();
+
+    // ISnapshotManager overrides.
+    bool BeginUpdate() override;
+    bool CancelUpdate() override;
+    bool FinishedSnapshotWrites(bool wipe) override;
+    bool InitiateMerge() override;
+    UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
+                                   const std::function<bool()>& before_cancel = {}) override;
+    UpdateState GetUpdateState(double* progress = nullptr) override;
+    Return CreateUpdateSnapshots(
+            const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
+    bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
+                           std::string* snapshot_path) override;
+    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
+    bool NeedSnapshotsInFirstStageMount() override;
+    bool CreateLogicalAndSnapshotPartitions(
+            const std::string& super_device,
+            const std::chrono::milliseconds& timeout_ms = {}) override;
+    bool HandleImminentDataWipe(const std::function<void()>& callback = {}) override;
+    CreateResult RecoveryCreateSnapshotDevices() override;
+    CreateResult RecoveryCreateSnapshotDevices(
+            const std::unique_ptr<AutoDevice>& metadata_device) override;
+    bool Dump(std::ostream& os) override;
+    std::unique_ptr<AutoDevice> EnsureMetadataMounted() override;
+    ISnapshotMergeStats* GetSnapshotMergeStatsInstance() override;
+};
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c9fa28e..eafeea2 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2685,5 +2685,9 @@
     return true;
 }
 
+ISnapshotMergeStats* SnapshotManager::GetSnapshotMergeStatsInstance() {
+    return SnapshotMergeStats::GetInstance(*this);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
new file mode 100644
index 0000000..2747b03
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -0,0 +1,125 @@
+// 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.
+
+#include <libsnapshot/snapshot_stub.h>
+
+#include <android-base/logging.h>
+
+#include <libsnapshot/snapshot_stats.h>
+
+using android::fs_mgr::CreateLogicalPartitionParams;
+using chromeos_update_engine::DeltaArchiveManifest;
+
+namespace android::snapshot {
+
+std::unique_ptr<ISnapshotManager> SnapshotManagerStub::New() {
+    return std::make_unique<SnapshotManagerStub>();
+}
+
+bool SnapshotManagerStub::BeginUpdate() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::CancelUpdate() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::FinishedSnapshotWrites(bool) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::InitiateMerge() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+UpdateState SnapshotManagerStub::ProcessUpdateState(const std::function<bool()>&,
+                                                    const std::function<bool()>&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return UpdateState::None;
+}
+
+UpdateState SnapshotManagerStub::GetUpdateState(double*) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return UpdateState::None;
+}
+
+Return SnapshotManagerStub::CreateUpdateSnapshots(const DeltaArchiveManifest&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return Return::Error();
+}
+
+bool SnapshotManagerStub::MapUpdateSnapshot(const CreateLogicalPartitionParams&, std::string*) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::UnmapUpdateSnapshot(const std::string&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::NeedSnapshotsInFirstStageMount() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::CreateLogicalAndSnapshotPartitions(const std::string&,
+                                                             const std::chrono::milliseconds&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+bool SnapshotManagerStub::HandleImminentDataWipe(const std::function<void()>&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+CreateResult SnapshotManagerStub::RecoveryCreateSnapshotDevices() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return CreateResult::ERROR;
+}
+
+CreateResult SnapshotManagerStub::RecoveryCreateSnapshotDevices(
+        const std::unique_ptr<AutoDevice>&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return CreateResult::ERROR;
+}
+
+bool SnapshotManagerStub::Dump(std::ostream&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
+std::unique_ptr<AutoDevice> SnapshotManagerStub::EnsureMetadataMounted() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return nullptr;
+}
+
+class SnapshotMergeStatsStub : public ISnapshotMergeStats {
+    bool Start() override { return false; }
+    void set_state(android::snapshot::UpdateState) override {}
+    std::unique_ptr<Result> Finish() override { return nullptr; }
+};
+
+ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
+    static SnapshotMergeStatsStub snapshot_merge_stats;
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return &snapshot_merge_stats;
+}
+
+}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c662838..53a37be 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -41,6 +41,11 @@
 #include <libsnapshot/test_helpers.h>
 #include "utility.h"
 
+// Mock classes are not used. Header included to ensure mocked class definition aligns with the
+// class itself.
+#include <libsnapshot/mock_device_info.h>
+#include <libsnapshot/mock_snapshot.h>
+
 namespace android {
 namespace snapshot {
 
diff --git a/init/Android.bp b/init/Android.bp
index 827a829..edf9099 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -131,6 +131,7 @@
         "libpropertyinfoparser",
         "libsnapshot_init",
         "lib_apex_manifest_proto_lite",
+        "update_metadata-protos",
     ],
     shared_libs: [
         "libbacktrace",
diff --git a/init/Android.mk b/init/Android.mk
index 416b732..da94daf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
     libext2_uuid \
     libprotobuf-cpp-lite \
     libsnapshot_init \
+    update_metadata-protos \
 
 LOCAL_SANITIZE := signed-integer-overflow
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 2f91663..72f0450 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -203,6 +203,7 @@
 }
 
 static Result<void> CallVdc(const std::string& system, const std::string& cmd) {
+    LOG(INFO) << "Calling /system/bin/vdc " << system << " " << cmd;
     const char* vdc_argv[] = {"/system/bin/vdc", system.c_str(), cmd.c_str()};
     int status;
     if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
@@ -456,10 +457,14 @@
 #define ZRAM_RESET    "/sys/block/zram0/reset"
 #define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
 static Result<void> KillZramBackingDevice() {
+    if (access(ZRAM_BACK_DEV, F_OK) != 0 && errno == ENOENT) {
+        LOG(INFO) << "No zram backing device configured";
+        return {};
+    }
     std::string backing_dev;
-    if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return {};
-
-    if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return {};
+    if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) {
+        return ErrnoError() << "Failed to read " << ZRAM_BACK_DEV;
+    }
 
     // cut the last "\n"
     backing_dev.erase(backing_dev.length() - 1);
@@ -478,6 +483,11 @@
                        << " failed";
     }
 
+    if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) {
+        LOG(INFO) << backing_dev << " is not a loop device. Exiting early";
+        return {};
+    }
+
     // clear loopback device
     unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
     if (loop.get() < 0) {
@@ -785,7 +795,7 @@
     }
     auto sigterm_timeout = GetMillisProperty("init.userspace_reboot.sigterm.timeoutmillis", 5s);
     auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
-    LOG(INFO) << "Timeout to terminate services : " << sigterm_timeout.count() << "ms"
+    LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
               << "Timeout to kill services: " << sigkill_timeout.count() << "ms";
     StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
     if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
index cb2ff14..f4d497e 100755
--- a/libcutils/arch-x86/android_memset16.S
+++ b/libcutils/arch-x86/android_memset16.S
@@ -105,14 +105,16 @@
     /* We loaded the jump table and adjuested EDX. Go.  */	\
     jmp		*%ebx
 
-	.section	.gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
 	.globl	__x86.get_pc_thunk.bx
 	.hidden	__x86.get_pc_thunk.bx
 	ALIGN (4)
 	.type	__x86.get_pc_thunk.bx,@function
 __x86.get_pc_thunk.bx:
+	cfi_startproc
 	movl	(%esp), %ebx
 	ret
+	cfi_endproc
 #else
 # define ENTRANCE
 # define RETURN_END	ret
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
index f4326dc..b928f6b 100755
--- a/libcutils/arch-x86/android_memset32.S
+++ b/libcutils/arch-x86/android_memset32.S
@@ -105,14 +105,16 @@
     /* We loaded the jump table and adjuested EDX. Go.  */	\
     jmp		*%ebx
 
-	.section	.gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
 	.globl	__x86.get_pc_thunk.bx
 	.hidden	__x86.get_pc_thunk.bx
 	ALIGN (4)
 	.type	__x86.get_pc_thunk.bx,@function
 __x86.get_pc_thunk.bx:
+	cfi_startproc
 	movl	(%esp), %ebx
 	ret
+	cfi_endproc
 #else
 # define ENTRANCE
 # define RETURN_END	ret
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
index 90d1e76..19edb83 100644
--- a/liblog/include/log/log.h
+++ b/liblog/include/log/log.h
@@ -87,8 +87,6 @@
 /*
  * Event log entry types.
  */
-#ifndef __AndroidEventLogType_defined
-#define __AndroidEventLogType_defined
 typedef enum {
   /* Special markers for android_log_list_element type */
   EVENT_TYPE_LIST_STOP = '\n', /* declare end of list  */
@@ -101,9 +99,6 @@
   EVENT_TYPE_LIST = 3,
   EVENT_TYPE_FLOAT = 4,
 } AndroidEventLogType;
-#endif
-#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
-#define typeof_AndroidEventLogType unsigned char
 
 #ifndef LOG_EVENT_INT
 #define LOG_EVENT_INT(_tag, _value)                                          \
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index c174b85..d15b367 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -330,7 +330,7 @@
   ErrnoRestorer errno_restorer;
 
   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-    return 0;
+    return -EPERM;
   }
 
   __android_log_message log_message = {
@@ -343,7 +343,7 @@
   ErrnoRestorer errno_restorer;
 
   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-    return 0;
+    return -EPERM;
   }
 
   __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
@@ -360,7 +360,7 @@
   ErrnoRestorer errno_restorer;
 
   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-    return 0;
+    return -EPERM;
   }
 
   va_list ap;
@@ -380,7 +380,7 @@
   ErrnoRestorer errno_restorer;
 
   if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-    return 0;
+    return -EPERM;
   }
 
   va_list ap;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 21da12d..bf7d69e 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -57,6 +57,7 @@
         "MapInfo.cpp",
         "Maps.cpp",
         "Memory.cpp",
+        "MemoryMte.cpp",
         "LocalUnwinder.cpp",
         "Regs.cpp",
         "RegsArm.cpp",
@@ -101,6 +102,16 @@
         "liblog",
         "liblzma",
     ],
+
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
+
+    product_variables: {
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
+    },
 }
 
 cc_library {
@@ -213,6 +224,7 @@
         "tests/MemoryRangesTest.cpp",
         "tests/MemoryRemoteTest.cpp",
         "tests/MemoryTest.cpp",
+        "tests/MemoryMteTest.cpp",
         "tests/RegsInfoTest.cpp",
         "tests/RegsIterateTest.cpp",
         "tests/RegsStepIfSignalHandlerTest.cpp",
@@ -268,6 +280,16 @@
         "tests/files/offline/straddle_arm/*",
         "tests/files/offline/straddle_arm64/*",
     ],
+
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
+
+    product_variables: {
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
+    },
 }
 
 cc_test {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index e142b97..b4623fa 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -334,6 +334,16 @@
   return ProcessVmRead(getpid(), addr, dst, size);
 }
 
+#if !defined(ANDROID_EXPERIMENTAL_MTE)
+long MemoryRemote::ReadTag(uint64_t) {
+  return -1;
+}
+
+long MemoryLocal::ReadTag(uint64_t) {
+  return -1;
+}
+#endif
+
 MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
                          uint64_t offset)
     : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
index 769d907..d97640d 100644
--- a/libunwindstack/MemoryCache.h
+++ b/libunwindstack/MemoryCache.h
@@ -33,6 +33,7 @@
   virtual ~MemoryCache() = default;
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
+  long ReadTag(uint64_t addr) override { return impl_->ReadTag(addr); }
 
   void Clear() override { cache_.clear(); }
 
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
index 7e027cf..741f107 100644
--- a/libunwindstack/MemoryLocal.h
+++ b/libunwindstack/MemoryLocal.h
@@ -31,6 +31,7 @@
   bool IsLocal() const override { return true; }
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
+  long ReadTag(uint64_t addr) override;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/MemoryMte.cpp b/libunwindstack/MemoryMte.cpp
new file mode 100644
index 0000000..d1d0ebc
--- /dev/null
+++ b/libunwindstack/MemoryMte.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+
+#include <sys/ptrace.h>
+
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
+
+#include "MemoryLocal.h"
+#include "MemoryRemote.h"
+
+namespace unwindstack {
+
+long MemoryRemote::ReadTag(uint64_t addr) {
+#if defined(__aarch64__)
+  return ptrace(PTRACE_PEEKTAG, pid_, (void*)addr, nullptr);
+#else
+  (void)addr;
+  return -1;
+#endif
+}
+
+long MemoryLocal::ReadTag(uint64_t addr) {
+#if defined(__aarch64__)
+  // Check that the memory is readable first. This is racy with the ldg but there's not much
+  // we can do about it.
+  char data;
+  if (!mte_supported() || !Read(addr, &data, 1)) {
+    return -1;
+  }
+
+  __asm__ __volatile__(".arch_extension mte; ldg %0, [%0]" : "+r"(addr) : : "memory");
+  return (addr >> 56) & 0xf;
+#else
+  (void)addr;
+  return -1;
+#endif
+}
+
+}  // namespace unwindstack
+
+#endif
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
index db367d6..dd09c88 100644
--- a/libunwindstack/MemoryRemote.h
+++ b/libunwindstack/MemoryRemote.h
@@ -32,6 +32,7 @@
   virtual ~MemoryRemote() = default;
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
+  long ReadTag(uint64_t addr) override;
 
   pid_t pid() { return pid_; }
 
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 995230e..3d81878 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -44,6 +44,7 @@
   virtual bool IsLocal() const { return false; }
 
   virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
+  virtual long ReadTag(uint64_t) { return -1; }
 
   bool ReadFully(uint64_t addr, void* dst, size_t size);
 
diff --git a/libunwindstack/tests/MemoryMteTest.cpp b/libunwindstack/tests/MemoryMteTest.cpp
new file mode 100644
index 0000000..3ae322e
--- /dev/null
+++ b/libunwindstack/tests/MemoryMteTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#if defined(ANDROID_EXPERIMENTAL_MTE)
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <gtest/gtest.h>
+
+#include <bionic/mte.h>
+
+#include "MemoryLocal.h"
+#include "MemoryRemote.h"
+#include "TestUtils.h"
+
+namespace unwindstack {
+
+static uintptr_t CreateTagMapping() {
+  uintptr_t mapping =
+      reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE,
+                                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  if (reinterpret_cast<void*>(mapping) == MAP_FAILED) {
+    return 0;
+  }
+#if defined(__aarch64__)
+  __asm__ __volatile__(".arch_extension mte; stg %0, [%0]"
+                       :
+                       : "r"(mapping + (1ULL << 56))
+                       : "memory");
+#endif
+  return mapping;
+}
+
+TEST(MemoryMteTest, remote_read_tag) {
+#if !defined(__aarch64__)
+  GTEST_SKIP() << "Requires aarch64";
+#else
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+#endif
+
+  uintptr_t mapping = CreateTagMapping();
+  ASSERT_NE(0U, mapping);
+
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    while (true)
+      ;
+    exit(1);
+  }
+  ASSERT_LT(0, pid);
+  TestScopedPidReaper reap(pid);
+
+  ASSERT_TRUE(TestAttach(pid));
+
+  MemoryRemote remote(pid);
+
+  EXPECT_EQ(1, remote.ReadTag(mapping));
+  EXPECT_EQ(0, remote.ReadTag(mapping + 16));
+
+  ASSERT_TRUE(TestDetach(pid));
+}
+
+TEST(MemoryMteTest, local_read_tag) {
+#if !defined(__aarch64__)
+  GTEST_SKIP() << "Requires aarch64";
+#else
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+#endif
+
+  uintptr_t mapping = CreateTagMapping();
+  ASSERT_NE(0U, mapping);
+
+  MemoryLocal local;
+
+  EXPECT_EQ(1, local.ReadTag(mapping));
+  EXPECT_EQ(0, local.ReadTag(mapping + 16));
+}
+
+}  // namespace unwindstack
+
+#endif
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index c90dedc..385078d 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -26,8 +26,10 @@
 
 #include <vector>
 
-#include <android-base/test_utils.h>
 #include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <bionic/mte.h>
+#include <bionic/mte_kernel.h>
 #include <gtest/gtest.h>
 
 #include "MemoryRemote.h"
@@ -37,24 +39,7 @@
 
 namespace unwindstack {
 
-class MemoryRemoteTest : public ::testing::Test {
- protected:
-  static bool Attach(pid_t pid) {
-    if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
-      return false;
-    }
-
-    return TestQuiescePid(pid);
-  }
-
-  static bool Detach(pid_t pid) {
-    return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
-  }
-
-  static constexpr size_t NS_PER_SEC = 1000000000ULL;
-};
-
-TEST_F(MemoryRemoteTest, read) {
+TEST(MemoryRemoteTest, read) {
   std::vector<uint8_t> src(1024);
   memset(src.data(), 0x4c, 1024);
 
@@ -66,7 +51,7 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -76,10 +61,10 @@
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_large) {
+TEST(MemoryRemoteTest, read_large) {
   static constexpr size_t kTotalPages = 245;
   std::vector<uint8_t> src(kTotalPages * getpagesize());
   for (size_t i = 0; i < kTotalPages; i++) {
@@ -95,7 +80,7 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -105,10 +90,10 @@
     ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_partial) {
+TEST(MemoryRemoteTest, read_partial) {
   char* mapping = static_cast<char*>(
       mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
   ASSERT_NE(MAP_FAILED, mapping);
@@ -128,7 +113,7 @@
   // Unmap from our process.
   ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -149,10 +134,10 @@
     ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
   }
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_fail) {
+TEST(MemoryRemoteTest, read_fail) {
   int pagesize = getpagesize();
   void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0);
   memset(src, 0x4c, pagesize * 2);
@@ -169,7 +154,7 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -188,10 +173,10 @@
 
   ASSERT_EQ(0, munmap(src, pagesize));
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_overflow) {
+TEST(MemoryRemoteTest, read_overflow) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     while (true)
@@ -201,7 +186,7 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -209,10 +194,10 @@
   std::vector<uint8_t> dst(200);
   ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_illegal) {
+TEST(MemoryRemoteTest, read_illegal) {
   pid_t pid;
   if ((pid = fork()) == 0) {
     while (true);
@@ -221,7 +206,7 @@
   ASSERT_LT(0, pid);
   TestScopedPidReaper reap(pid);
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
 
@@ -229,10 +214,10 @@
   ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
   ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
 
-  ASSERT_TRUE(Detach(pid));
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_mprotect_hole) {
+TEST(MemoryRemoteTest, read_mprotect_hole) {
   size_t page_size = getpagesize();
   void* mapping =
       mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -250,7 +235,7 @@
 
   ASSERT_EQ(0, munmap(mapping, 3 * page_size));
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -263,9 +248,11 @@
   for (size_t i = read_size; i < dst.size(); ++i) {
     ASSERT_EQ(0xCC, dst[i]);
   }
+
+  ASSERT_TRUE(TestDetach(pid));
 }
 
-TEST_F(MemoryRemoteTest, read_munmap_hole) {
+TEST(MemoryRemoteTest, read_munmap_hole) {
   size_t page_size = getpagesize();
   void* mapping =
       mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -285,7 +272,7 @@
   ASSERT_EQ(0, munmap(mapping, page_size));
   ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   MemoryRemote remote(pid);
   std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
@@ -297,11 +284,13 @@
   for (size_t i = read_size; i < dst.size(); ++i) {
     ASSERT_EQ(0xCC, dst[i]);
   }
+
+  ASSERT_TRUE(TestDetach(pid));
 }
 
 // Verify that the memory remote object chooses a memory read function
 // properly. Either process_vm_readv or ptrace.
-TEST_F(MemoryRemoteTest, read_choose_correctly) {
+TEST(MemoryRemoteTest, read_choose_correctly) {
   size_t page_size = getpagesize();
   void* mapping =
       mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
@@ -320,7 +309,7 @@
 
   ASSERT_EQ(0, munmap(mapping, 2 * page_size));
 
-  ASSERT_TRUE(Attach(pid));
+  ASSERT_TRUE(TestAttach(pid));
 
   // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
   // Read from the PROT_NONE area first to force the choice of ptrace.
@@ -348,6 +337,8 @@
   bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
   ASSERT_EQ(sizeof(value), bytes);
   ASSERT_EQ(0xfcfcfcfcU, value);
+
+  ASSERT_TRUE(TestDetach(pid));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index a4d7b9b..0685006 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -21,6 +21,7 @@
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 namespace unwindstack {
 
@@ -50,6 +51,18 @@
   return ready;
 }
 
+inline bool TestAttach(pid_t pid) {
+  if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+    return false;
+  }
+
+  return TestQuiescePid(pid);
+}
+
+inline bool TestDetach(pid_t pid) {
+  return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
+}
+
 void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
 
 }  // namespace unwindstack
diff --git a/libziparchive/ziptool.cpp b/libziparchive/ziptool.cpp
index 17d4833..a261535 100644
--- a/libziparchive/ziptool.cpp
+++ b/libziparchive/ziptool.cpp
@@ -263,12 +263,12 @@
   snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
            t.tm_mday, t.tm_hour, t.tm_min);
   if (flag_v) {
-    printf("%8" PRIu64 " %s  %8" PRIu64 " %3.0f%% %s %08x  %s\n", entry.uncompressed_length,
+    printf("%8" PRIu64 "  %s %8" PRIu64 " %3.0f%% %s %08x  %s\n", entry.uncompressed_length,
            (entry.method == kCompressStored) ? "Stored" : "Defl:N", entry.compressed_length,
            CompressionRatio(entry.uncompressed_length, entry.compressed_length), time, entry.crc32,
            name.c_str());
   } else {
-    printf("%9" PRIu64 " %s   %s\n", entry.uncompressed_length, time, name.c_str());
+    printf("%9" PRIu64 "  %s   %s\n", entry.uncompressed_length, time, name.c_str());
   }
 }