libsnapshot: Remove ISnapshotWriter.

This only added one real method to ICowWriter, so let's just fold it
into ICowWriter. CompressedSnapshotWriter goes away as well.
CompressedSnapshotReader is now part of libsnapshot_cow.

Bug: 280529365
Test: m otapackage
      apply ota
Change-Id: I55358c3c9be111d5aee1a0c22c29cb1539d05494
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index e931bec..046d30c 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -85,11 +85,9 @@
         "android/snapshot/snapshot.proto",
         "device_info.cpp",
         "snapshot.cpp",
-        "snapshot_reader.cpp",
         "snapshot_stats.cpp",
         "snapshot_stub.cpp",
         "snapshot_metadata_updater.cpp",
-        "snapshot_writer.cpp",
         "partition_cow_creator.cpp",
         "return.cpp",
         "utility.cpp",
@@ -165,6 +163,9 @@
         "liblz4",
         "libzstd",
     ],
+    header_libs: [
+        "libupdate_engine_headers",
+    ],
     export_include_dirs: ["include"],
 }
 
@@ -179,6 +180,7 @@
         "libsnapshot_cow/cow_format.cpp",
         "libsnapshot_cow/cow_reader.cpp",
         "libsnapshot_cow/parser_v2.cpp",
+        "libsnapshot_cow/snapshot_reader.cpp",
         "libsnapshot_cow/writer_base.cpp",
         "libsnapshot_cow/writer_v2.cpp",
     ],
@@ -224,9 +226,7 @@
     srcs: [
         "partition_cow_creator_test.cpp",
         "snapshot_metadata_updater_test.cpp",
-        "snapshot_reader_test.cpp",
         "snapshot_test.cpp",
-        "snapshot_writer_test.cpp",
     ],
     shared_libs: [
         "libbinder",
@@ -372,6 +372,7 @@
         "libsnapshot_cow_defaults",
     ],
     srcs: [
+        "libsnapshot_cow/snapshot_reader_test.cpp",
         "libsnapshot_cow/test_v2.cpp",
     ],
     cflags: [
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 95a1270..3890b17 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -24,6 +24,10 @@
 #include <android-base/unique_fd.h>
 #include <libsnapshot/cow_format.h>
 
+namespace chromeos_update_engine {
+class FileDescriptor;
+}  // namespace chromeos_update_engine
+
 namespace android {
 namespace snapshot {
 
@@ -32,6 +36,8 @@
 // Interface for reading from a snapuserd COW.
 class ICowReader {
   public:
+    using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
     virtual ~ICowReader() {}
 
     // Return the file header.
@@ -109,10 +115,9 @@
     bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
 
     bool InitForMerge(android::base::unique_fd&& fd);
+
     bool VerifyMergeOps() override;
-
     bool GetFooter(CowFooter* footer) override;
-
     bool GetLastLabel(uint64_t* label) override;
 
     // Create a CowOpIter object which contains footer_.num_ops
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index af2d3ef..d6194eb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -61,6 +61,8 @@
 // will occur in the sequence they were added to the COW.
 class ICowWriter {
   public:
+    using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
     virtual ~ICowWriter() {}
 
     // Encode an operation that copies the contents of |old_block| to the
@@ -93,6 +95,17 @@
 
     virtual uint32_t GetBlockSize() const = 0;
     virtual std::optional<uint32_t> GetMaxBlocks() const = 0;
+
+    // Open an ICowReader for this writer. The reader will be a snapshot of the
+    // current operations in the writer; new writes after OpenReader() will not
+    // be reflected.
+    virtual std::unique_ptr<ICowReader> OpenReader() = 0;
+
+    // Open a file descriptor. This allows reading and seeing through the cow
+    // as if it were a normal file. The optional source_device must be a valid
+    // path if the CowReader contains any copy or xor operations.
+    virtual std::unique_ptr<FileDescriptor> OpenFileDescriptor(
+            const std::optional<std::string>& source_device) = 0;
 };
 
 class CompressWorker {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
similarity index 75%
rename from fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
rename to fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
index 52e3a9c..c58c654 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
@@ -15,17 +15,16 @@
 //
 
 #include <gmock/gmock.h>
-#include <libsnapshot/snapshot_writer.h>
+#include <libsnapshot/cow_writer.h>
 
 namespace android::snapshot {
 
-class MockSnapshotWriter : public ISnapshotWriter {
+class MockCowWriter : public ICowWriter {
   public:
-    using FileDescriptor = ISnapshotWriter::FileDescriptor;
+    using FileDescriptor = chromeos_update_engine::FileDescriptor;
 
     MOCK_METHOD(bool, Finalize, (), (override));
 
-    // Return number of bytes the cow image occupies on disk.
     MOCK_METHOD(uint64_t, GetCowSize, (), (override));
 
     MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override));
@@ -35,11 +34,12 @@
     MOCK_METHOD(bool, AddZeroBlocks, (uint64_t, uint64_t), (override));
     MOCK_METHOD(bool, AddLabel, (uint64_t), (override));
     MOCK_METHOD(bool, AddSequenceData, (size_t, const uint32_t*), (override));
-    MOCK_METHOD(bool, Initialize, (), (override));
-    MOCK_METHOD(bool, InitializeAppend, (uint64_t), (override));
-    MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept));
-    MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
     MOCK_METHOD(uint32_t, GetBlockSize, (), (override, const));
     MOCK_METHOD(std::optional<uint32_t>, GetMaxBlocks, (), (override, const));
+
+    MOCK_METHOD(std::unique_ptr<ICowReader>, OpenReader, (), (override));
+    MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenFileDescriptor,
+                (const std::optional<std::string>&), (override));
 };
+
 }  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index d458b87..ca45d2f 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -42,9 +42,9 @@
                 (const android::fs_mgr::CreateLogicalPartitionParams& params,
                  std::string* snapshot_path),
                 (override));
-    MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
+    MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
                 (const android::fs_mgr::CreateLogicalPartitionParams& params,
-                 const std::optional<std::string>&),
+                 std::optional<uint64_t>),
                 (override));
     MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
     MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index ecf1d15..df532ee 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -33,12 +33,11 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
-#include <update_engine/update_metadata.pb.h>
-
 #include <libsnapshot/auto_device.h>
+#include <libsnapshot/cow_writer.h>
 #include <libsnapshot/return.h>
-#include <libsnapshot/snapshot_writer.h>
 #include <snapuserd/snapuserd_client.h>
+#include <update_engine/update_metadata.pb.h>
 
 #ifndef FRIEND_TEST
 #define FRIEND_TEST(test_set_name, individual_test) \
@@ -211,16 +210,13 @@
     virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                                    std::string* snapshot_path) = 0;
 
-    // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
+    // Create an ICowWriter to build a snapshot against a target partition. The partition name
     // must be suffixed. If a source partition exists, it must be specified as well. The source
     // partition will only be used if raw bytes are needed. The source partition should be an
     // absolute path to the device, not a partition name.
-    //
-    // After calling OpenSnapshotWriter, the caller must invoke Initialize or InitializeForAppend
-    // before invoking write operations.
-    virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+    virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
             const android::fs_mgr::CreateLogicalPartitionParams& params,
-            const std::optional<std::string>& source_device) = 0;
+            std::optional<uint64_t> label = {}) = 0;
 
     // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
     // OpenSnapshotWriter. All outstanding open descriptors, writers, or
@@ -362,9 +358,9 @@
     Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
-    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+    std::unique_ptr<ICowWriter> OpenSnapshotWriter(
             const android::fs_mgr::CreateLogicalPartitionParams& params,
-            const std::optional<std::string>& source_device) override;
+            std::optional<uint64_t> label) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
     bool CreateLogicalAndSnapshotPartitions(
@@ -693,10 +689,10 @@
     };
 
     // Helpers for OpenSnapshotWriter.
-    std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(
-            LockedFile* lock, const std::optional<std::string>& source_device,
-            const std::string& partition_name, const SnapshotStatus& status,
-            const SnapshotPaths& paths);
+    std::unique_ptr<ICowWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
+                                                             const SnapshotStatus& status,
+                                                             const SnapshotPaths& paths,
+                                                             std::optional<uint64_t> label);
 
     // Map the base device, COW devices, and snapshot device.
     bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
@@ -743,7 +739,7 @@
     // Initialize snapshots so that they can be mapped later.
     // Map the COW partition and zero-initialize the header.
     Return InitializeUpdateSnapshots(
-            LockedFile* lock, MetadataBuilder* target_metadata,
+            LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
             const LpMetadata* exported_target_metadata, const std::string& target_suffix,
             const std::map<std::string, SnapshotStatus>& all_snapshot_status);
 
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 171c7c6..1c9b403 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -40,9 +40,9 @@
             const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
-    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+    std::unique_ptr<ICowWriter> OpenSnapshotWriter(
             const android::fs_mgr::CreateLogicalPartitionParams& params,
-            const std::optional<std::string>& source_device) override;
+            std::optional<uint64_t> label) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
     bool CreateLogicalAndSnapshotPartitions(
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
deleted file mode 100644
index 2653a60..0000000
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <optional>
-
-#include <android-base/unique_fd.h>
-
-#include <libsnapshot/cow_writer.h>
-
-namespace chromeos_update_engine {
-class FileDescriptor;
-}  // namespace chromeos_update_engine
-
-namespace android {
-namespace snapshot {
-
-class ISnapshotWriter : public ICowWriter {
-  public:
-    using FileDescriptor = chromeos_update_engine::FileDescriptor;
-
-    virtual ~ISnapshotWriter() {}
-
-    // Open the writer in write mode (no append).
-    virtual bool Initialize() = 0;
-
-    // Open the writer in append mode, with the last label to resume
-    // from. See CowWriter::InitializeAppend.
-    virtual bool InitializeAppend(uint64_t label) = 0;
-
-    virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
-
-    virtual bool VerifyMergeOps() const noexcept = 0;
-};
-
-// Send writes to a COW or a raw device directly, based on a threshold.
-class CompressedSnapshotWriter final : public ISnapshotWriter {
-  public:
-    CompressedSnapshotWriter(const CowOptions& options);
-
-    void SetSourceDevice(const std::string& source_device);
-
-    // Sets the COW device; this is required.
-    bool SetCowDevice(android::base::unique_fd&& cow_device);
-
-    bool Initialize() override;
-    bool InitializeAppend(uint64_t label) override;
-    bool Finalize() override;
-    uint64_t GetCowSize() override;
-    uint32_t GetBlockSize() const override;
-    std::optional<uint32_t> GetMaxBlocks() const override;
-    std::unique_ptr<FileDescriptor> OpenReader() override;
-    bool VerifyMergeOps() const noexcept;
-
-    bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
-    bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
-    bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
-                      uint16_t offset) override;
-    bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
-    bool AddLabel(uint64_t label) override;
-    bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
-
-  private:
-    std::unique_ptr<CowReader> OpenCowReader() const;
-    android::base::borrowed_fd GetSourceFd();
-
-    CowOptions options_;
-
-    // Set the source device. This is used for AddCopy() operations, if the
-    // underlying writer needs the original bytes (for example if backed by
-    // dm-snapshot or if writing directly to an unsnapshotted region). The
-    // device is only opened on the first operation that requires it.
-    std::optional<std::string> source_device_;
-    android::base::unique_fd source_fd_;
-
-    android::base::unique_fd cow_device_;
-    std::unique_ptr<ICowWriter> cow_;
-};
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index f45d4ed..5e9f049 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -198,7 +198,7 @@
 // Expect space of |path| is multiple of 4K.
 bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
                      std::string* hash = nullptr);
-std::string HashSnapshot(ISnapshotWriter* writer);
+std::string HashSnapshot(ICowWriter::FileDescriptor* writer);
 
 std::string ToHexString(const uint8_t* buf, size_t len);
 
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
similarity index 82%
rename from fs_mgr/libsnapshot/snapshot_reader.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
index 4e75ba7..f9cdbc0 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
@@ -18,73 +18,24 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <ext4_utils/ext4_utils.h>
 
 namespace android {
 namespace snapshot {
 
 using android::base::borrowed_fd;
 
-// Not supported.
-bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
-    errno = EINVAL;
-    return false;
-}
-
-bool ReadOnlyFileDescriptor::Open(const char*, int) {
-    errno = EINVAL;
-    return false;
-}
-
-ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
-    errno = EINVAL;
-    return false;
-}
-
-bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
-    errno = EINVAL;
-    return false;
-}
-
-ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
-
-ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
-    return read(fd_.get(), buf, count);
-}
-
-off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
-    return lseek(fd_.get(), offset, whence);
-}
-
-uint64_t ReadFdFileDescriptor::BlockDevSize() {
-    return get_block_device_size(fd_.get());
-}
-
-bool ReadFdFileDescriptor::Close() {
-    fd_ = {};
-    return true;
-}
-
-bool ReadFdFileDescriptor::IsSettingErrno() {
-    return true;
-}
-
-bool ReadFdFileDescriptor::IsOpen() {
-    return fd_ >= 0;
-}
-
-bool ReadFdFileDescriptor::Flush() {
-    return true;
-}
-
-bool CompressedSnapshotReader::SetCow(std::unique_ptr<CowReader>&& cow) {
-    cow_ = std::move(cow);
-
+CompressedSnapshotReader::CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
+                                                   const std::optional<std::string>& source_device,
+                                                   std::optional<uint64_t> block_dev_size)
+    : cow_(std::move(cow)),
+      block_size_(cow_->GetHeader().block_size),
+      source_device_(source_device),
+      block_device_size_(block_dev_size.value_or(0)) {
     const auto& header = cow_->GetHeader();
     block_size_ = header.block_size;
 
     // Populate the operation map.
-    op_iter_ = cow_->GetOpIter();
+    op_iter_ = cow_->GetOpIter(false);
     while (!op_iter_->AtEnd()) {
         const CowOperation* op = op_iter_->Get();
         if (IsMetadataOp(*op)) {
@@ -97,16 +48,27 @@
         ops_[op->new_block] = op;
         op_iter_->Next();
     }
-
-    return true;
 }
 
-void CompressedSnapshotReader::SetSourceDevice(const std::string& source_device) {
-    source_device_ = {source_device};
+// Not supported.
+bool CompressedSnapshotReader::Open(const char*, int, mode_t) {
+    errno = EINVAL;
+    return false;
 }
 
-void CompressedSnapshotReader::SetBlockDeviceSize(uint64_t block_device_size) {
-    block_device_size_ = block_device_size;
+bool CompressedSnapshotReader::Open(const char*, int) {
+    errno = EINVAL;
+    return false;
+}
+
+ssize_t CompressedSnapshotReader::Write(const void*, size_t) {
+    errno = EINVAL;
+    return false;
+}
+
+bool CompressedSnapshotReader::BlkIoctl(int, uint64_t, uint64_t, int*) {
+    errno = EINVAL;
+    return false;
 }
 
 borrowed_fd CompressedSnapshotReader::GetSourceFd() {
diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
similarity index 69%
rename from fs_mgr/libsnapshot/snapshot_reader.h
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
index 5e19c62..3de63ed 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
@@ -26,36 +26,16 @@
 namespace android {
 namespace snapshot {
 
-class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
+class CompressedSnapshotReader : public chromeos_update_engine::FileDescriptor {
   public:
+    CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
+                             const std::optional<std::string>& source_device,
+                             std::optional<uint64_t> block_dev_size);
+
     bool Open(const char* path, int flags, mode_t mode) override;
     bool Open(const char* path, int flags) override;
     ssize_t Write(const void* buf, size_t count) override;
     bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override;
-};
-
-class ReadFdFileDescriptor : public ReadOnlyFileDescriptor {
-  public:
-    explicit ReadFdFileDescriptor(android::base::unique_fd&& fd);
-
-    ssize_t Read(void* buf, size_t count) override;
-    off64_t Seek(off64_t offset, int whence) override;
-    uint64_t BlockDevSize() override;
-    bool Close() override;
-    bool IsSettingErrno() override;
-    bool IsOpen() override;
-    bool Flush() override;
-
-  private:
-    android::base::unique_fd fd_;
-};
-
-class CompressedSnapshotReader : public ReadOnlyFileDescriptor {
-  public:
-    bool SetCow(std::unique_ptr<CowReader>&& cow);
-    void SetSourceDevice(const std::string& source_device);
-    void SetBlockDeviceSize(uint64_t block_device_size);
-
     ssize_t Read(void* buf, size_t count) override;
     off64_t Seek(off64_t offset, int whence) override;
     uint64_t BlockDevSize() override;
@@ -68,7 +48,7 @@
     ssize_t ReadBlock(uint64_t chunk, size_t start_offset, void* buffer, size_t size);
     android::base::borrowed_fd GetSourceFd();
 
-    std::unique_ptr<CowReader> cow_;
+    std::unique_ptr<ICowReader> cow_;
     std::unique_ptr<ICowOpIter> op_iter_;
     uint32_t block_size_ = 0;
 
diff --git a/fs_mgr/libsnapshot/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
similarity index 92%
rename from fs_mgr/libsnapshot/snapshot_reader_test.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
index f25023d..10cb06d 100644
--- a/fs_mgr/libsnapshot/snapshot_reader_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <libsnapshot/snapshot.h>
-
 #include <unordered_set>
 
 #include <android-base/file.h>
@@ -61,7 +59,7 @@
         ASSERT_EQ(fsync(base_->fd), 0);
     }
 
-    void WriteCow(ISnapshotWriter* writer) {
+    void WriteCow(ICowWriter* writer) {
         std::string new_block = MakeNewBlockString();
         std::string xor_block = MakeXorBlockString();
 
@@ -72,8 +70,8 @@
         ASSERT_TRUE(writer->Finalize());
     }
 
-    void TestBlockReads(ISnapshotWriter* writer) {
-        auto reader = writer->OpenReader();
+    void TestBlockReads(ICowWriter* writer) {
+        auto reader = writer->OpenFileDescriptor(base_->path);
         ASSERT_NE(reader, nullptr);
 
         // Test that unchanged blocks are not modified.
@@ -117,8 +115,8 @@
         ASSERT_EQ(two_blocks, zeroes);
     }
 
-    void TestByteReads(ISnapshotWriter* writer) {
-        auto reader = writer->OpenReader();
+    void TestByteReads(ICowWriter* writer) {
+        auto reader = writer->OpenFileDescriptor(base_->path);
         ASSERT_NE(reader, nullptr);
 
         std::string blob(kBlockSize * 3, 'x');
@@ -154,7 +152,7 @@
         ASSERT_EQ(got, expected);
     }
 
-    void TestReads(ISnapshotWriter* writer) {
+    void TestReads(ICowWriter* writer) {
         ASSERT_NO_FATAL_FAILURE(TestBlockReads(writer));
         ASSERT_NO_FATAL_FAILURE(TestByteReads(writer));
     }
@@ -186,10 +184,7 @@
     unique_fd cow_fd(dup(cow_->fd));
     ASSERT_GE(cow_fd, 0);
 
-    auto writer = std::make_unique<CompressedSnapshotWriter>(options);
-    writer->SetSourceDevice(base_->path);
-    ASSERT_TRUE(writer->SetCowDevice(std::move(cow_fd)));
-    ASSERT_TRUE(writer->Initialize());
+    auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd));
     ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get()));
     ASSERT_NO_FATAL_FAILURE(TestReads(writer.get()));
 }
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
index 22e63d0..ff34c59 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <android-base/logging.h>
+#include "snapshot_reader.h"
 
 // The info messages here are spammy, but as useful for update_engine. Disable
 // them when running on the host.
@@ -159,5 +160,36 @@
     return true;
 }
 
+std::unique_ptr<ICowReader> CowWriterBase::OpenReader() {
+    unique_fd cow_fd(fcntl(fd_.get(), F_DUPFD | F_DUPFD_CLOEXEC, 0));
+    if (cow_fd < 0) {
+        PLOG(ERROR) << "CowWriterV2::OpenReander: dup COW device";
+        return nullptr;
+    }
+
+    auto cow = std::make_unique<CowReader>();
+    if (!cow->Parse(std::move(cow_fd))) {
+        LOG(ERROR) << "CowWriterV2::OpenReader: unable to read COW";
+        return nullptr;
+    }
+    return cow;
+}
+
+std::unique_ptr<chromeos_update_engine::FileDescriptor> CowWriterBase::OpenFileDescriptor(
+        const std::optional<std::string>& source_device) {
+    auto reader = OpenReader();
+    if (!reader) {
+        return nullptr;
+    }
+
+    std::optional<uint64_t> block_dev_size;
+    if (options_.max_blocks) {
+        block_dev_size = {*options_.max_blocks * options_.block_size};
+    }
+
+    return std::make_unique<CompressedSnapshotReader>(std::move(reader), source_device,
+                                                      block_dev_size);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
index 8fa9065..c8b4772 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
@@ -43,6 +43,9 @@
     bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
     uint32_t GetBlockSize() const override { return options_.block_size; }
     std::optional<uint32_t> GetMaxBlocks() const override { return options_.max_blocks; }
+    std::unique_ptr<ICowReader> OpenReader() override;
+    std::unique_ptr<FileDescriptor> OpenFileDescriptor(
+            const std::optional<std::string>& source_device) override;
 
     const CowOptions& options() const { return options_; }
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 5920bc2..fbea79b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -45,10 +45,9 @@
 #include <android/snapshot/snapshot.pb.h>
 #include <libsnapshot/snapshot_stats.h>
 #include "device_info.h"
-#include "libsnapshot_cow/writer_v2.h"
+#include "libsnapshot_cow/parser_v2.h"
 #include "partition_cow_creator.h"
 #include "snapshot_metadata_updater.h"
-#include "snapshot_reader.h"
 #include "utility.h"
 
 namespace android {
@@ -3288,7 +3287,7 @@
         return Return::Error();
     }
 
-    ret = InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
+    ret = InitializeUpdateSnapshots(lock.get(), dap_metadata.cow_version(), target_metadata.get(),
                                     exported_target_metadata.get(), target_suffix,
                                     all_snapshot_status);
     if (!ret.is_ok()) return ret;
@@ -3510,7 +3509,7 @@
 }
 
 Return SnapshotManager::InitializeUpdateSnapshots(
-        LockedFile* lock, MetadataBuilder* target_metadata,
+        LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
         const LpMetadata* exported_target_metadata, const std::string& target_suffix,
         const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
     CHECK(lock);
@@ -3558,8 +3557,8 @@
             }
             options.compression = it->second.compression_algorithm();
 
-            CowWriterV2 writer(options, std::move(fd));
-            if (!writer.Initialize(std::nullopt) || !writer.Finalize()) {
+            auto writer = CreateCowWriter(cow_version, options, std::move(fd));
+            if (!writer->Finalize()) {
                 LOG(ERROR) << "Could not initialize COW device for " << target_partition->name();
                 return Return::Error();
             }
@@ -3609,12 +3608,12 @@
     return true;
 }
 
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
+std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
         const android::fs_mgr::CreateLogicalPartitionParams& params,
-        const std::optional<std::string>& source_device) {
+        std::optional<uint64_t> label) {
 #if defined(LIBSNAPSHOT_NO_COW_WRITE)
     (void)params;
-    (void)source_device;
+    (void)label;
 
     LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
     return nullptr;
@@ -3653,16 +3652,14 @@
         return nullptr;
     }
 
-    return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
-                                        status, paths);
+    return OpenCompressedSnapshotWriter(lock.get(), status, paths, label);
 #endif
 }
 
 #if !defined(LIBSNAPSHOT_NO_COW_WRITE)
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
-        LockedFile* lock, const std::optional<std::string>& source_device,
-        [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status,
-        const SnapshotPaths& paths) {
+std::unique_ptr<ICowWriter> SnapshotManager::OpenCompressedSnapshotWriter(
+        LockedFile* lock, const SnapshotStatus& status, const SnapshotPaths& paths,
+        std::optional<uint64_t> label) {
     CHECK(lock);
 
     CowOptions cow_options;
@@ -3679,11 +3676,6 @@
     // never creates this scenario.
     CHECK(status.snapshot_size() == status.device_size());
 
-    auto writer = std::make_unique<CompressedSnapshotWriter>(cow_options);
-    if (source_device) {
-        writer->SetSourceDevice(*source_device);
-    }
-
     std::string cow_path;
     if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
         LOG(ERROR) << "Could not determine path for " << paths.cow_device_name;
@@ -3695,12 +3687,14 @@
         PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path;
         return nullptr;
     }
-    if (!writer->SetCowDevice(std::move(cow_fd))) {
-        LOG(ERROR) << "Could not create COW writer from " << cow_path;
+
+    CowHeader header;
+    if (!ReadCowHeader(cow_fd, &header)) {
+        LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
         return nullptr;
     }
 
-    return writer;
+    return CreateCowWriter(header.prefix.major_version, cow_options, std::move(cow_fd), label);
 }
 #endif  // !defined(LIBSNAPSHOT_NO_COW_WRITE)
 
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 84e2226..9354102 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -154,8 +154,8 @@
     return &snapshot_merge_stats;
 }
 
-std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
-        const CreateLogicalPartitionParams&, const std::optional<std::string>&) {
+std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(
+        const CreateLogicalPartitionParams&, std::optional<uint64_t>) {
     LOG(ERROR) << __FUNCTION__ << " should never be called.";
     return nullptr;
 }
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index dac1b77..0a85489 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -345,7 +345,7 @@
     }
 
     AssertionResult MapUpdateSnapshot(const std::string& name,
-                                      std::unique_ptr<ISnapshotWriter>* writer) {
+                                      std::unique_ptr<ICowWriter>* writer) {
         TestPartitionOpener opener(fake_super);
         CreateLogicalPartitionParams params{
                 .block_device = fake_super,
@@ -355,14 +355,10 @@
                 .partition_opener = &opener,
         };
 
-        auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
-        auto result = sm->OpenSnapshotWriter(params, {old_partition});
+        auto result = sm->OpenSnapshotWriter(params, {});
         if (!result) {
             return AssertionFailure() << "Cannot open snapshot for writing: " << name;
         }
-        if (!result->Initialize()) {
-            return AssertionFailure() << "Cannot initialize snapshot for writing: " << name;
-        }
 
         if (writer) {
             *writer = std::move(result);
@@ -440,7 +436,7 @@
 
     // Prepare A/B slot for a partition named "test_partition".
     AssertionResult PrepareOneSnapshot(uint64_t device_size,
-                                       std::unique_ptr<ISnapshotWriter>* writer = nullptr) {
+                                       std::unique_ptr<ICowWriter>* writer = nullptr) {
         lock_ = nullptr;
 
         DeltaArchiveManifest manifest;
@@ -651,7 +647,7 @@
 
     bool userspace_snapshots = false;
     if (snapuserd_required_) {
-        std::unique_ptr<ISnapshotWriter> writer;
+        std::unique_ptr<ICowWriter> writer;
         ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
 
         userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get());
@@ -1160,7 +1156,7 @@
 
     AssertionResult MapOneUpdateSnapshot(const std::string& name) {
         if (snapuserd_required_) {
-            std::unique_ptr<ISnapshotWriter> writer;
+            std::unique_ptr<ICowWriter> writer;
             return MapUpdateSnapshot(name, &writer);
         } else {
             std::string path;
@@ -1181,7 +1177,7 @@
     AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
         std::string name = partition->partition_name() + "_b";
         if (snapuserd_required_) {
-            std::unique_ptr<ISnapshotWriter> writer;
+            std::unique_ptr<ICowWriter> writer;
             auto res = MapUpdateSnapshot(name, &writer);
             if (!res) {
                 return res;
@@ -1250,7 +1246,7 @@
     // It doesn't really matter the order, we just want copies that reference
     // blocks that won't exist if the partition shrinks.
     AssertionResult ShiftAllSnapshotBlocks(const std::string& name, uint64_t old_size) {
-        std::unique_ptr<ISnapshotWriter> writer;
+        std::unique_ptr<ICowWriter> writer;
         if (auto res = MapUpdateSnapshot(name, &writer); !res) {
             return res;
         }
@@ -1273,7 +1269,13 @@
             return AssertionFailure() << "Unable to finalize writer for " << name;
         }
 
-        auto hash = HashSnapshot(writer.get());
+        auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
+        auto reader = writer->OpenFileDescriptor(old_partition);
+        if (!reader) {
+            return AssertionFailure() << "Could not open file descriptor for " << name;
+        }
+
+        auto hash = HashSnapshot(reader.get());
         if (hash.empty()) {
             return AssertionFailure() << "Unable to hash snapshot writer for " << name;
         }
@@ -1428,7 +1430,7 @@
     for (auto* partition : partitions) {
         AddOperation(partition);
 
-        std::unique_ptr<ISnapshotWriter> writer;
+        std::unique_ptr<ICowWriter> writer;
         auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
         ASSERT_TRUE(res);
         ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
deleted file mode 100644
index 0ea424c..0000000
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <libsnapshot/snapshot_writer.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <payload_consumer/file_descriptor.h>
-#include "libsnapshot_cow/writer_v2.h"
-#include "snapshot_reader.h"
-
-namespace android {
-namespace snapshot {
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-using chromeos_update_engine::FileDescriptor;
-
-void CompressedSnapshotWriter::SetSourceDevice(const std::string& source_device) {
-    source_device_ = {source_device};
-}
-
-borrowed_fd CompressedSnapshotWriter::GetSourceFd() {
-    if (!source_device_) {
-        LOG(ERROR) << "Attempted to read from source device but none was set";
-        return borrowed_fd{-1};
-    }
-
-    if (source_fd_ < 0) {
-        source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
-        if (source_fd_ < 0) {
-            PLOG(ERROR) << "open " << *source_device_;
-            return borrowed_fd{-1};
-        }
-    }
-    return source_fd_;
-}
-
-CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) : options_(options) {}
-
-bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
-    cow_device_ = std::move(cow_device);
-    return true;
-}
-
-bool CompressedSnapshotWriter::Finalize() {
-    return cow_->Finalize();
-}
-
-uint64_t CompressedSnapshotWriter::GetCowSize() {
-    return cow_->GetCowSize();
-}
-
-std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
-    unique_fd cow_fd(dup(cow_device_.get()));
-    if (cow_fd < 0) {
-        PLOG(ERROR) << "dup COW device";
-        return nullptr;
-    }
-
-    auto cow = std::make_unique<CowReader>();
-    if (!cow->Parse(std::move(cow_fd))) {
-        LOG(ERROR) << "Unable to read COW";
-        return nullptr;
-    }
-    return cow;
-}
-
-bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
-    auto cow_reader = OpenCowReader();
-    if (cow_reader == nullptr) {
-        LOG(ERROR) << "Couldn't open CowReader";
-        return false;
-    }
-    return cow_reader->VerifyMergeOps();
-}
-
-std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
-    auto cow = OpenCowReader();
-    if (cow == nullptr) {
-        return nullptr;
-    }
-
-    auto reader = std::make_unique<CompressedSnapshotReader>();
-    if (!reader->SetCow(std::move(cow))) {
-        LOG(ERROR) << "Unable to initialize COW reader";
-        return nullptr;
-    }
-    if (source_device_) {
-        reader->SetSourceDevice(*source_device_);
-    }
-
-    if (options_.max_blocks) {
-        reader->SetBlockDeviceSize(*options_.max_blocks * options_.block_size);
-    }
-
-    return reader;
-}
-
-bool CompressedSnapshotWriter::AddCopy(uint64_t new_block, uint64_t old_block,
-                                       uint64_t num_blocks) {
-    return cow_->AddCopy(new_block, old_block, num_blocks);
-}
-
-bool CompressedSnapshotWriter::AddRawBlocks(uint64_t new_block_start, const void* data,
-                                            size_t size) {
-    return cow_->AddRawBlocks(new_block_start, data, size);
-}
-
-bool CompressedSnapshotWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size,
-                                            uint32_t old_block, uint16_t offset) {
-    return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
-}
-
-bool CompressedSnapshotWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
-    return cow_->AddZeroBlocks(new_block_start, num_blocks);
-}
-
-bool CompressedSnapshotWriter::AddLabel(uint64_t label) {
-    return cow_->AddLabel(label);
-}
-
-bool CompressedSnapshotWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
-    return cow_->AddSequenceData(num_ops, data);
-}
-
-bool CompressedSnapshotWriter::Initialize() {
-    unique_fd cow_fd(dup(cow_device_.get()));
-    if (cow_fd < 0) {
-        PLOG(ERROR) << "dup COW device";
-        return false;
-    }
-
-    auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
-    if (!cow->Initialize(std::nullopt)) {
-        return false;
-    }
-    cow_ = std::move(cow);
-    return true;
-}
-
-bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
-    unique_fd cow_fd(dup(cow_device_.get()));
-    if (cow_fd < 0) {
-        PLOG(ERROR) << "dup COW device";
-        return false;
-    }
-
-    auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
-    if (!cow->Initialize(label)) {
-        return false;
-    }
-    cow_ = std::move(cow);
-    return true;
-}
-
-uint32_t CompressedSnapshotWriter::GetBlockSize() const {
-    return cow_->GetBlockSize();
-}
-
-std::optional<uint32_t> CompressedSnapshotWriter::GetMaxBlocks() const {
-    return cow_->GetMaxBlocks();
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_writer_test.cpp b/fs_mgr/libsnapshot/snapshot_writer_test.cpp
deleted file mode 100644
index a03632b..0000000
--- a/fs_mgr/libsnapshot/snapshot_writer_test.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright (C) 2021 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.h>
-
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-#include <libsnapshot/snapshot_writer.h>
-#include <payload_consumer/file_descriptor.h>
-
-namespace android::snapshot {
-class CompressedSnapshotWriterTest : public ::testing::Test {
-  public:
-    static constexpr size_t BLOCK_SIZE = 4096;
-};
-
-TEST_F(CompressedSnapshotWriterTest, ReadAfterWrite) {
-    TemporaryFile cow_device_file{};
-    android::snapshot::CowOptions options{.block_size = BLOCK_SIZE};
-    android::snapshot::CompressedSnapshotWriter snapshot_writer{options};
-    ASSERT_TRUE(snapshot_writer.SetCowDevice(android::base::unique_fd{cow_device_file.fd}));
-    ASSERT_TRUE(snapshot_writer.Initialize());
-    std::vector<unsigned char> buffer;
-    buffer.resize(BLOCK_SIZE);
-    std::fill(buffer.begin(), buffer.end(), 123);
-
-    ASSERT_TRUE(snapshot_writer.AddRawBlocks(0, buffer.data(), buffer.size()));
-    ASSERT_TRUE(snapshot_writer.Finalize());
-    auto cow_reader = snapshot_writer.OpenReader();
-    ASSERT_NE(cow_reader, nullptr);
-    ASSERT_TRUE(snapshot_writer.AddRawBlocks(1, buffer.data(), buffer.size()));
-    ASSERT_TRUE(snapshot_writer.AddRawBlocks(2, buffer.data(), buffer.size()));
-    ASSERT_TRUE(snapshot_writer.Finalize());
-    // After wrigin some data, if we call OpenReader() again, writes should
-    // be visible to the newly opened reader. update_engine relies on this
-    // behavior for verity writes.
-    cow_reader = snapshot_writer.OpenReader();
-    ASSERT_NE(cow_reader, nullptr);
-    std::vector<unsigned char> read_back;
-    read_back.resize(buffer.size());
-    cow_reader->Seek(BLOCK_SIZE, SEEK_SET);
-    const auto bytes_read = cow_reader->Read(read_back.data(), read_back.size());
-    ASSERT_EQ((size_t)(bytes_read), BLOCK_SIZE);
-    ASSERT_EQ(read_back, buffer);
-}
-
-}  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index ad3f83c..38eb719 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -133,7 +133,6 @@
 
     // Write the "new" system partition.
     auto system_target_name = "system" + target_slot;
-    auto source_device = "/dev/block/mapper/" + system_source_name;
     CreateLogicalPartitionParams clpp = {
             .block_device = fs_mgr_get_super_partition_name(target_slot_number),
             .metadata_slot = {target_slot_number},
@@ -141,15 +140,11 @@
             .partition_opener = &opener,
             .timeout_ms = 10s,
     };
-    auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
+    auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt);
     if (!writer) {
         std::cerr << "Could not open snapshot writer.\n";
         return false;
     }
-    if (!writer->Initialize()) {
-        std::cerr << "Could not initialize snapshot for writing.\n";
-        return false;
-    }
 
     for (uint64_t block = 0; block < system_source_size / 4096; block++) {
         if (!writer->AddCopy(block, block)) {
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index a224f6b..2eac347 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -130,12 +130,7 @@
     return true;
 }
 
-std::string HashSnapshot(ISnapshotWriter* writer) {
-    auto reader = writer->OpenReader();
-    if (!reader) {
-        return {};
-    }
-
+std::string HashSnapshot(ICowWriter::FileDescriptor* reader) {
     SHA256_CTX ctx;
     SHA256_Init(&ctx);