Merge "Make second stage init visible to microdroid"
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 4f60005..007a20f 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -40,6 +40,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/macros.h>
 #include <bionic/reserved_signals.h>
 #include <cutils/sockets.h>
 #include <log/log.h>
@@ -299,7 +300,9 @@
       *siginfo = crash_info->data.s.siginfo;
       if (signal_has_si_addr(siginfo)) {
         process_info->has_fault_address = true;
-        process_info->fault_address = reinterpret_cast<uintptr_t>(siginfo->si_addr);
+        process_info->maybe_tagged_fault_address = reinterpret_cast<uintptr_t>(siginfo->si_addr);
+        process_info->untagged_fault_address =
+            untag_address(reinterpret_cast<uintptr_t>(siginfo->si_addr));
       }
       regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
                                                         &crash_info->data.s.ucontext));
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index f271365..9750fc4 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -72,8 +72,8 @@
 
   // Get the external crash address from the thread info.
   crash_address_ = 0u;
-  if (signal_has_si_addr(thread_info.siginfo)) {
-    crash_address_ = reinterpret_cast<uintptr_t>(thread_info.siginfo->si_addr);
+  if (process_info.has_fault_address) {
+    crash_address_ = process_info.untagged_fault_address;
   }
 
   // Ensure the error belongs to GWP-ASan.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 30e75e1..86522ee 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -46,5 +46,6 @@
   uintptr_t scudo_region_info = 0;
 
   bool has_fault_address = false;
-  uintptr_t fault_address = 0;
+  uintptr_t untagged_fault_address = 0;
+  uintptr_t maybe_tagged_fault_address = 0;
 };
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
index f8bfe07..141c3bd 100644
--- a/debuggerd/libdebuggerd/scudo.cpp
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -44,7 +44,7 @@
   auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
                                        __scudo_get_region_info_size());
 
-  untagged_fault_addr_ = untag_address(process_info.fault_address);
+  untagged_fault_addr_ = process_info.untagged_fault_address;
   uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
 
   uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
@@ -67,7 +67,7 @@
     memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
   }
 
-  __scudo_get_error_info(&error_info_, process_info.fault_address, stack_depot.get(),
+  __scudo_get_error_info(&error_info_, process_info.maybe_tagged_fault_address, stack_depot.get(),
                          region_info.get(), memory.get(), memory_tags.get(), memory_begin,
                          memory_end - memory_begin);
 }
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d88c5a9..4bd7192 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -151,7 +151,9 @@
                              const ProcessInfo& process_info, unwindstack::Memory* process_memory) {
   char addr_desc[64];  // ", fault addr 0x1234"
   if (process_info.has_fault_address) {
-    size_t addr = process_info.fault_address;
+    // SIGILL faults will never have tagged addresses, so okay to
+    // indiscriminately use the tagged address here.
+    size_t addr = process_info.maybe_tagged_fault_address;
     if (thread_info.siginfo->si_signo == SIGILL) {
       uint32_t instruction = {};
       process_memory->Read(addr, &instruction, sizeof(instruction));
@@ -433,9 +435,8 @@
                          thread_info.registers.get());
     if (maps != nullptr) {
       uint64_t addr = 0;
-      siginfo_t* si = thread_info.siginfo;
-      if (signal_has_si_addr(si)) {
-        addr = reinterpret_cast<uint64_t>(si->si_addr);
+      if (process_info.has_fault_address) {
+        addr = process_info.untagged_fault_address;
       }
       dump_all_maps(log, unwinder, addr);
     }
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index 8fb9697..2f1ca70 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -91,12 +91,19 @@
     name: "libfs_avb_test",
     defaults: ["libfs_avb_host_test_defaults"],
     test_suites: ["general-tests"],
+    test_options: {
+        unit_test: true,
+    },
     static_libs: [
         "libfs_avb_test_util",
     ],
     shared_libs: [
         "libcrypto",
     ],
+    data: [
+        ":avbtool",
+        ":fec",
+    ],
     srcs: [
         "tests/basic_test.cpp",
         "tests/fs_avb_test.cpp",
@@ -108,9 +115,17 @@
     name: "libfs_avb_internal_test",
     defaults: ["libfs_avb_host_test_defaults"],
     test_suites: ["general-tests"],
+    test_options: {
+        unit_test: true,
+    },
     static_libs: [
         "libfs_avb_test_util",
     ],
+    compile_multilib: "first",
+    data: [
+        ":avbtool",
+        ":fec",
+    ],
     srcs: [
         "avb_util.cpp",
         "util.cpp",
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
index 784eb9c..1827566 100644
--- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -216,9 +216,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     1088 bytes\n"
             "Auxiliary Block:          2304 bytes\n"
+            "Public key (sha1):        5227b569de003adc7f8ec3fc03e05dfbd969abad\n"
             "Algorithm:                SHA512_RSA8192\n"
             "Rollback Index:           20\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hashtree descriptor:\n"
@@ -346,9 +348,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     576 bytes\n"
             "Auxiliary Block:          1216 bytes\n"
+            "Public key (sha1):        2597c218aae470a130f61162feaae70afd97f011\n"
             "Algorithm:                SHA256_RSA4096\n"
             "Rollback Index:           10\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hash descriptor:\n"
@@ -639,9 +643,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     1088 bytes\n"
             "Auxiliary Block:          3840 bytes\n"
+            "Public key (sha1):        5227b569de003adc7f8ec3fc03e05dfbd969abad\n"
             "Algorithm:                SHA256_RSA8192\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Chain Partition descriptor:\n"
@@ -854,9 +860,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     1088 bytes\n"
             "Auxiliary Block:          3840 bytes\n"
+            "Public key (sha1):        5227b569de003adc7f8ec3fc03e05dfbd969abad\n"
             "Algorithm:                SHA256_RSA8192\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Chain Partition descriptor:\n"
@@ -886,9 +894,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     576 bytes\n"
             "Auxiliary Block:          2176 bytes\n"
+            "Public key (sha1):        2597c218aae470a130f61162feaae70afd97f011\n"
             "Algorithm:                SHA256_RSA4096\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Chain Partition descriptor:\n"
@@ -936,9 +946,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     320 bytes\n"
             "Auxiliary Block:          960 bytes\n"
+            "Public key (sha1):        cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
             "Algorithm:                SHA256_RSA2048\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hash descriptor:\n"
diff --git a/fs_mgr/libfs_avb/tests/basic_test.cpp b/fs_mgr/libfs_avb/tests/basic_test.cpp
index 5a1cd0d..1c47c07 100644
--- a/fs_mgr/libfs_avb/tests/basic_test.cpp
+++ b/fs_mgr/libfs_avb/tests/basic_test.cpp
@@ -59,9 +59,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     320 bytes\n"
             "Auxiliary Block:          576 bytes\n"
+            "Public key (sha1):        cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
             "Algorithm:                SHA256_RSA2048\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    (none)\n",
@@ -89,9 +91,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     576 bytes\n"
             "Auxiliary Block:          1216 bytes\n"
+            "Public key (sha1):        2597c218aae470a130f61162feaae70afd97f011\n"
             "Algorithm:                SHA256_RSA4096\n"
             "Rollback Index:           10\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hash descriptor:\n"
@@ -126,9 +130,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     1088 bytes\n"
             "Auxiliary Block:          2304 bytes\n"
+            "Public key (sha1):        5227b569de003adc7f8ec3fc03e05dfbd969abad\n"
             "Algorithm:                SHA512_RSA8192\n"
             "Rollback Index:           20\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hashtree descriptor:\n"
@@ -180,9 +186,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     320 bytes\n"
             "Auxiliary Block:          960 bytes\n"
+            "Public key (sha1):        cdbb77177f731920bbe0a0f94f84d9038ae0617d\n"
             "Algorithm:                SHA256_RSA2048\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hash descriptor:\n"
@@ -249,9 +257,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     1088 bytes\n"
             "Auxiliary Block:          3840 bytes\n"
+            "Public key (sha1):        5227b569de003adc7f8ec3fc03e05dfbd969abad\n"
             "Algorithm:                SHA256_RSA8192\n"
             "Rollback Index:           0\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Chain Partition descriptor:\n"
diff --git a/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp b/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
index 7c34009..5ec1e90 100644
--- a/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/fs_avb_util_test.cpp
@@ -57,9 +57,11 @@
             "Header Block:             256 bytes\n"
             "Authentication Block:     576 bytes\n"
             "Auxiliary Block:          1280 bytes\n"
+            "Public key (sha1):        2597c218aae470a130f61162feaae70afd97f011\n"
             "Algorithm:                SHA512_RSA4096\n"
             "Rollback Index:           20\n"
             "Flags:                    0\n"
+            "Rollback Index Location:  0\n"
             "Release String:           'unit test'\n"
             "Descriptors:\n"
             "    Hashtree descriptor:\n"
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 0addba3..7fa23db 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -98,6 +98,7 @@
     void ValidateMerge();
     void ReadSnapshotDeviceAndValidate();
     void Shutdown();
+    void MergeInterrupt();
 
     std::string snapshot_dev() const { return snapshot_dev_->path(); }
 
@@ -105,7 +106,11 @@
 
   private:
     void SetupImpl();
+
     void MergeImpl();
+    void SimulateDaemonRestart();
+    void StartMerge();
+
     void CreateCowDevice();
     void CreateBaseDevice();
     void InitCowDevice();
@@ -130,7 +135,7 @@
     std::unique_ptr<uint8_t[]> merged_buffer_;
     bool setup_ok_ = false;
     bool merge_ok_ = false;
-    size_t size_ = 1_MiB;
+    size_t size_ = 50_MiB;
     int cow_num_sectors_;
     int total_base_size_;
 };
@@ -154,9 +159,13 @@
 }
 
 void CowSnapuserdTest::Shutdown() {
-    ASSERT_TRUE(client_->StopSnapuserd());
     ASSERT_TRUE(snapshot_dev_->Destroy());
     ASSERT_TRUE(dmuser_dev_->Destroy());
+
+    auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
+    ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
+    ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
+    ASSERT_TRUE(client_->DetachSnapuserd());
 }
 
 bool CowSnapuserdTest::Setup() {
@@ -367,7 +376,7 @@
     return merge_ok_;
 }
 
-void CowSnapuserdTest::MergeImpl() {
+void CowSnapuserdTest::StartMerge() {
     DmTable merge_table;
     ASSERT_TRUE(merge_table.AddTarget(std::make_unique<DmTargetSnapshot>(
             0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
@@ -377,6 +386,11 @@
 
     DeviceMapper& dm = DeviceMapper::Instance();
     ASSERT_TRUE(dm.LoadTableAndActivate("cowsnapuserd-test-dm-snapshot", merge_table));
+}
+
+void CowSnapuserdTest::MergeImpl() {
+    StartMerge();
+    DeviceMapper& dm = DeviceMapper::Instance();
 
     while (true) {
         vector<DeviceMapper::TargetInfo> status;
@@ -405,6 +419,44 @@
     ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
 }
 
+void CowSnapuserdTest::SimulateDaemonRestart() {
+    Shutdown();
+    SetDeviceControlName();
+    StartSnapuserdDaemon();
+    InitCowDevice();
+    CreateDmUserDevice();
+    InitDaemon();
+    CreateSnapshotDevice();
+}
+
+void CowSnapuserdTest::MergeInterrupt() {
+    StartMerge();
+    std::this_thread::sleep_for(4s);
+    SimulateDaemonRestart();
+
+    StartMerge();
+    std::this_thread::sleep_for(3s);
+    SimulateDaemonRestart();
+
+    StartMerge();
+    std::this_thread::sleep_for(3s);
+    SimulateDaemonRestart();
+
+    StartMerge();
+    std::this_thread::sleep_for(1s);
+    SimulateDaemonRestart();
+
+    ASSERT_TRUE(Merge());
+}
+
+TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
+    CowSnapuserdTest harness;
+    ASSERT_TRUE(harness.Setup());
+    harness.MergeInterrupt();
+    harness.ValidateMerge();
+    harness.Shutdown();
+}
+
 TEST(Snapuserd_Test, Snapshot) {
     CowSnapuserdTest harness;
     ASSERT_TRUE(harness.Setup());
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 0a8567f..d2ffaa7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -441,7 +441,7 @@
     //
     // All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes
     // must be a multiple of the sector size (512 bytes).
-    bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status);
+    bool CreateSnapshot(LockedFile* lock, PartitionCowCreator* cow_creator, SnapshotStatus* status);
 
     // |name| should be the base partition name (e.g. "system_a"). Create the
     // backing COW image using the size previously passed to CreateSnapshot().
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index ebda430..9329725 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -312,7 +312,8 @@
     return WriteUpdateState(lock.get(), UpdateState::Unverified);
 }
 
-bool SnapshotManager::CreateSnapshot(LockedFile* lock, SnapshotStatus* status) {
+bool SnapshotManager::CreateSnapshot(LockedFile* lock, PartitionCowCreator* cow_creator,
+                                     SnapshotStatus* status) {
     CHECK(lock);
     CHECK(lock->lock_mode() == LOCK_EX);
     CHECK(status);
@@ -353,7 +354,7 @@
     status->set_state(SnapshotState::CREATED);
     status->set_sectors_allocated(0);
     status->set_metadata_sectors(0);
-    status->set_compression_enabled(IsCompressionEnabled());
+    status->set_compression_enabled(cow_creator->compression_enabled);
 
     if (!WriteSnapshotStatus(lock, *status)) {
         PLOG(ERROR) << "Could not write snapshot status: " << status->name();
@@ -2129,10 +2130,6 @@
 bool SnapshotManager::UnmapDmUserDevice(const std::string& snapshot_name) {
     auto& dm = DeviceMapper::Instance();
 
-    if (!EnsureSnapuserdConnected()) {
-        return false;
-    }
-
     auto dm_user_name = GetDmUserCowName(snapshot_name);
     if (dm.GetState(dm_user_name) == DmDeviceState::INVALID) {
         return true;
@@ -2143,6 +2140,9 @@
         return false;
     }
 
+    if (!EnsureSnapuserdConnected()) {
+        return false;
+    }
     if (!snapuserd_client_->WaitForDeviceDelete(dm_user_name)) {
         LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
         return false;
@@ -2172,12 +2172,44 @@
         return false;
     }
 
-    if (!UnmapAllSnapshots(lock.get())) {
+    std::vector<std::string> snapshots;
+    if (!ListSnapshots(lock.get(), &snapshots)) {
         return false;
     }
 
-    uint32_t slot = SlotNumberForSlotSuffix(device_->GetOtherSlotSuffix());
-    return MapAllPartitions(lock.get(), device_->GetSuperDevice(slot), slot, timeout_ms);
+    const auto& opener = device_->GetPartitionOpener();
+    auto slot_suffix = device_->GetOtherSlotSuffix();
+    auto slot_number = SlotNumberForSlotSuffix(slot_suffix);
+    auto super_device = device_->GetSuperDevice(slot_number);
+    auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot_number);
+    if (!metadata) {
+        LOG(ERROR) << "MapAllSnapshots could not read dynamic partition metadata for device: "
+                   << super_device;
+        return false;
+    }
+
+    for (const auto& snapshot : snapshots) {
+        if (!UnmapPartitionWithSnapshot(lock.get(), snapshot)) {
+            LOG(ERROR) << "MapAllSnapshots could not unmap snapshot: " << snapshot;
+            return false;
+        }
+
+        CreateLogicalPartitionParams params = {
+                .block_device = super_device,
+                .metadata = metadata.get(),
+                .partition_name = snapshot,
+                .partition_opener = &opener,
+                .timeout_ms = timeout_ms,
+        };
+        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
+                                      nullptr)) {
+            LOG(ERROR) << "MapAllSnapshots failed to map: " << snapshot;
+            return false;
+        }
+    }
+
+    LOG(INFO) << "MapAllSnapshots succeeded.";
+    return true;
 }
 
 bool SnapshotManager::UnmapAllSnapshots() {
@@ -2584,6 +2616,10 @@
     // these devices.
     AutoDeviceList created_devices;
 
+    bool use_compression = IsCompressionEnabled() &&
+                           manifest.dynamic_partition_metadata().vabc_enabled() &&
+                           !device_->IsRecovery();
+
     PartitionCowCreator cow_creator{
             .target_metadata = target_metadata.get(),
             .target_suffix = target_suffix,
@@ -2592,7 +2628,7 @@
             .current_suffix = current_suffix,
             .update = nullptr,
             .extra_extents = {},
-            .compression_enabled = IsCompressionEnabled(),
+            .compression_enabled = use_compression,
     };
 
     auto ret = CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
@@ -2744,7 +2780,7 @@
         }
 
         // Store these device sizes to snapshot status file.
-        if (!CreateSnapshot(lock, &cow_creator_ret->snapshot_status)) {
+        if (!CreateSnapshot(lock, cow_creator, &cow_creator_ret->snapshot_status)) {
             return Return::Error();
         }
         created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
@@ -2857,11 +2893,6 @@
 
 bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                                         std::string* snapshot_path) {
-    if (IsCompressionEnabled()) {
-        LOG(ERROR) << "MapUpdateSnapshot cannot be used in compression mode.";
-        return false;
-    }
-
     auto lock = LockShared();
     if (!lock) return false;
     if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
@@ -2870,6 +2901,15 @@
         return false;
     }
 
+    SnapshotStatus status;
+    if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
+        return false;
+    }
+    if (status.compression_enabled()) {
+        LOG(ERROR) << "Cannot use MapUpdateSnapshot with compressed snapshots";
+        return false;
+    }
+
     SnapshotPaths paths;
     if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
         return false;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 4c209ec..0b8a03a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -41,6 +41,7 @@
 
 #include <android/snapshot/snapshot.pb.h>
 #include <libsnapshot/test_helpers.h>
+#include "partition_cow_creator.h"
 #include "utility.h"
 
 // Mock classes are not used. Header included to ensure mocked class definition aligns with the
@@ -323,7 +324,10 @@
 
         DeltaArchiveManifest manifest;
 
-        auto group = manifest.mutable_dynamic_partition_metadata()->add_groups();
+        auto dynamic_partition_metadata = manifest.mutable_dynamic_partition_metadata();
+        dynamic_partition_metadata->set_vabc_enabled(IsCompressionEnabled());
+
+        auto group = dynamic_partition_metadata->add_groups();
         group->set_name("group");
         group->set_size(device_size * 2);
         group->add_partition_names("test_partition");
@@ -416,13 +420,16 @@
 TEST_F(SnapshotTest, CreateSnapshot) {
     ASSERT_TRUE(AcquireLock());
 
+    PartitionCowCreator cow_creator;
+    cow_creator.compression_enabled = IsCompressionEnabled();
+
     static const uint64_t kDeviceSize = 1024 * 1024;
     SnapshotStatus status;
     status.set_name("test-snapshot");
     status.set_device_size(kDeviceSize);
     status.set_snapshot_size(kDeviceSize);
     status.set_cow_file_size(kDeviceSize);
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::vector<std::string> snapshots;
@@ -437,6 +444,7 @@
         ASSERT_EQ(status.state(), SnapshotState::CREATED);
         ASSERT_EQ(status.device_size(), kDeviceSize);
         ASSERT_EQ(status.snapshot_size(), kDeviceSize);
+        ASSERT_EQ(status.compression_enabled(), cow_creator.compression_enabled);
     }
 
     ASSERT_TRUE(sm->UnmapSnapshot(lock_.get(), "test-snapshot"));
@@ -447,13 +455,16 @@
 TEST_F(SnapshotTest, MapSnapshot) {
     ASSERT_TRUE(AcquireLock());
 
+    PartitionCowCreator cow_creator;
+    cow_creator.compression_enabled = IsCompressionEnabled();
+
     static const uint64_t kDeviceSize = 1024 * 1024;
     SnapshotStatus status;
     status.set_name("test-snapshot");
     status.set_device_size(kDeviceSize);
     status.set_snapshot_size(kDeviceSize);
     status.set_cow_file_size(kDeviceSize);
-    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &status));
+    ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
     ASSERT_TRUE(CreateCowImage("test-snapshot"));
 
     std::string base_device;
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 9ad4a1a..ceba8ab 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -96,7 +96,7 @@
 // it will be de-compressed.
 bool Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
     if (!reader_->ReadData(*cow_op, &bufsink_)) {
-        SNAP_LOG(ERROR) << "ReadData failed for chunk: " << cow_op->new_block;
+        SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block;
         return false;
     }
 
@@ -113,7 +113,8 @@
     // if the successive blocks are contiguous.
     if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
                                           cow_op->source * BLOCK_SIZE)) {
-        SNAP_LOG(ERROR) << "Copy-op failed. Read from backing store at: " << cow_op->source;
+        SNAP_PLOG(ERROR) << "Copy-op failed. Read from backing store: " << backing_store_device_
+                         << "at block :" << cow_op->source;
         return false;
     }
 
@@ -160,7 +161,7 @@
                     << " Aligned sector: " << it->second;
 
     if (!ProcessCowOp(it->second)) {
-        SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed";
+        SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size;
         return -1;
     }
 
@@ -377,16 +378,21 @@
             CHECK(cow_de->new_chunk == 0);
             break;
         } else {
-            SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata";
-            SNAP_LOG(ERROR) << "merged_de-old-chunk: " << merged_de->old_chunk;
-            SNAP_LOG(ERROR) << "merged_de-new-chunk: " << merged_de->new_chunk;
-            SNAP_LOG(ERROR) << "cow_de-old-chunk: " << cow_de->old_chunk;
-            SNAP_LOG(ERROR) << "cow_de-new-chunk: " << cow_de->new_chunk;
+            SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata: "
+                            << " merged_de-old-chunk: " << merged_de->old_chunk
+                            << " merged_de-new-chunk: " << merged_de->new_chunk
+                            << " cow_de-old-chunk: " << cow_de->old_chunk
+                            << " cow_de-new-chunk: " << cow_de->new_chunk
+                            << " unmerged_exceptions: " << unmerged_exceptions
+                            << " merged_ops_cur_iter: " << merged_ops_cur_iter
+                            << " offset: " << offset;
             return -1;
         }
     }
 
     if (*copy_op) {
+        SNAP_LOG(ERROR) << "Invalid batch merge of copy ops: merged_ops_cur_iter: "
+                        << merged_ops_cur_iter;
         CHECK(merged_ops_cur_iter == 1);
     }
     return merged_ops_cur_iter;
@@ -446,7 +452,7 @@
     header.num_merge_ops += merged_ops_cur_iter;
     reader_->UpdateMergeProgress(merged_ops_cur_iter);
     if (!writer_->CommitMerge(merged_ops_cur_iter, copy_op)) {
-        SNAP_LOG(ERROR) << "CommitMerge failed...";
+        SNAP_LOG(ERROR) << "CommitMerge failed... merged_ops_cur_iter: " << merged_ops_cur_iter;
         return false;
     }
 
@@ -661,7 +667,7 @@
 bool Snapuserd::WriteDmUserPayload(size_t size) {
     if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
                                    sizeof(struct dm_user_header) + size)) {
-        SNAP_PLOG(ERROR) << "Write to dm-user failed";
+        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << size;
         return false;
     }
 
@@ -670,7 +676,7 @@
 
 bool Snapuserd::ReadDmUserPayload(void* buffer, size_t size) {
     if (!android::base::ReadFully(ctrl_fd_, buffer, size)) {
-        SNAP_PLOG(ERROR) << "ReadDmUserPayload failed";
+        SNAP_PLOG(ERROR) << "ReadDmUserPayload failed size: " << size;
         return false;
     }
 
@@ -808,7 +814,8 @@
                 ret = ReadData(sector + num_sectors_read, read_size);
                 if (ret < 0) {
                     SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
-                                    << "Sector: " << header->sector;
+                                    << " Sector: " << (sector + num_sectors_read)
+                                    << " size: " << read_size << " header-len: " << header->len;
                     header->type = DM_USER_RESP_ERROR;
                 } else {
                     SNAP_LOG(DEBUG) << "ReadData success for chunk id: " << chunk
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
index dda214e..4a97f81 100644
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -73,6 +73,7 @@
 
 message DynamicPartitionMetadata {
     repeated DynamicPartitionGroup groups = 1;
+    optional bool vabc_enabled = 3;
 }
 
 message DeltaArchiveManifest {
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 7c46281..7307237 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -253,6 +253,22 @@
 
     if (!InitDevices()) return false;
 
+    // Mount /metadata before creating logical partitions, since we need to
+    // know whether a snapshot merge is in progress.
+    auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
+        return entry.mount_point == "/metadata";
+    });
+    if (metadata_partition != fstab_.end()) {
+        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
+            // Copies DSU AVB keys from the ramdisk to /metadata.
+            // Must be done before the following TrySwitchSystemAsRoot().
+            // Otherwise, ramdisk will be inaccessible after switching root.
+            CopyDsuAvbKeys();
+        }
+    }
+
+    if (!CreateLogicalPartitions()) return false;
+
     if (!MountPartitions()) return false;
 
     return true;
@@ -505,22 +521,6 @@
 }
 
 bool FirstStageMount::MountPartitions() {
-    // Mount /metadata before creating logical partitions, since we need to
-    // know whether a snapshot merge is in progress.
-    auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
-        return entry.mount_point == "/metadata";
-    });
-    if (metadata_partition != fstab_.end()) {
-        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
-            // Copies DSU AVB keys from the ramdisk to /metadata.
-            // Must be done before the following TrySwitchSystemAsRoot().
-            // Otherwise, ramdisk will be inaccessible after switching root.
-            CopyDsuAvbKeys();
-        }
-    }
-
-    if (!CreateLogicalPartitions()) return false;
-
     if (!TrySwitchSystemAsRoot()) return false;
 
     if (!SkipMountingPartitions(&fstab_)) return false;