Merge "Expose libstatspull as a stable C API"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 73dcde1..2bcd0a6 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -227,16 +227,20 @@
         return 1;
     }
 
-    copy_to_file(local_fd.get(), remote_fd.get());
+    if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+        fprintf(stderr, "adb: failed to install: copy_to_file: %s: %s", file, strerror(errno));
+        return 1;
+    }
 
     char buf[BUFSIZ];
     read_status_line(remote_fd.get(), buf, sizeof(buf));
-    if (!strncmp("Success", buf, 7)) {
-        fputs(buf, stdout);
-        return 0;
+    if (strncmp("Success", buf, 7) != 0) {
+        fprintf(stderr, "adb: failed to install %s: %s", file, buf);
+        return 1;
     }
-    fprintf(stderr, "adb: failed to install %s: %s", file, buf);
-    return 1;
+
+    fputs(buf, stdout);
+    return 0;
 }
 
 static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) {
@@ -455,7 +459,12 @@
             goto finalize_session;
         }
 
-        copy_to_file(local_fd.get(), remote_fd.get());
+        if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+            fprintf(stderr, "adb: failed to write \"%s\": %s\n", file, strerror(errno));
+            success = false;
+            goto finalize_session;
+        }
+
         read_status_line(remote_fd.get(), buf, sizeof(buf));
 
         if (strncmp("Success", buf, 7)) {
@@ -634,7 +643,11 @@
                 goto finalize_multi_package_session;
             }
 
-            copy_to_file(local_fd.get(), remote_fd.get());
+            if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+                fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno));
+                goto finalize_multi_package_session;
+            }
+
             read_status_line(remote_fd.get(), buf, sizeof(buf));
 
             if (strncmp("Success", buf, 7)) {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index a6d7e31..c302965 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -352,7 +352,8 @@
 #endif
 }
 
-void copy_to_file(int inFd, int outFd) {
+bool copy_to_file(int inFd, int outFd) {
+    bool result = true;
     std::vector<char> buf(64 * 1024);
     int len;
     long total = 0;
@@ -375,6 +376,7 @@
         }
         if (len < 0) {
             D("copy_to_file(): read failed: %s", strerror(errno));
+            result = false;
             break;
         }
         if (outFd == STDOUT_FILENO) {
@@ -388,7 +390,8 @@
 
     stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
 
-    D("copy_to_file() finished after %lu bytes", total);
+    D("copy_to_file() finished with %s after %lu bytes", result ? "success" : "failure", total);
+    return result;
 }
 
 static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
index ab77b29..b9dee56 100644
--- a/adb/client/commandline.h
+++ b/adb/client/commandline.h
@@ -100,7 +100,7 @@
 
 int adb_commandline(int argc, const char** argv);
 
-void copy_to_file(int inFd, int outFd);
+bool copy_to_file(int inFd, int outFd);
 
 // Connects to the device "shell" service with |command| and prints the
 // resulting output.
diff --git a/base/expected_test.cpp b/base/expected_test.cpp
index a74bc1d..6c3d421 100644
--- a/base/expected_test.cpp
+++ b/base/expected_test.cpp
@@ -499,24 +499,6 @@
   EXPECT_TRUE(e4 != e3);
 }
 
-TEST(Expected, testCompareWithSameValue) {
-  exp_int e = 10;
-  int value = 10;
-  EXPECT_TRUE(e == value);
-  EXPECT_TRUE(value == e);
-  EXPECT_FALSE(e != value);
-  EXPECT_FALSE(value != e);
-}
-
-TEST(Expected, testCompareWithDifferentValue) {
-  exp_int e = 10;
-  int value = 20;
-  EXPECT_FALSE(e == value);
-  EXPECT_FALSE(value == e);
-  EXPECT_TRUE(e != value);
-  EXPECT_TRUE(value != e);
-}
-
 TEST(Expected, testCompareWithSameError) {
   exp_int e = unexpected(10);
   exp_int::unexpected_type error = 10;
@@ -594,7 +576,7 @@
   EXPECT_EQ(-1, divide(10, 0).error().cause);
 
   EXPECT_TRUE(divide(10, 3));
-  EXPECT_EQ(QR(3, 1), divide(10, 3));
+  EXPECT_EQ(QR(3, 1), *divide(10, 3));
 }
 
 TEST(Expected, testPair) {
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index b3f5adb..44e0b4a 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -366,16 +366,6 @@
   template<class T1, class E1, class T2, class E2>
   friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
 
-  // comparison with T
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator==(const expected<T1, E1>&, const T2&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator==(const T2&, const expected<T1, E1>&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator!=(const expected<T1, E1>&, const T2&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator!=(const T2&, const expected<T1, E1>&);
-
   // Comparison with unexpected<E>
   template<class T1, class E1, class E2>
   friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
@@ -410,24 +400,6 @@
   return !(x == y);
 }
 
-// comparison with T
-template<class T1, class E1, class T2>
-constexpr bool operator==(const expected<T1, E1>& x, const T2& y) {
-  return x.has_value() && (*x == y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator==(const T2& x, const expected<T1, E1>& y) {
-  return y.has_value() && (x == *y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const expected<T1, E1>& x, const T2& y) {
-  return !x.has_value() || (*x != y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const T2& x, const expected<T1, E1>& y) {
-  return !y.has_value() || (x != *y);
-}
-
 // Comparison with unexpected<E>
 template<class T1, class E1, class E2>
 constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 970ca94..2f2919f 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -230,16 +230,16 @@
       if [ -n "`get_property sys.boot.reason`" ]
       then
         vals=`get_property |
-              sed -n 's/[[]sys[.]\(boot_completed\|bootstat.first_boot_completed\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
-        if [ "${vals}" = "`echo boot_completed=1 ; echo bootstat.first_boot_completed=1`" ]
-        then
-          sleep 1
-          break
-        fi
-        if [ "${vals}" = "`echo bootstat.first_boot_completed=1 ; echo boot_completed=1`" ]
-        then
-          sleep 1
-          break
+              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\|bootstat[.]first_boot_completed\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+        if [ X"${vals}" != X"${vals##*boot_completed=1}" ]; then
+          if [ X"${vals}" != X"${vals##*logbootcomple=1}" ]; then
+            sleep 1
+            break
+          fi
+          if [ X"${vals}" != X"${vals##*bootstat.first_boot_completed=1}" ]; then
+            sleep 1
+            break
+          fi
         fi
       fi
     fi
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7a88aa3..f5daf91 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -96,6 +96,10 @@
     export_header_lib_headers: [
         "libfiemap_headers",
     ],
+    required: [
+        "e2freefrag",
+        "e2fsdroid",
+    ],
 }
 
 // Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index a947b4e..de38ff6 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "libdm_test"
+    },
+    {
+      "name": "liblp_test"
     }
   ]
 }
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 0195716..6717922 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -252,7 +252,7 @@
     // For dm-linear devices sitting on top of /data, we cannot risk deleting
     // the file. The underlying blocks could be reallocated by the filesystem.
     if (IsImageMapped(name)) {
-        LOG(ERROR) << "Backing image " << name << " is currently mapped to a block device";
+        LOG(ERROR) << "Cannot delete backing image " << name << " because mapped to a block device";
         return false;
     }
 
diff --git a/fs_mgr/libfiemap/metadata.cpp b/fs_mgr/libfiemap/metadata.cpp
index ea1f508..b0dfb5c 100644
--- a/fs_mgr/libfiemap/metadata.cpp
+++ b/fs_mgr/libfiemap/metadata.cpp
@@ -39,7 +39,13 @@
 
 bool MetadataExists(const std::string& metadata_dir) {
     auto metadata_file = GetMetadataFile(metadata_dir);
-    return access(metadata_file.c_str(), F_OK) == 0;
+    if (access(metadata_file.c_str(), F_OK)) {
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "Access " << metadata_file << " failed:";
+        }
+        return false;
+    }
+    return true;
 }
 
 std::unique_ptr<LpMetadata> OpenMetadata(const std::string& metadata_dir) {
@@ -61,7 +67,7 @@
     std::unique_ptr<MetadataBuilder> builder;
     if (access(metadata_file.c_str(), R_OK)) {
         if (errno != ENOENT) {
-            PLOG(ERROR) << "access " << metadata_file << " failed:";
+            PLOG(ERROR) << "Access " << metadata_file << " failed:";
             return nullptr;
         }
 
@@ -112,7 +118,12 @@
 
 bool RemoveAllMetadata(const std::string& dir) {
     auto metadata_file = GetMetadataFile(dir);
-    return android::base::RemoveFileIfExists(metadata_file);
+    std::string err;
+    if (!android::base::RemoveFileIfExists(metadata_file, &err)) {
+        LOG(ERROR) << "Could not remove metadata file: " << err;
+        return false;
+    }
+    return true;
 }
 
 bool FillPartitionExtents(MetadataBuilder* builder, Partition* partition, SplitFiemap* file,
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 8770a6b..50de42c 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -266,8 +266,10 @@
     return avb_handle;
 }
 
-AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
-    if (fstab_entry.avb_keys.empty()) {
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+                                            const std::vector<std::string>& preload_avb_key_blobs) {
+    // At least one of the following should be provided for public key matching.
+    if (preload_avb_key_blobs.empty() && fstab_entry.avb_keys.empty()) {
         LERROR << "avb_keys=/path/to/key(s) is missing for " << fstab_entry.mount_point;
         return nullptr;
     }
@@ -309,18 +311,36 @@
             return nullptr;
     }
 
-    // fstab_entry.avb_keys might be either a directory containing multiple keys,
-    // or a string indicating multiple keys separated by ':'.
-    std::vector<std::string> allowed_avb_keys;
-    auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
-    if (list_avb_keys_in_dir) {
-        std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
-        allowed_avb_keys = *list_avb_keys_in_dir;
-    } else {
-        allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+    bool public_key_match = false;
+    // Performs key matching for preload_avb_key_blobs first, if it is present.
+    if (!public_key_data.empty() && !preload_avb_key_blobs.empty()) {
+        if (std::find(preload_avb_key_blobs.begin(), preload_avb_key_blobs.end(),
+                      public_key_data) != preload_avb_key_blobs.end()) {
+            public_key_match = true;
+        }
+    }
+    // Performs key matching for fstab_entry.avb_keys if necessary.
+    // Note that it is intentional to match both preload_avb_key_blobs and fstab_entry.avb_keys.
+    // Some keys might only be availble before init chroots into /system, e.g., /avb/key1
+    // in the first-stage ramdisk, while other keys might only be available after the chroot,
+    // e.g., /system/etc/avb/key2.
+    if (!public_key_data.empty() && !public_key_match) {
+        // fstab_entry.avb_keys might be either a directory containing multiple keys,
+        // or a string indicating multiple keys separated by ':'.
+        std::vector<std::string> allowed_avb_keys;
+        auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
+        if (list_avb_keys_in_dir) {
+            std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
+            allowed_avb_keys = *list_avb_keys_in_dir;
+        } else {
+            allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+        }
+        if (ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+            public_key_match = true;
+        }
     }
 
-    if (!ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+    if (!public_key_match) {
         avb_handle->status_ = AvbHandleStatus::kVerificationError;
         LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point;
         if (!allow_verification_error) {
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 521f2d5..4702e68 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -85,8 +85,15 @@
     // TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
     static AvbUniquePtr Open();                 // loads inline vbmeta, via libavb.
     static AvbUniquePtr LoadAndVerifyVbmeta();  // loads inline vbmeta.
-    static AvbUniquePtr LoadAndVerifyVbmeta(
-            const FstabEntry& fstab_entry);     // loads offline vbmeta.
+
+    // The caller can specify optional preload_avb_key_blobs for public key matching.
+    // This is mostly for init to preload AVB keys before chroot into /system.
+    // Both preload_avb_key_blobs and fstab_entry.avb_keys (file paths) will be used
+    // for public key matching.
+    static AvbUniquePtr LoadAndVerifyVbmeta(  // loads offline vbmeta.
+            const FstabEntry& fstab_entry,
+            const std::vector<std::string>& preload_avb_key_blobs = {});
+
     static AvbUniquePtr LoadAndVerifyVbmeta(    // loads offline vbmeta.
             const std::string& partition_name, const std::string& ab_suffix,
             const std::string& ab_other_suffix, const std::string& expected_public_key,
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ad48b82..c58101a 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -95,6 +95,16 @@
     static_libs: [
         "libfs_mgr_binder"
     ],
+
+    shared_libs: [
+        // TODO(b/148818798): remove when parent bug is fixed
+        "libutilscallstack",
+    ],
+    cflags: [
+        "-g",
+        "-O0",
+        "-DLIBSNAPSHOT_USE_CALLSTACK",
+    ],
 }
 
 cc_library_static {
@@ -171,6 +181,9 @@
         "libsparse",
         "libutils",
         "libz",
+
+        // TODO(b/148818798): remove when parent bug is fixed
+        "libutilscallstack",
     ],
     static_libs: [
         "libgmock",
@@ -207,6 +220,9 @@
         "liblp",
         "libprotobuf-cpp-lite",
         "libutils",
+
+        // TODO(b/148818798): remove when parent bug is fixed.
+        "libutilscallstack",
     ],
     init_rc: [
         "snapshotctl.rc",
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a6f07fc..63a9302 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,6 +21,7 @@
 #include <sys/unistd.h>
 
 #include <optional>
+#include <sstream>
 #include <thread>
 #include <unordered_set>
 
@@ -37,6 +38,10 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+#include <utils/CallStack.h>
+#endif
+
 #include <android/snapshot/snapshot.pb.h>
 #include "device_info.h"
 #include "partition_cow_creator.h"
@@ -197,6 +202,22 @@
 }
 
 bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
+    LOG(INFO) << "Removing all update state.";
+
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+    LOG(WARNING) << "Logging stack; see b/148818798.";
+    // Do not use CallStack's log functions because snapshotctl relies on
+    // android-base/logging to save log to files.
+    // TODO(b/148818798): remove this before we ship.
+    CallStack callstack;
+    callstack.update();
+    auto callstack_str = callstack.toString();
+    LOG(WARNING) << callstack_str.c_str();
+    std::stringstream path;
+    path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
+    android::base::WriteStringToFile(callstack_str.c_str(), path.str());
+#endif
+
     if (!RemoveAllSnapshots(lock)) {
         LOG(ERROR) << "Could not remove all snapshots";
         return false;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c49c49e..c5ad44c 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -335,6 +335,7 @@
         return AssertionSuccess();
     }
 
+    static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
     bool is_virtual_ab_;
     DeviceMapper& dm_;
     std::unique_ptr<SnapshotManager::LockedFile> lock_;
@@ -511,7 +512,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     ASSERT_TRUE(AcquireLock());
 
@@ -540,7 +541,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     ASSERT_TRUE(AcquireLock());
 
@@ -567,7 +568,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     ASSERT_TRUE(init->InitiateMerge());
 
     // Now, reflash super. Note that we haven't called ProcessUpdateState, so the
@@ -577,7 +578,7 @@
     FormatFakeSuper();
     ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Because the status is Merging, we must call ProcessUpdateState, which should
     // detect a cancelled update.
@@ -1012,7 +1013,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1140,7 +1141,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1152,7 +1153,7 @@
     init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_a"));
     ASSERT_NE(init, nullptr);
     ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Assert that the source partitions aren't affected.
     for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -1189,7 +1190,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     init = nullptr;
 
     // Initiate the merge and wait for it to be completed.
@@ -1325,7 +1326,7 @@
     // won't be set.
     auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Keep an open handle to the cow device. This should cause the merge to
     // be incomplete.
@@ -1341,7 +1342,7 @@
     ASSERT_TRUE(UnmapAll());
 
     // init does first stage mount again.
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // sys_b should be mapped as a dm-linear device directly.
     ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
@@ -1427,7 +1428,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     init = nullptr;
 
     // Initiate the merge and then immediately stop it to simulate a reboot.
@@ -1532,7 +1533,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partition have the same content. Hashtree and FEC extents
     // should be accounted for.
@@ -1584,7 +1585,7 @@
     {
         auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
         ASSERT_NE(nullptr, init);
-        ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+        ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     }
 
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
@@ -1630,7 +1631,7 @@
   public:
     AssertionResult InitiateMerge(const std::string& slot_suffix) {
         auto sm = SnapshotManager::New(new TestDeviceInfo(fake_super, slot_suffix));
-        if (!sm->CreateLogicalAndSnapshotPartitions("super")) {
+        if (!sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)) {
             return AssertionFailure() << "Cannot CreateLogicalAndSnapshotPartitions";
         }
         if (!sm->InitiateMerge()) {
@@ -1712,7 +1713,7 @@
     if (flashed_slot && after_merge) {
         ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
     }
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys", "vnd"}) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 1bc0357..9f23c45 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -19,9 +19,15 @@
 #include <chrono>
 #include <iostream>
 #include <map>
+#include <sstream>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <libsnapshot/snapshot.h>
+#include "utility.h"
+
+#include "utility.h"
 
 using namespace std::string_literals;
 
@@ -31,9 +37,11 @@
                  "Actions:\n"
                  "  dump\n"
                  "    Print snapshot states.\n"
-                 "  merge [--logcat]\n"
+                 "  merge [--logcat] [--log-to-file]\n"
                  "    Initialize merge and wait for it to be completed.\n"
-                 "    If --logcat is specified, log to logcat. Otherwise, log to stdout.\n";
+                 "    If --logcat is specified, log to logcat.\n"
+                 "    If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
+                 "    If both specified, log to both. If none specified, log to stdout.\n";
     return EX_USAGE;
 }
 
@@ -45,20 +53,62 @@
     return SnapshotManager::New()->Dump(std::cout);
 }
 
+class FileLogger {
+  public:
+    FileLogger() {
+        static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
+        std::stringstream ss;
+        ss << kLogFilePath << "snapshotctl." << Now() << ".log";
+        fd_.reset(TEMP_FAILURE_RETRY(
+                open(ss.str().c_str(),
+                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)));
+    }
+    // Copy-contuctor needed to be converted to std::function.
+    FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
+    void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
+                    const char* /*file*/, unsigned int /*line*/, const char* message) {
+        if (fd_ == -1) return;
+        std::stringstream ss;
+        ss << Now() << ":" << message << "\n";
+        (void)android::base::WriteStringToFd(ss.str(), fd_);
+    }
+
+  private:
+    android::base::unique_fd fd_;
+};
+
+class MergeCmdLogger {
+  public:
+    MergeCmdLogger(int argc, char** argv) {
+        for (int i = 0; i < argc; ++i) {
+            if (argv[i] == "--logcat"s) {
+                loggers_.push_back(android::base::LogdLogger());
+            }
+            if (argv[i] == "--log-to-file"s) {
+                loggers_.push_back(std::move(FileLogger()));
+            }
+        }
+        if (loggers_.empty()) {
+            loggers_.push_back(&android::base::StdioLogger);
+        }
+    }
+    void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+                    const char* file, unsigned int line, const char* message) {
+        for (auto&& logger : loggers_) {
+            logger(id, severity, tag, file, line, message);
+        }
+    }
+
+  private:
+    std::vector<android::base::LogFunction> loggers_;
+};
+
 bool MergeCmdHandler(int argc, char** argv) {
     auto begin = std::chrono::steady_clock::now();
 
-    bool log_to_logcat = false;
-    for (int i = 2; i < argc; ++i) {
-        if (argv[i] == "--logcat"s) {
-            log_to_logcat = true;
-        }
-    }
-    if (log_to_logcat) {
-        android::base::InitLogging(argv);
-    } else {
-        android::base::InitLogging(argv, &android::base::StdioLogger);
-    }
+    // 'snapshotctl merge' is stripped away from arguments to
+    // Logger.
+    android::base::InitLogging(argv, MergeCmdLogger(argc - 2, argv + 2));
 
     auto state = SnapshotManager::New()->InitiateMergeAndWait();
 
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
index 3ab0645..5dbe352 100644
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -1,2 +1,2 @@
 on property:sys.boot_completed=1
-    exec_background - root root -- /system/bin/snapshotctl merge --logcat
+    exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 3a64448..3318b33 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -15,6 +15,10 @@
 #include "utility.h"
 
 #include <errno.h>
+#include <time.h>
+
+#include <iomanip>
+#include <sstream>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -155,5 +159,12 @@
     return true;
 }
 
+std::ostream& operator<<(std::ostream& os, const Now&) {
+    struct tm now;
+    time_t t = time(nullptr);
+    localtime_r(&t, &now);
+    return os << std::put_time(&now, "%Y%m%d-%H%M%S");
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index ad46090..90ad0fe 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -15,6 +15,7 @@
 #pragma once
 
 #include <functional>
+#include <iostream>
 #include <string>
 
 #include <android-base/macros.h>
@@ -120,5 +121,9 @@
 // is an open fd to |path|, because that fd has an old view of the file.
 bool WriteStringToFileAtomic(const std::string& content, const std::string& path);
 
+// Writes current time to a given stream.
+struct Now {};
+std::ostream& operator<<(std::ostream& os, const Now&);
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c66f307..e364436 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -474,20 +474,9 @@
       if [ 0 != ${counter} ]; then
         adb_wait
       fi
-      if [ -n "`get_property sys.boot.reason`" ]
-      then
-        vals=`get_property |
-              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
-        if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
-        then
-          sleep 1
-          break
-        fi
-        if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
-        then
-          sleep 1
-          break
-        fi
+      if [ "1" = "`get_property sys.boot_completed`" ]; then
+        sleep 1
+        break
       fi
     fi
     counter=`expr ${counter} + 1`
@@ -858,7 +847,7 @@
 USB_SERIAL=
 [ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
                                           grep usb |
-                                          xargs grep -l ${ANDROID_SERIAL}`
+                                          xargs -r grep -l ${ANDROID_SERIAL}`
 USB_ADDRESS=
 if [ -n "${USB_SERIAL}" ]; then
   USB_ADDRESS=${USB_SERIAL%/serial}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d8c4843..21663e6 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <map>
 #include <memory>
 #include <set>
 #include <string>
@@ -29,6 +30,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr.h>
@@ -45,7 +47,9 @@
 #include "uevent_listener.h"
 #include "util.h"
 
+using android::base::ReadFileToString;
 using android::base::Split;
+using android::base::StringPrintf;
 using android::base::Timer;
 using android::fiemap::IImageManager;
 using android::fs_mgr::AvbHandle;
@@ -95,6 +99,7 @@
     void GetDmLinearMetadataDevice(std::set<std::string>* devices);
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
     void UseDsuIfPresent();
+    void PreloadAvbKeys();
 
     ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
 
@@ -110,6 +115,9 @@
     std::string super_partition_name_;
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
+    // Reads all AVB keys before chroot into /system, as they might be used
+    // later when mounting other partitions, e.g., /vendor and /product.
+    std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
 };
 
 class FirstStageMountVBootV1 : public FirstStageMount {
@@ -508,11 +516,57 @@
     return mounted;
 }
 
+void FirstStageMount::PreloadAvbKeys() {
+    for (const auto& entry : fstab_) {
+        // No need to cache the key content if it's empty, or is already cached.
+        if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
+            continue;
+        }
+
+        // Determines all key paths first.
+        std::vector<std::string> key_paths;
+        if (is_dir(entry.avb_keys.c_str())) {  // fstab_keys might be a dir, e.g., /avb.
+            const char* avb_key_dir = entry.avb_keys.c_str();
+            std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
+            if (!dir) {
+                LOG(ERROR) << "Failed to opendir: " << dir;
+                continue;
+            }
+            // Gets all key pathes under the dir.
+            struct dirent* de;
+            while ((de = readdir(dir.get()))) {
+                if (de->d_type != DT_REG) continue;
+                std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
+                key_paths.emplace_back(std::move(full_path));
+            }
+            std::sort(key_paths.begin(), key_paths.end());
+        } else {
+            // avb_keys are key paths separated by ":", if it's not a dir.
+            key_paths = Split(entry.avb_keys, ":");
+        }
+
+        // Reads the key content then cache it.
+        std::vector<std::string> key_blobs;
+        for (const auto& path : key_paths) {
+            std::string key_value;
+            if (!ReadFileToString(path, &key_value)) {
+                continue;
+            }
+            key_blobs.emplace_back(std::move(key_value));
+        }
+
+        // Maps entry.avb_keys to actual key blobs.
+        preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
+    }
+}
+
 // If system is in the fstab then we're not a system-as-root device, and in
 // this case, we mount system first then pivot to it.  From that point on,
 // we are effectively identical to a system-as-root device.
 bool FirstStageMount::TrySwitchSystemAsRoot() {
     UseDsuIfPresent();
+    // Preloading all AVB keys from the ramdisk before switching root to /system.
+    PreloadAvbKeys();
 
     auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
         return entry.mount_point == "/system";
@@ -776,7 +830,8 @@
                        << fstab_entry->mount_point;
             return true;  // Returns true to mount the partition directly.
         } else {
-            auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
+            auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
+                    *fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
             if (!avb_standalone_handle) {
                 LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
                 // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 1d431e3..3f81792 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -208,7 +208,7 @@
 
         // If the property is not set, it defaults to none, in which case there are no keycodes
         // for this service.
-        if (expanded == "none") {
+        if (*expanded == "none") {
             return {};
         }
 
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index d76a5e7..f36b214 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -92,5 +92,5 @@
         "liblog",
         "libutils",
     ],
-    test_suites: ["device_tests"],
+    test_suites: ["device-tests"],
 }
diff --git a/libstats/socket/TEST_MAPPING b/libstats/socket/TEST_MAPPING
new file mode 100644
index 0000000..0224998
--- /dev/null
+++ b/libstats/socket/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit" : [
+    {
+      "name" : "libstatssocket_test"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 731aba3..5fbad75 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -613,6 +613,7 @@
     mkdir /data/misc/installd 0700 root root
     mkdir /data/misc/apexdata 0711 root root
     mkdir /data/misc/apexrollback 0700 root root
+    mkdir /data/misc/snapshotctl_log 0770 root root
 
     mkdir /data/preloads 0775 system system encryption=None
 
@@ -693,10 +694,6 @@
     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
@@ -734,6 +731,11 @@
     wait_for_prop apexd.status ready
     perform_apex_config
 
+    # Special-case /data/media/obb per b/64566063
+    mkdir /data/media 0770 media_rw media_rw encryption=None
+    exec - media_rw media_rw -- /system/bin/chattr +F /data/media
+    mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
+
     exec_start derive_sdk
 
     init_user0