Merge "libunwindstack: Support signal frame CIEs."
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 0b4a925..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-filegroup {
-    name: "android_filesystem_config_header",
-    srcs: ["include/private/android_filesystem_config.h"],
-}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index e6f9ffa..fe05553 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -126,7 +126,7 @@
     shared_libs: [
         "android.hardware.boot@1.0",
         "android.hardware.boot@1.1",
-        "android.hardware.fastboot@1.0",
+        "android.hardware.fastboot@1.1",
         "android.hardware.health@2.0",
         "libasyncio",
         "libbase",
@@ -147,7 +147,6 @@
     static_libs: [
         "libgtest_prod",
         "libhealthhalutils",
-        "libsnapshot_cow",
         "libsnapshot_nobinder",
         "update_metadata-protos",
     ],
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2553353..4601960 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -164,6 +164,28 @@
     return device->WriteOkay(message);
 }
 
+bool OemPostWipeData(FastbootDevice* device) {
+    auto fastboot_hal = device->fastboot_hal();
+    if (!fastboot_hal) {
+        return false;
+    }
+
+    Result ret;
+    auto ret_val = fastboot_hal->doOemSpecificErase([&](Result result) { ret = result; });
+    if (!ret_val.isOk()) {
+        return false;
+    }
+    if (ret.status == Status::NOT_SUPPORTED) {
+        return false;
+    } else if (ret.status != Status::SUCCESS) {
+        device->WriteStatus(FastbootResult::FAIL, ret.message);
+    } else {
+        device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+    }
+
+    return true;
+}
+
 bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
     if (args.size() < 2) {
         return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
@@ -184,7 +206,18 @@
         return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
     }
     if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
-        return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+        //Perform oem PostWipeData if Android userdata partition has been erased
+        bool support_oem_postwipedata = false;
+        if (partition_name == "userdata") {
+            support_oem_postwipedata = OemPostWipeData(device);
+        }
+
+        if (!support_oem_postwipedata) {
+            return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+        } else {
+            //Write device status in OemPostWipeData(), so just return true
+            return true;
+        }
     }
     return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
 }
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 1b0859f..52ea9f0 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -22,7 +22,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android/hardware/boot/1.0/IBootControl.h>
-#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
 #include <fs_mgr.h>
 #include <fs_mgr/roots.h>
 #include <healthhalutils/HealthHalUtils.h>
@@ -37,7 +37,7 @@
 using ::android::hardware::hidl_string;
 using ::android::hardware::boot::V1_0::IBootControl;
 using ::android::hardware::boot::V1_0::Slot;
-using ::android::hardware::fastboot::V1_0::IFastboot;
+using ::android::hardware::fastboot::V1_1::IFastboot;
 using ::android::hardware::health::V2_0::get_health_service;
 
 namespace sph = std::placeholders;
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index bbe8172..23be721 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -24,7 +24,7 @@
 
 #include <android/hardware/boot/1.0/IBootControl.h>
 #include <android/hardware/boot/1.1/IBootControl.h>
-#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
 #include <android/hardware/health/2.0/IHealth.h>
 
 #include "commands.h"
@@ -53,7 +53,7 @@
         return boot_control_hal_;
     }
     android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1() { return boot1_1_; }
-    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
+    android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal() {
         return fastboot_hal_;
     }
     android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
@@ -67,7 +67,7 @@
     android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
     android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1_;
     android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
-    android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
+    android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal_;
     std::vector<char> download_data_;
     std::string active_slot_;
 };
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 046ea74..db2e16c 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -74,11 +74,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",
@@ -163,6 +161,38 @@
     ramdisk_available: true,
 }
 
+cc_defaults {
+    name: "libsnapshot_snapuserd_defaults",
+    defaults: [
+        "fs_mgr_defaults",
+    ],
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "snapuserd_client.cpp",
+    ],
+}
+
+cc_library_static {
+    name: "libsnapshot_snapuserd",
+    defaults: [
+        "libsnapshot_snapuserd_defaults",
+    ],
+    recovery_available: true,
+    static_libs: [
+        "libcutils_sockets",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    ramdisk_available: true,
+}
+
 cc_library_static {
     name: "libsnapshot_test_helpers",
     defaults: ["libsnapshot_defaults"],
@@ -217,7 +247,6 @@
         "libgmock",
         "liblp",
         "libsnapshot",
-        "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libsparse",
     ],
@@ -252,7 +281,6 @@
     static_libs: [
         "libfstab",
         "libsnapshot",
-        "libsnapshot_cow",
         "update_metadata-protos",
     ],
     shared_libs: [
@@ -316,7 +344,6 @@
         "libgmock", // from libsnapshot_test_helpers
         "liblog",
         "liblp",
-        "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libprotobuf-mutator",
     ],
@@ -363,7 +390,9 @@
         "fs_mgr_defaults",
     ],
     srcs: [
+	"snapuserd_server.cpp",
         "snapuserd.cpp",
+	"snapuserd_daemon.cpp",
     ],
 
     cflags: [
@@ -374,6 +403,7 @@
     static_libs: [
         "libbase",
         "libbrotli",
+	"libcutils_sockets",
         "liblog",
         "libdm",
         "libz",
@@ -513,6 +543,8 @@
         "libbrotli",
         "libgtest",
         "libsnapshot_cow",
+	"libsnapshot_snapuserd",
+        "libcutils_sockets",
         "libz",
     ],
     header_libs: [
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 80acb4a..75e54f7 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -26,6 +26,7 @@
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 #include <libsnapshot/cow_writer.h>
+#include <libsnapshot/snapuserd_client.h>
 #include <storage_literals/storage_literals.h>
 
 namespace android {
@@ -43,17 +44,29 @@
         cow_product_ = std::make_unique<TemporaryFile>();
         ASSERT_GE(cow_product_->fd, 0) << strerror(errno);
 
+        cow_system_1_ = std::make_unique<TemporaryFile>();
+        ASSERT_GE(cow_system_1_->fd, 0) << strerror(errno);
+
+        cow_product_1_ = std::make_unique<TemporaryFile>();
+        ASSERT_GE(cow_product_1_->fd, 0) << strerror(errno);
+
         size_ = 100_MiB;
     }
 
     void TearDown() override {
         cow_system_ = nullptr;
         cow_product_ = nullptr;
+
+        cow_system_1_ = nullptr;
+        cow_product_1_ = nullptr;
     }
 
     std::unique_ptr<TemporaryFile> cow_system_;
     std::unique_ptr<TemporaryFile> cow_product_;
 
+    std::unique_ptr<TemporaryFile> cow_system_1_;
+    std::unique_ptr<TemporaryFile> cow_product_1_;
+
     unique_fd sys_fd_;
     unique_fd product_fd_;
     size_t size_;
@@ -71,12 +84,14 @@
 
     void Init();
     void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
-    void CreateSystemDmUser();
-    void CreateProductDmUser();
+    void CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow);
+    void CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow);
     void StartSnapuserdDaemon();
     void CreateSnapshotDevices();
+    void SwitchSnapshotDevices();
 
-    void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf);
+    void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer);
+    SnapuserdClient client_;
 };
 
 void SnapuserdTest::Init() {
@@ -112,7 +127,7 @@
     // Read from system partition from offset 0 of size 100MB
     ASSERT_EQ(ReadFullyAtOffset(sys_fd_, system_buffer_.get(), size_, 0), true);
 
-    // Read from system partition from offset 0 of size 100MB
+    // Read from product partition from offset 0 of size 100MB
     ASSERT_EQ(ReadFullyAtOffset(product_fd_, product_buffer_.get(), size_, 0), true);
 }
 
@@ -167,9 +182,10 @@
     ASSERT_EQ(lseek(cow->fd, 0, SEEK_SET), 0);
 }
 
-void SnapuserdTest::CreateSystemDmUser() {
+void SnapuserdTest::CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow) {
     unique_fd system_a_fd;
     std::string cmd;
+    system_device_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
@@ -180,7 +196,7 @@
     int err = ioctl(system_a_fd.get(), BLKGETSIZE, &system_blksize_);
     ASSERT_GE(err, 0);
 
-    std::string str(cow_system_->path);
+    std::string str(cow->path);
     std::size_t found = str.find_last_of("/\\");
     ASSERT_NE(found, std::string::npos);
     system_device_name_ = str.substr(found + 1);
@@ -189,9 +205,10 @@
     system(cmd.c_str());
 }
 
-void SnapuserdTest::CreateProductDmUser() {
+void SnapuserdTest::CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow) {
     unique_fd product_a_fd;
     std::string cmd;
+    product_device_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
@@ -202,7 +219,7 @@
     int err = ioctl(product_a_fd.get(), BLKGETSIZE, &product_blksize_);
     ASSERT_GE(err, 0);
 
-    std::string str(cow_product_->path);
+    std::string str(cow->path);
     std::size_t found = str.find_last_of("/\\");
     ASSERT_NE(found, std::string::npos);
     product_device_name_ = str.substr(found + 1);
@@ -212,15 +229,16 @@
 }
 
 void SnapuserdTest::StartSnapuserdDaemon() {
-    // Start the snapuserd daemon
-    if (fork() == 0) {
-        const char* argv[] = {"/system/bin/snapuserd",       cow_system_->path,
-                              "/dev/block/mapper/system_a",  cow_product_->path,
-                              "/dev/block/mapper/product_a", nullptr};
-        if (execv(argv[0], const_cast<char**>(argv))) {
-            ASSERT_TRUE(0);
-        }
-    }
+    int ret;
+
+    ret = client_.StartSnapuserd();
+    ASSERT_EQ(ret, 0);
+
+    ret = client_.InitializeSnapuserd(cow_system_->path, "/dev/block/mapper/system_a");
+    ASSERT_EQ(ret, 0);
+
+    ret = client_.InitializeSnapuserd(cow_product_->path, "/dev/block/mapper/product_a");
+    ASSERT_EQ(ret, 0);
 }
 
 void SnapuserdTest::CreateSnapshotDevices() {
@@ -243,9 +261,29 @@
     system(cmd.c_str());
 }
 
-void SnapuserdTest::TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf) {
+void SnapuserdTest::SwitchSnapshotDevices() {
+    std::string cmd;
+
+    cmd = "dmctl create system-snapshot-1 -ro snapshot 0 " + std::to_string(system_blksize_);
+    cmd += " /dev/block/mapper/system_a";
+    cmd += " /dev/block/mapper/" + system_device_name_;
+    cmd += " P 8";
+
+    system(cmd.c_str());
+
+    cmd.clear();
+
+    cmd = "dmctl create product-snapshot-1 -ro snapshot 0 " + std::to_string(product_blksize_);
+    cmd += " /dev/block/mapper/product_a";
+    cmd += " /dev/block/mapper/" + product_device_name_;
+    cmd += " P 8";
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer) {
     loff_t offset = 0;
-    std::unique_ptr<uint8_t[]> buffer = std::move(buf);
+    // std::unique_ptr<uint8_t[]> buffer = std::move(buf);
 
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
 
@@ -326,8 +364,8 @@
     CreateCowDevice(cow_system_);
     CreateCowDevice(cow_product_);
 
-    CreateSystemDmUser();
-    CreateProductDmUser();
+    CreateSystemDmUser(cow_system_);
+    CreateProductDmUser(cow_product_);
 
     StartSnapuserdDaemon();
 
@@ -335,11 +373,44 @@
 
     snapshot_fd.reset(open("/dev/block/mapper/system-snapshot", O_RDONLY));
     ASSERT_TRUE(snapshot_fd > 0);
-    TestIO(snapshot_fd, std::move(system_buffer_));
+    TestIO(snapshot_fd, system_buffer_);
 
     snapshot_fd.reset(open("/dev/block/mapper/product-snapshot", O_RDONLY));
     ASSERT_TRUE(snapshot_fd > 0);
-    TestIO(snapshot_fd, std::move(product_buffer_));
+    TestIO(snapshot_fd, product_buffer_);
+
+    // Sequence of operations for transition
+    CreateCowDevice(cow_system_1_);
+    CreateCowDevice(cow_product_1_);
+
+    CreateSystemDmUser(cow_system_1_);
+    CreateProductDmUser(cow_product_1_);
+
+    std::vector<std::pair<std::string, std::string>> vec;
+    vec.push_back(std::make_pair(cow_system_1_->path, "/dev/block/mapper/system_a"));
+    vec.push_back(std::make_pair(cow_product_1_->path, "/dev/block/mapper/product_a"));
+
+    // Start the second stage deamon and send the devices
+    ASSERT_EQ(client_.RestartSnapuserd(vec), 0);
+
+    // TODO: This is not switching snapshot device but creates a new table;
+    // however, it should serve the testing purpose.
+    SwitchSnapshotDevices();
+
+    // Stop the first stage daemon
+    ASSERT_EQ(client_.StopSnapuserd(true), 0);
+
+    // Test the IO again with the second stage daemon
+    snapshot_fd.reset(open("/dev/block/mapper/system-snapshot-1", O_RDONLY));
+    ASSERT_TRUE(snapshot_fd > 0);
+    TestIO(snapshot_fd, system_buffer_);
+
+    snapshot_fd.reset(open("/dev/block/mapper/product-snapshot-1", O_RDONLY));
+    ASSERT_TRUE(snapshot_fd > 0);
+    TestIO(snapshot_fd, product_buffer_);
+
+    // Stop the second stage daemon
+    ASSERT_EQ(client_.StopSnapuserd(false), 0);
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index f96f174..70fdac1 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -32,9 +32,6 @@
 
 static_assert(sizeof(off_t) == sizeof(uint64_t));
 
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
 bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
     if (!ValidateNewBlock(new_block)) {
         return false;
@@ -101,12 +98,12 @@
     return true;
 }
 
-bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
+bool CowWriter::Initialize(android::base::unique_fd&& fd, OpenMode mode) {
     owned_fd_ = std::move(fd);
-    return Initialize(borrowed_fd{owned_fd_}, mode);
+    return Initialize(android::base::borrowed_fd{owned_fd_}, mode);
 }
 
-bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
+bool CowWriter::Initialize(android::base::borrowed_fd fd, OpenMode mode) {
     fd_ = fd;
 
     if (!ParseOptions()) {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 2bc0171..245da0c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -58,9 +58,6 @@
     // Return number of bytes the cow image occupies on disk.
     virtual uint64_t GetCowSize() = 0;
 
-    // Returns true if AddCopy() operations are supported.
-    virtual bool SupportsCopyOperation() const { return true; }
-
     const CowOptions& options() { return options_; }
 
   protected:
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 13f19aa..eb6ad05 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -38,7 +38,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), (override));
+    MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenSnapshotReader,
                 (const android::fs_mgr::CreateLogicalPartitionParams& params), (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 1bc972e..6fef58a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -35,8 +35,8 @@
 #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>
 
 #ifndef FRIEND_TEST
 #define FRIEND_TEST(test_set_name, individual_test) \
@@ -44,6 +44,10 @@
 #define DEFINED_FRIEND_TEST
 #endif
 
+namespace chromeos_update_engine {
+class FileDescriptor;
+}  // namespace chromeos_update_engine
+
 namespace android {
 
 namespace fiemap {
@@ -106,6 +110,8 @@
     };
     virtual ~ISnapshotManager() = default;
 
+    using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
     // Begin an update. This must be called before creating any snapshots. It
     // will fail if GetUpdateState() != None.
     virtual bool BeginUpdate() = 0;
@@ -181,14 +187,19 @@
     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
-    // must be suffixed.
-    virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+    // Create an ICowWriter to build a snapshot against a target partition. The partition name must
+    // be suffixed.
+    virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
+            const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
+
+    // Open a snapshot for reading. A file-like interface is provided through the FileDescriptor.
+    // In this mode, writes are not supported. The partition name must be suffixed.
+    virtual std::unique_ptr<FileDescriptor> OpenSnapshotReader(
             const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
 
     // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
-    // OpenSnapshotWriter. All outstanding open descriptors, writers, or
-    // readers must be deleted before this is called.
+    // OpenSnapshotWriter, or OpenSnapshotReader. All outstanding open descriptors, writers,
+    // or readers must be deleted before this is called.
     virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;
 
     // If this returns true, first-stage mount must call
@@ -299,7 +310,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) override;
+    std::unique_ptr<FileDescriptor> OpenSnapshotReader(
             const android::fs_mgr::CreateLogicalPartitionParams& params) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
@@ -519,39 +532,9 @@
     std::string GetSnapshotDeviceName(const std::string& snapshot_name,
                                       const SnapshotStatus& status);
 
-    // Reason for calling MapPartitionWithSnapshot.
-    enum class SnapshotContext {
-        // For writing or verification (during update_engine).
-        Update,
-
-        // For mounting a full readable device.
-        Mount,
-    };
-
-    struct SnapshotPaths {
-        // Target/base device (eg system_b), always present.
-        std::string target_device;
-
-        // COW path (eg system_cow). Not present if no COW is needed.
-        std::string cow_device;
-
-        // dm-snapshot instance. Not present in Update mode for VABC.
-        std::string snapshot_device;
-    };
-
-    // Helpers for OpenSnapshotWriter.
-    std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
-                                                                  const std::string& partition_name,
-                                                                  const SnapshotStatus& status,
-                                                                  const SnapshotPaths& paths);
-    std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(LockedFile* lock,
-                                                              const std::string& partition_name,
-                                                              const SnapshotStatus& status,
-                                                              const SnapshotPaths& paths);
-
     // Map the base device, COW devices, and snapshot device.
     bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
-                                  SnapshotContext context, SnapshotPaths* paths);
+                                  std::string* path);
 
     // Map the COW devices, including the partition in super and the images.
     // |params|:
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index cda2bee..149f463 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -36,7 +36,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) override;
+    std::unique_ptr<FileDescriptor> OpenSnapshotReader(
             const android::fs_mgr::CreateLogicalPartitionParams& params) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
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 bf57a00..0000000
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ /dev/null
@@ -1,68 +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 <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;
-
-    explicit ISnapshotWriter(const 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).
-    void SetSourceDevice(android::base::unique_fd&& source_fd);
-
-    virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
-
-  protected:
-    android::base::unique_fd source_fd_;
-};
-
-// Write directly to a dm-snapshot device.
-class OnlineKernelSnapshotWriter : public ISnapshotWriter {
-  public:
-    OnlineKernelSnapshotWriter(const CowOptions& options);
-
-    // Set the device used for all writes.
-    void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);
-
-    bool Flush() override;
-    uint64_t GetCowSize() override { return cow_size_; }
-    virtual std::unique_ptr<FileDescriptor> OpenReader() override;
-
-  protected:
-    bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
-    bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
-    bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
-
-  private:
-    android::base::unique_fd snapshot_fd_;
-    uint64_t cow_size_ = 0;
-};
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
index e757579..6331edb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -14,85 +14,94 @@
 
 #pragma once
 
+#include <linux/types.h>
 #include <stdint.h>
+#include <stdlib.h>
+
+#include <csignal>
+#include <cstring>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <libdm/dm.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+#include <libsnapshot/snapuserd_kernel.h>
 
 namespace android {
 namespace snapshot {
 
-// Kernel COW header fields
-static constexpr uint32_t SNAP_MAGIC = 0x70416e53;
+using android::base::unique_fd;
 
-static constexpr uint32_t SNAPSHOT_DISK_VERSION = 1;
+class BufferSink : public IByteSink {
+  public:
+    void Initialize(size_t size);
+    void* GetBufPtr() { return buffer_.get(); }
+    void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
+    void* GetPayloadBuffer(size_t size);
+    void* GetBuffer(size_t requested, size_t* actual) override;
+    void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
+    struct dm_user_header* GetHeaderPtr();
+    bool ReturnData(void*, size_t) override { return true; }
+    void ResetBufferOffset() { buffer_offset_ = 0; }
 
-static constexpr uint32_t NUM_SNAPSHOT_HDR_CHUNKS = 1;
-
-static constexpr uint32_t SNAPSHOT_VALID = 1;
-
-/*
- * The basic unit of block I/O is a sector. It is used in a number of contexts
- * in Linux (blk, bio, genhd). The size of one sector is 512 = 2**9
- * bytes. Variables of type sector_t represent an offset or size that is a
- * multiple of 512 bytes. Hence these two constants.
- */
-static constexpr uint32_t SECTOR_SHIFT = 9;
-
-typedef __u64 sector_t;
-typedef sector_t chunk_t;
-
-static constexpr uint32_t CHUNK_SIZE = 8;
-static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1);
-
-static constexpr uint32_t BLOCK_SIZE = 4096;
-static constexpr uint32_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SIZE) - 1);
-
-// This structure represents the kernel COW header.
-// All the below fields should be in Little Endian format.
-struct disk_header {
-    uint32_t magic;
-
-    /*
-     * Is this snapshot valid.  There is no way of recovering
-     * an invalid snapshot.
-     */
-    uint32_t valid;
-
-    /*
-     * Simple, incrementing version. no backward
-     * compatibility.
-     */
-    uint32_t version;
-
-    /* In sectors */
-    uint32_t chunk_size;
-} __packed;
-
-// A disk exception is a mapping of old_chunk to new_chunk
-// old_chunk is the chunk ID of a dm-snapshot device.
-// new_chunk is the chunk ID of the COW device.
-struct disk_exception {
-    uint64_t old_chunk;
-    uint64_t new_chunk;
-} __packed;
-
-// Control structures to communicate with dm-user
-// It comprises of header and a payload
-struct dm_user_header {
-    __u64 seq;
-    __u64 type;
-    __u64 flags;
-    __u64 sector;
-    __u64 len;
-    __u64 io_in_progress;
-} __attribute__((packed));
-
-struct dm_user_payload {
-    __u8 buf[];
+  private:
+    std::unique_ptr<uint8_t[]> buffer_;
+    loff_t buffer_offset_;
+    size_t buffer_size_;
 };
 
-// Message comprising both header and payload
-struct dm_user_message {
-    struct dm_user_header header;
-    struct dm_user_payload payload;
+class Snapuserd final {
+  public:
+    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device)
+        : cow_device_(in_cow_device),
+          backing_store_device_(in_backing_store_device),
+          metadata_read_done_(false) {}
+
+    int Init();
+    int Run();
+    int ReadDmUserHeader();
+    int WriteDmUserPayload(size_t size);
+    int ConstructKernelCowHeader();
+    int ReadMetadata();
+    int ZerofillDiskExceptions(size_t read_size);
+    int ReadDiskExceptions(chunk_t chunk, size_t size);
+    int ReadData(chunk_t chunk, size_t size);
+
+  private:
+    int ProcessReplaceOp(const CowOperation* cow_op);
+    int ProcessCopyOp(const CowOperation* cow_op);
+    int ProcessZeroOp();
+
+    std::string cow_device_;
+    std::string backing_store_device_;
+
+    unique_fd cow_fd_;
+    unique_fd backing_store_fd_;
+    unique_fd ctrl_fd_;
+
+    uint32_t exceptions_per_area_;
+
+    std::unique_ptr<ICowOpIter> cowop_iter_;
+    std::unique_ptr<CowReader> reader_;
+
+    // Vector of disk exception which is a
+    // mapping of old-chunk to new-chunk
+    std::vector<std::unique_ptr<uint8_t[]>> vec_;
+
+    // Index - Chunk ID
+    // Value - cow operation
+    std::vector<const CowOperation*> chunk_vec_;
+
+    bool metadata_read_done_;
+    BufferSink bufsink_;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
new file mode 100644
index 0000000..2d9d729
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -0,0 +1,73 @@
+// 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 <arpa/inet.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace snapshot {
+
+static constexpr uint32_t PACKET_SIZE = 512;
+static constexpr uint32_t MAX_CONNECT_RETRY_COUNT = 10;
+
+class SnapuserdClient {
+  private:
+    int sockfd_ = 0;
+
+    int Sendmsg(const char* msg, size_t size);
+    std::string Receivemsg();
+    int StartSnapuserdaemon(std::string socketname);
+    bool ConnectToServerSocket(std::string socketname);
+    bool ConnectToServer();
+
+    void DisconnectFromServer() { close(sockfd_); }
+
+    std::string GetSocketNameFirstStage() {
+        static std::string snapd_one("snapdone");
+        return snapd_one;
+    }
+
+    std::string GetSocketNameSecondStage() {
+        static std::string snapd_two("snapdtwo");
+        return snapd_two;
+    }
+
+  public:
+    int StartSnapuserd();
+    int StopSnapuserd(bool firstStageDaemon);
+    int RestartSnapuserd(std::vector<std::pair<std::string, std::string>>& vec);
+    int InitializeSnapuserd(std::string cow_device, std::string backing_device);
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h
new file mode 100644
index 0000000..c0d3c5e
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <libsnapshot/snapuserd_server.h>
+
+namespace android {
+namespace snapshot {
+
+class Daemon {
+    // The Daemon class is a singleton to avoid
+    // instantiating more than once
+  public:
+    static Daemon& Instance() {
+        static Daemon instance;
+        return instance;
+    }
+
+    int StartServer(std::string socketname);
+    bool IsRunning();
+    void Run();
+
+  private:
+    bool is_running_;
+
+    Daemon();
+    Daemon(Daemon const&) = delete;
+    void operator=(Daemon const&) = delete;
+
+    SnapuserdServer server_;
+    static void SignalHandler(int signal);
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
new file mode 100644
index 0000000..1a6ba8f
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -0,0 +1,97 @@
+// 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
+
+namespace android {
+namespace snapshot {
+
+// Kernel COW header fields
+static constexpr uint32_t SNAP_MAGIC = 0x70416e53;
+
+static constexpr uint32_t SNAPSHOT_DISK_VERSION = 1;
+
+static constexpr uint32_t NUM_SNAPSHOT_HDR_CHUNKS = 1;
+
+static constexpr uint32_t SNAPSHOT_VALID = 1;
+
+/*
+ * The basic unit of block I/O is a sector. It is used in a number of contexts
+ * in Linux (blk, bio, genhd). The size of one sector is 512 = 2**9
+ * bytes. Variables of type sector_t represent an offset or size that is a
+ * multiple of 512 bytes. Hence these two constants.
+ */
+static constexpr uint32_t SECTOR_SHIFT = 9;
+
+typedef __u64 sector_t;
+typedef sector_t chunk_t;
+
+static constexpr uint32_t CHUNK_SIZE = 8;
+static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1);
+
+static constexpr uint32_t BLOCK_SIZE = 4096;
+static constexpr uint32_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SIZE) - 1);
+
+// This structure represents the kernel COW header.
+// All the below fields should be in Little Endian format.
+struct disk_header {
+    uint32_t magic;
+
+    /*
+     * Is this snapshot valid.  There is no way of recovering
+     * an invalid snapshot.
+     */
+    uint32_t valid;
+
+    /*
+     * Simple, incrementing version. no backward
+     * compatibility.
+     */
+    uint32_t version;
+
+    /* In sectors */
+    uint32_t chunk_size;
+} __packed;
+
+// A disk exception is a mapping of old_chunk to new_chunk
+// old_chunk is the chunk ID of a dm-snapshot device.
+// new_chunk is the chunk ID of the COW device.
+struct disk_exception {
+    uint64_t old_chunk;
+    uint64_t new_chunk;
+} __packed;
+
+// Control structures to communicate with dm-user
+// It comprises of header and a payload
+struct dm_user_header {
+    __u64 seq;
+    __u64 type;
+    __u64 flags;
+    __u64 sector;
+    __u64 len;
+    __u64 io_in_progress;
+} __attribute__((packed));
+
+struct dm_user_payload {
+    __u8 buf[];
+};
+
+// Message comprising both header and payload
+struct dm_user_message {
+    struct dm_user_header header;
+    struct dm_user_payload payload;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
new file mode 100644
index 0000000..79b883a
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
@@ -0,0 +1,115 @@
+// 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 <stdint.h>
+
+#include <arpa/inet.h>
+#include <cutils/sockets.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <cstdio>
+#include <cstring>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace snapshot {
+
+static constexpr uint32_t MAX_PACKET_SIZE = 512;
+
+enum class DaemonOperations {
+    START,
+    QUERY,
+    TERMINATING,
+    STOP,
+    INVALID,
+};
+
+class Client {
+  private:
+    std::unique_ptr<std::thread> threadHandler_;
+
+  public:
+    void SetThreadHandler(std::function<void(void)> func) {
+        threadHandler_ = std::make_unique<std::thread>(func);
+    }
+
+    std::unique_ptr<std::thread>& GetThreadHandler() { return threadHandler_; }
+};
+
+class Stoppable {
+    std::promise<void> exitSignal_;
+    std::future<void> futureObj_;
+
+  public:
+    Stoppable() : futureObj_(exitSignal_.get_future()) {}
+
+    virtual ~Stoppable() {}
+
+    virtual void ThreadStart(std::string cow_device, std::string backing_device) = 0;
+
+    bool StopRequested() {
+        // checks if value in future object is available
+        if (futureObj_.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout)
+            return false;
+        return true;
+    }
+    // Request the thread to stop by setting value in promise object
+    void StopThreads() { exitSignal_.set_value(); }
+};
+
+class SnapuserdServer : public Stoppable {
+  private:
+    android::base::unique_fd sockfd_;
+    bool terminating_;
+    std::vector<std::unique_ptr<Client>> clients_vec_;
+    void ThreadStart(std::string cow_device, std::string backing_device) override;
+    void ShutdownThreads();
+    DaemonOperations Resolveop(std::string& input);
+    std::string GetDaemonStatus();
+    void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
+
+    void SetTerminating() { terminating_ = true; }
+
+    bool IsTerminating() { return terminating_; }
+
+  public:
+    ~SnapuserdServer() { clients_vec_.clear(); }
+
+    SnapuserdServer() { terminating_ = false; }
+
+    int Start(std::string socketname);
+    int AcceptClient();
+    int Receivemsg(int fd);
+    int Sendmsg(int fd, char* msg, size_t len);
+    std::string Recvmsg(int fd, int* ret);
+};
+
+}  // 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 197aeaa..8e369b0 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -144,7 +144,6 @@
 // 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);
-bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);
 
 std::optional<std::string> GetHash(const std::string& path);
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b672d0e..0904fc7 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -15,7 +15,6 @@
 #include <libsnapshot/snapshot.h>
 
 #include <dirent.h>
-#include <fcntl.h>
 #include <math.h>
 #include <sys/file.h>
 #include <sys/types.h>
@@ -44,7 +43,6 @@
 #include "device_info.h"
 #include "partition_cow_creator.h"
 #include "snapshot_metadata_updater.h"
-#include "snapshot_reader.h"
 #include "utility.h"
 
 namespace android {
@@ -1572,8 +1570,7 @@
                 .timeout_ms = timeout_ms,
         };
         std::string ignore_path;
-        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
-                                      nullptr)) {
+        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) {
             return false;
         }
     }
@@ -1601,10 +1598,11 @@
 
 bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
                                                CreateLogicalPartitionParams params,
-                                               SnapshotContext context, SnapshotPaths* paths) {
+                                               std::string* path) {
     auto begin = std::chrono::steady_clock::now();
 
     CHECK(lock);
+    path->clear();
 
     if (params.GetPartitionName() != params.GetDeviceName()) {
         LOG(ERROR) << "Mapping snapshot with a different name is unsupported: partition_name = "
@@ -1685,11 +1683,8 @@
     }
     created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
 
-    if (paths) {
-        paths->target_device = base_path;
-    }
-
     if (!live_snapshot_status.has_value()) {
+        *path = base_path;
         created_devices.Release();
         return true;
     }
@@ -1716,33 +1711,21 @@
         LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
         return false;
     }
-    if (paths) {
-        paths->cow_device = cow_device;
-    }
 
     remaining_time = GetRemainingTime(params.timeout_ms, begin);
     if (remaining_time.count() < 0) return false;
 
-    if (context == SnapshotContext::Update && IsCompressionEnabled()) {
-        // Stop here, we can't run dm-user yet, the COW isn't built.
-        return true;
-    }
-
-    std::string path;
     if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
-                     &path)) {
+                     path)) {
         LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
         return false;
     }
     // No need to add params.GetPartitionName() to created_devices since it is immediately released.
 
-    if (paths) {
-        paths->snapshot_device = path;
-    }
-
     created_devices.Release();
 
-    LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
+    LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
+
     return true;
 }
 
@@ -2455,86 +2438,23 @@
                    << params.GetPartitionName();
         return false;
     }
-
-    SnapshotPaths paths;
-    if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
-        return false;
-    }
-
-    if (paths.snapshot_device.empty()) {
-        *snapshot_path = paths.snapshot_device;
-    } else {
-        *snapshot_path = paths.target_device;
-    }
-    return true;
+    return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
 }
 
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
+std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
         const android::fs_mgr::CreateLogicalPartitionParams& params) {
-    // First unmap any existing mapping.
-    auto lock = LockShared();
-    if (!lock) return nullptr;
-    if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
-        LOG(ERROR) << "Cannot unmap existing snapshot before re-mapping it: "
-                   << params.GetPartitionName();
-        return nullptr;
-    }
+    (void)params;
 
-    SnapshotPaths paths;
-    if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
-        return nullptr;
-    }
-
-    SnapshotStatus status;
-    if (!paths.cow_device.empty()) {
-        if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
-            return nullptr;
-        }
-    } else {
-        // Currently, partition_cow_creator always creates snapshots. The
-        // reason is that if partition X shrinks while partition Y grows, we
-        // cannot bindly write to the newly freed extents in X. This would
-        // make the old slot unusable. So, the entire size of the target
-        // partition is currently considered snapshottable.
-        LOG(ERROR) << "No snapshot available for partition " << params.GetPartitionName();
-        return nullptr;
-    }
-
-    if (IsCompressionEnabled()) {
-        return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
-    } else {
-        return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
-    }
-}
-
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
-        LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
-    LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
+    LOG(ERROR) << "OpenSnapshotWriter not yet implemented";
     return nullptr;
 }
 
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
-        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
-        const SnapshotStatus& status, const SnapshotPaths& paths) {
-    CHECK(lock);
+std::unique_ptr<FileDescriptor> SnapshotManager::OpenSnapshotReader(
+        const android::fs_mgr::CreateLogicalPartitionParams& params) {
+    (void)params;
 
-    CowOptions cow_options;
-    cow_options.max_blocks = {status.device_size() / cow_options.block_size};
-
-    auto writer = std::make_unique<OnlineKernelSnapshotWriter>(cow_options);
-
-    std::string_view path =
-            paths.snapshot_device.empty() ? paths.target_device : paths.snapshot_device;
-    unique_fd fd(open(path.data(), O_RDWR | O_CLOEXEC));
-    if (fd < 0) {
-        PLOG(ERROR) << "open failed: " << path;
-        return nullptr;
-    }
-
-    uint64_t cow_size = status.cow_partition_size() + status.cow_file_size();
-    writer->SetSnapshotDevice(std::move(fd), cow_size);
-
-    return writer;
+    LOG(ERROR) << "OpenSnapshotReader not yet implemented";
+    return nullptr;
 }
 
 bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
deleted file mode 100644
index 0d47468..0000000
--- a/fs_mgr/libsnapshot/snapshot_reader.cpp
+++ /dev/null
@@ -1,77 +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 <ext4_utils/ext4_utils.h>
-
-#include "snapshot_reader.h"
-
-namespace android {
-namespace snapshot {
-
-// 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;
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/snapshot_reader.h
deleted file mode 100644
index 1f2ffe2..0000000
--- a/fs_mgr/libsnapshot/snapshot_reader.h
+++ /dev/null
@@ -1,50 +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 <android-base/file.h>
-#include <payload_consumer/file_descriptor.h>
-
-namespace android {
-namespace snapshot {
-
-class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
-  public:
-    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_;
-};
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 41f5da4..8ae6305 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -130,7 +130,13 @@
     return &snapshot_merge_stats;
 }
 
-std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
+std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(
+        const CreateLogicalPartitionParams&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return nullptr;
+}
+
+std::unique_ptr<FileDescriptor> SnapshotManagerStub::OpenSnapshotReader(
         const CreateLogicalPartitionParams&) {
     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 f2caaa4..6ff935b 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -80,7 +80,6 @@
 std::string fake_super;
 
 void MountMetadata();
-bool IsCompressionEnabled();
 
 class SnapshotTest : public ::testing::Test {
   public:
@@ -893,39 +892,42 @@
         return AssertionSuccess();
     }
 
-    AssertionResult MapUpdateSnapshot(const std::string& name,
-                                      std::unique_ptr<ICowWriter>* writer = nullptr) {
-        CreateLogicalPartitionParams params{
-                .block_device = fake_super,
-                .metadata_slot = 1,
-                .partition_name = name,
-                .timeout_ms = 10s,
-                .partition_opener = opener_.get(),
-        };
-
-        auto result = sm->OpenSnapshotWriter(params);
-        if (!result) {
-            return AssertionFailure() << "Cannot open snapshot for writing: " << name;
+    AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path = nullptr) {
+        std::string real_path;
+        if (!sm->MapUpdateSnapshot(
+                    CreateLogicalPartitionParams{
+                            .block_device = fake_super,
+                            .metadata_slot = 1,
+                            .partition_name = name,
+                            .timeout_ms = 10s,
+                            .partition_opener = opener_.get(),
+                    },
+                    &real_path)) {
+            return AssertionFailure() << "Unable to map snapshot " << name;
         }
-
-        if (writer) {
-            *writer = std::move(result);
+        if (path) {
+            *path = real_path;
         }
-        return AssertionSuccess();
+        return AssertionSuccess() << "Mapped snapshot " << name << " to " << real_path;
     }
 
-    AssertionResult WriteSnapshotAndHash(const std::string& name) {
-        std::unique_ptr<ICowWriter> writer;
-        auto res = MapUpdateSnapshot(name, &writer);
+    AssertionResult WriteSnapshotAndHash(const std::string& name,
+                                         std::optional<size_t> size = std::nullopt) {
+        std::string path;
+        auto res = MapUpdateSnapshot(name, &path);
         if (!res) {
             return res;
         }
 
-        if (!WriteRandomData(writer.get(), &hashes_[name])) {
-            return AssertionFailure() << "Unable to write random data to snapshot " << name;
+        std::string size_string = size ? (std::to_string(*size) + " bytes") : "";
+
+        if (!WriteRandomData(path, size, &hashes_[name])) {
+            return AssertionFailure() << "Unable to write " << size_string << " to " << path
+                                      << " for partition " << name;
         }
 
-        return AssertionSuccess() << "Written random data to snapshot " << name
+        return AssertionSuccess() << "Written " << size_string << " to " << path
+                                  << " for snapshot partition " << name
                                   << ", hash: " << hashes_[name];
     }
 
@@ -1001,7 +1003,7 @@
 
     // Write some data to target partitions.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
-        ASSERT_TRUE(WriteSnapshotAndHash(name));
+        ASSERT_TRUE(WriteSnapshotAndHash(name, partition_size));
     }
 
     // Assert that source partitions aren't affected.
@@ -1404,10 +1406,6 @@
     MetadataMountedTest().TearDown();
 }
 
-bool IsCompressionEnabled() {
-    return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
-}
-
 TEST_F(MetadataMountedTest, Android) {
     auto device = sm->EnsureMetadataMounted();
     EXPECT_NE(nullptr, device);
@@ -1625,7 +1623,7 @@
 
     // Map and write some data to target partition.
     ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
-    ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+    ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
 
     // Finish update.
     ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
@@ -1657,7 +1655,7 @@
 
     // Map and write some data to target partitions.
     ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
-    ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+    ASSERT_TRUE(WriteSnapshotAndHash("sys_b", actual_write_size));
 
     std::vector<android::dm::DeviceMapper::TargetInfo> table;
     ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
deleted file mode 100644
index 584f15e..0000000
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ /dev/null
@@ -1,97 +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 "snapshot_reader.h"
-
-namespace android {
-namespace snapshot {
-
-using android::base::unique_fd;
-using chromeos_update_engine::FileDescriptor;
-
-ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
-
-void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
-    source_fd_ = std::move(source_fd);
-}
-
-OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
-    : ISnapshotWriter(options) {}
-
-void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
-                                                   uint64_t cow_size) {
-    snapshot_fd_ = std::move(snapshot_fd);
-    cow_size_ = cow_size;
-}
-
-bool OnlineKernelSnapshotWriter::Flush() {
-    if (fsync(snapshot_fd_.get()) < 0) {
-        PLOG(ERROR) << "fsync";
-        return false;
-    }
-    return true;
-}
-
-bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
-                                               size_t size) {
-    uint64_t offset = new_block_start * options_.block_size;
-    if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
-        PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
-        return false;
-    }
-    if (!android::base::WriteFully(snapshot_fd_, data, size)) {
-        PLOG(ERROR) << "EmitRawBlocks write";
-        return false;
-    }
-    return true;
-}
-
-bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
-    std::string zeroes(options_.block_size, 0);
-    for (uint64_t i = 0; i < num_blocks; i++) {
-        if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
-    std::string buffer(options_.block_size, 0);
-    uint64_t offset = old_block * options_.block_size;
-    if (!android::base::ReadFullyAtOffset(source_fd_, buffer.data(), buffer.size(), offset)) {
-        PLOG(ERROR) << "EmitCopy read";
-        return false;
-    }
-    return EmitRawBlocks(new_block, buffer.data(), buffer.size());
-}
-
-std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
-    unique_fd fd(dup(snapshot_fd_.get()));
-    if (fd < 0) {
-        PLOG(ERROR) << "dup2 failed in OpenReader";
-        return nullptr;
-    }
-    return std::make_unique<ReadFdFileDescriptor>(std::move(fd));
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index d3f4f70..34481b7 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -14,25 +14,11 @@
  * limitations under the License.
  */
 
-#include <linux/types.h>
-#include <stdlib.h>
-
 #include <csignal>
-#include <cstring>
-#include <iostream>
-#include <limits>
-#include <string>
-#include <thread>
-#include <vector>
 
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <libdm/dm.h>
-#include <libsnapshot/cow_reader.h>
-#include <libsnapshot/cow_writer.h>
 #include <libsnapshot/snapuserd.h>
+#include <libsnapshot/snapuserd_daemon.h>
+#include <libsnapshot/snapuserd_server.h>
 
 namespace android {
 namespace snapshot {
@@ -60,140 +46,36 @@
     const std::string uuid_;
 };
 
-class Daemon {
-    // The Daemon class is a singleton to avoid
-    // instantiating more than once
-  public:
-    static Daemon& Instance() {
-        static Daemon instance;
-        return instance;
-    }
-
-    bool IsRunning();
-
-  private:
-    bool is_running_;
-
-    Daemon();
-    Daemon(Daemon const&) = delete;
-    void operator=(Daemon const&) = delete;
-
-    static void SignalHandler(int signal);
-};
-
-Daemon::Daemon() {
-    is_running_ = true;
-    signal(SIGINT, Daemon::SignalHandler);
-    signal(SIGTERM, Daemon::SignalHandler);
+void BufferSink::Initialize(size_t size) {
+    buffer_size_ = size;
+    buffer_offset_ = 0;
+    buffer_ = std::make_unique<uint8_t[]>(size);
 }
 
-bool Daemon::IsRunning() {
-    return is_running_;
+void* BufferSink::GetPayloadBuffer(size_t size) {
+    if ((buffer_size_ - buffer_offset_) < size) return nullptr;
+
+    char* buffer = reinterpret_cast<char*>(GetBufPtr());
+    struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+    return (char*)msg->payload.buf + buffer_offset_;
 }
 
-void Daemon::SignalHandler(int signal) {
-    LOG(DEBUG) << "Snapuserd received signal: " << signal;
-    switch (signal) {
-        case SIGINT:
-        case SIGTERM: {
-            Daemon::Instance().is_running_ = false;
-            break;
-        }
+void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
+    void* buf = GetPayloadBuffer(requested);
+    if (!buf) {
+        *actual = 0;
+        return nullptr;
     }
+    *actual = requested;
+    return buf;
 }
 
-class BufferSink : public IByteSink {
-  public:
-    void Initialize(size_t size) {
-        buffer_size_ = size;
-        buffer_offset_ = 0;
-        buffer_ = std::make_unique<uint8_t[]>(size);
-    }
-
-    void* GetBufPtr() { return buffer_.get(); }
-
-    void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
-
-    void* GetPayloadBuffer(size_t size) {
-        if ((buffer_size_ - buffer_offset_) < size) return nullptr;
-
-        char* buffer = reinterpret_cast<char*>(GetBufPtr());
-        struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-        return (char*)msg->payload.buf + buffer_offset_;
-    }
-
-    void* GetBuffer(size_t requested, size_t* actual) override {
-        void* buf = GetPayloadBuffer(requested);
-        if (!buf) {
-            *actual = 0;
-            return nullptr;
-        }
-        *actual = requested;
-        return buf;
-    }
-
-    void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
-
-    struct dm_user_header* GetHeaderPtr() {
-        CHECK(sizeof(struct dm_user_header) <= buffer_size_);
-        char* buf = reinterpret_cast<char*>(GetBufPtr());
-        struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
-        return header;
-    }
-
-    bool ReturnData(void*, size_t) override { return true; }
-    void ResetBufferOffset() { buffer_offset_ = 0; }
-
-  private:
-    std::unique_ptr<uint8_t[]> buffer_;
-    loff_t buffer_offset_;
-    size_t buffer_size_;
-};
-
-class Snapuserd final {
-  public:
-    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device)
-        : in_cow_device_(in_cow_device),
-          in_backing_store_device_(in_backing_store_device),
-          metadata_read_done_(false) {}
-
-    int Run();
-    int ReadDmUserHeader();
-    int WriteDmUserPayload(size_t size);
-    int ConstructKernelCowHeader();
-    int ReadMetadata();
-    int ZerofillDiskExceptions(size_t read_size);
-    int ReadDiskExceptions(chunk_t chunk, size_t size);
-    int ReadData(chunk_t chunk, size_t size);
-
-  private:
-    int ProcessReplaceOp(const CowOperation* cow_op);
-    int ProcessCopyOp(const CowOperation* cow_op);
-    int ProcessZeroOp();
-
-    std::string in_cow_device_;
-    std::string in_backing_store_device_;
-
-    unique_fd cow_fd_;
-    unique_fd backing_store_fd_;
-    unique_fd ctrl_fd_;
-
-    uint32_t exceptions_per_area_;
-
-    std::unique_ptr<ICowOpIter> cowop_iter_;
-    std::unique_ptr<CowReader> reader_;
-
-    // Vector of disk exception which is a
-    // mapping of old-chunk to new-chunk
-    std::vector<std::unique_ptr<uint8_t[]>> vec_;
-
-    // Index - Chunk ID
-    // Value - cow operation
-    std::vector<const CowOperation*> chunk_vec_;
-
-    bool metadata_read_done_;
-    BufferSink bufsink_;
-};
+struct dm_user_header* BufferSink::GetHeaderPtr() {
+    CHECK(sizeof(struct dm_user_header) <= buffer_size_);
+    char* buf = reinterpret_cast<char*>(GetBufPtr());
+    struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
+    return header;
+}
 
 // Construct kernel COW header in memory
 // This header will be in sector 0. The IO
@@ -581,9 +463,12 @@
 // Read Header from dm-user misc device. This gives
 // us the sector number for which IO is issued by dm-snapshot device
 int Snapuserd::ReadDmUserHeader() {
-    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
-        PLOG(ERROR) << "Control read failed";
-        return -1;
+    int ret;
+
+    ret = read(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header));
+    if (ret < 0) {
+        PLOG(ERROR) << "Control-read failed with: " << ret;
+        return ret;
     }
 
     return sizeof(struct dm_user_header);
@@ -600,22 +485,20 @@
     return sizeof(struct dm_user_header) + size;
 }
 
-// Start the daemon.
-// TODO: Handle signals
-int Snapuserd::Run() {
-    backing_store_fd_.reset(open(in_backing_store_device_.c_str(), O_RDONLY));
+int Snapuserd::Init() {
+    backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
     if (backing_store_fd_ < 0) {
-        LOG(ERROR) << "Open Failed: " << in_backing_store_device_;
+        LOG(ERROR) << "Open Failed: " << backing_store_device_;
         return 1;
     }
 
-    cow_fd_.reset(open(in_cow_device_.c_str(), O_RDWR));
+    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
     if (cow_fd_ < 0) {
-        LOG(ERROR) << "Open Failed: " << in_cow_device_;
+        LOG(ERROR) << "Open Failed: " << cow_device_;
         return 1;
     }
 
-    std::string str(in_cow_device_);
+    std::string str(cow_device_);
     std::size_t found = str.find_last_of("/\\");
     CHECK(found != std::string::npos);
     std::string device_name = str.substr(found + 1);
@@ -625,7 +508,7 @@
     auto& dm = dm::DeviceMapper::Instance();
     std::string uuid;
     if (!dm.GetDmDeviceUuidByName(device_name, &uuid)) {
-        LOG(ERROR) << "Unable to find UUID for " << in_cow_device_;
+        LOG(ERROR) << "Unable to find UUID for " << cow_device_;
         return 1;
     }
 
@@ -638,8 +521,6 @@
         return 1;
     }
 
-    int ret = 0;
-
     // Allocate the buffer which is used to communicate between
     // daemon and dm-user. The buffer comprises of header and a fixed payload.
     // If the dm-user requests a big IO, the IO will be broken into chunks
@@ -647,138 +528,125 @@
     size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_SIZE;
     bufsink_.Initialize(buf_size);
 
-    while (true) {
-        struct dm_user_header* header = bufsink_.GetHeaderPtr();
+    return 0;
+}
 
-        bufsink_.Clear();
+int Snapuserd::Run() {
+    int ret = 0;
 
-        ret = ReadDmUserHeader();
-        if (ret < 0) return ret;
+    struct dm_user_header* header = bufsink_.GetHeaderPtr();
 
-        LOG(DEBUG) << "dm-user returned " << ret << " bytes";
+    bufsink_.Clear();
 
-        LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
-        LOG(DEBUG) << "msg->type: " << std::hex << header->type;
-        LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
-        LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
-        LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+    ret = ReadDmUserHeader();
+    if (ret < 0) return ret;
 
-        switch (header->type) {
-            case DM_USER_MAP_READ: {
-                size_t remaining_size = header->len;
-                loff_t offset = 0;
-                header->io_in_progress = 0;
-                ret = 0;
-                do {
-                    size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
+    LOG(DEBUG) << "dm-user returned " << ret << " bytes";
 
-                    // Request to sector 0 is always for kernel
-                    // representation of COW header. This IO should be only
-                    // once during dm-snapshot device creation. We should
-                    // never see multiple IO requests. Additionally this IO
-                    // will always be a single 4k.
-                    if (header->sector == 0) {
-                        // Read the metadata from internal COW device
-                        // and build the in-memory data structures
-                        // for all the operations in the internal COW.
-                        if (!metadata_read_done_ && ReadMetadata()) {
-                            LOG(ERROR) << "Metadata read failed";
-                            return 1;
+    LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
+    LOG(DEBUG) << "msg->type: " << std::hex << header->type;
+    LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
+    LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
+    LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+
+    switch (header->type) {
+        case DM_USER_MAP_READ: {
+            size_t remaining_size = header->len;
+            loff_t offset = 0;
+            header->io_in_progress = 0;
+            ret = 0;
+            do {
+                size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
+
+                // Request to sector 0 is always for kernel
+                // representation of COW header. This IO should be only
+                // once during dm-snapshot device creation. We should
+                // never see multiple IO requests. Additionally this IO
+                // will always be a single 4k.
+                if (header->sector == 0) {
+                    // Read the metadata from internal COW device
+                    // and build the in-memory data structures
+                    // for all the operations in the internal COW.
+                    if (!metadata_read_done_ && ReadMetadata()) {
+                        LOG(ERROR) << "Metadata read failed";
+                        return 1;
+                    }
+                    metadata_read_done_ = true;
+
+                    CHECK(read_size == BLOCK_SIZE);
+                    ret = ConstructKernelCowHeader();
+                    if (ret < 0) return ret;
+                } else {
+                    // Convert the sector number to a chunk ID.
+                    //
+                    // Check if the chunk ID represents a metadata
+                    // page. If the chunk ID is not found in the
+                    // vector, then it points to a metadata page.
+                    chunk_t chunk = (header->sector >> CHUNK_SHIFT);
+
+                    if (chunk >= chunk_vec_.size()) {
+                        ret = ZerofillDiskExceptions(read_size);
+                        if (ret < 0) {
+                            LOG(ERROR) << "ZerofillDiskExceptions failed";
+                            return ret;
                         }
-                        metadata_read_done_ = true;
-
-                        CHECK(read_size == BLOCK_SIZE);
-                        ret = ConstructKernelCowHeader();
-                        if (ret < 0) return ret;
+                    } else if (chunk_vec_[chunk] == nullptr) {
+                        ret = ReadDiskExceptions(chunk, read_size);
+                        if (ret < 0) {
+                            LOG(ERROR) << "ReadDiskExceptions failed";
+                            return ret;
+                        }
                     } else {
-                        // Convert the sector number to a chunk ID.
-                        //
-                        // Check if the chunk ID represents a metadata
-                        // page. If the chunk ID is not found in the
-                        // vector, then it points to a metadata page.
-                        chunk_t chunk = (header->sector >> CHUNK_SHIFT);
-
-                        if (chunk >= chunk_vec_.size()) {
-                            ret = ZerofillDiskExceptions(read_size);
-                            if (ret < 0) {
-                                LOG(ERROR) << "ZerofillDiskExceptions failed";
-                                return ret;
-                            }
-                        } else if (chunk_vec_[chunk] == nullptr) {
-                            ret = ReadDiskExceptions(chunk, read_size);
-                            if (ret < 0) {
-                                LOG(ERROR) << "ReadDiskExceptions failed";
-                                return ret;
-                            }
-                        } else {
-                            chunk_t num_chunks_read = (offset >> BLOCK_SHIFT);
-                            ret = ReadData(chunk + num_chunks_read, read_size);
-                            if (ret < 0) {
-                                LOG(ERROR) << "ReadData failed";
-                                return ret;
-                            }
+                        chunk_t num_chunks_read = (offset >> BLOCK_SHIFT);
+                        ret = ReadData(chunk + num_chunks_read, read_size);
+                        if (ret < 0) {
+                            LOG(ERROR) << "ReadData failed";
+                            return ret;
                         }
                     }
+                }
 
-                    ssize_t written = WriteDmUserPayload(ret);
-                    if (written < 0) return written;
+                ssize_t written = WriteDmUserPayload(ret);
+                if (written < 0) return written;
 
-                    remaining_size -= ret;
-                    offset += ret;
-                    if (remaining_size) {
-                        LOG(DEBUG) << "Write done ret: " << ret
-                                   << " remaining size: " << remaining_size;
-                        bufsink_.GetHeaderPtr()->io_in_progress = 1;
-                    }
-                } while (remaining_size);
+                remaining_size -= ret;
+                offset += ret;
+                if (remaining_size) {
+                    LOG(DEBUG) << "Write done ret: " << ret
+                               << " remaining size: " << remaining_size;
+                    bufsink_.GetHeaderPtr()->io_in_progress = 1;
+                }
+            } while (remaining_size);
 
-                break;
-            }
-
-            case DM_USER_MAP_WRITE: {
-                // TODO: After merge operation is completed, kernel issues write
-                // to flush all the exception mappings where the merge is
-                // completed. If dm-user routes the WRITE IO, we need to clear
-                // in-memory data structures representing those exception
-                // mappings.
-                abort();
-                break;
-            }
+            break;
         }
 
-        LOG(DEBUG) << "read() finished, next message";
+        case DM_USER_MAP_WRITE: {
+            // TODO: After merge operation is completed, kernel issues write
+            // to flush all the exception mappings where the merge is
+            // completed. If dm-user routes the WRITE IO, we need to clear
+            // in-memory data structures representing those exception
+            // mappings.
+            abort();
+            break;
+        }
     }
 
+    LOG(DEBUG) << "read() finished, next message";
+
     return 0;
 }
 
 }  // namespace snapshot
 }  // namespace android
 
-void run_thread(std::string cow_device, std::string backing_device) {
-    android::snapshot::Snapuserd snapd(cow_device, backing_device);
-    snapd.Run();
-}
-
 int main([[maybe_unused]] int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::KernelLogger);
 
     android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
 
-    while (daemon.IsRunning()) {
-        // TODO: This is hardcoded wherein:
-        // argv[1] = system_cow, argv[2] = /dev/block/mapper/system_a
-        // argv[3] = product_cow, argv[4] = /dev/block/mapper/product_a
-        //
-        // This should be fixed based on some kind of IPC or setup a
-        // command socket and spin up the thread based when a new
-        // partition is visible.
-        std::thread system_a(run_thread, argv[1], argv[2]);
-        std::thread product_a(run_thread, argv[3], argv[4]);
-
-        system_a.join();
-        product_a.join();
-    }
+    daemon.StartServer(argv[1]);
+    daemon.Run();
 
     return 0;
 }
diff --git a/fs_mgr/libsnapshot/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
new file mode 100644
index 0000000..b10de35
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -0,0 +1,261 @@
+#include <android-base/logging.h>
+#include <libsnapshot/snapuserd_client.h>
+
+namespace android {
+namespace snapshot {
+
+bool SnapuserdClient::ConnectToServerSocket(std::string socketname) {
+    sockfd_ = 0;
+
+    sockfd_ =
+            socket_local_client(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    if (sockfd_ < 0) {
+        LOG(ERROR) << "Failed to connect to " << socketname;
+        return false;
+    }
+
+    std::string msg = "query";
+
+    int sendRet = Sendmsg(msg.c_str(), msg.size());
+    if (sendRet < 0) {
+        LOG(ERROR) << "Failed to send query message to snapuserd daemon with socket " << socketname;
+        DisconnectFromServer();
+        return false;
+    }
+
+    std::string str = Receivemsg();
+
+    if (str.find("fail") != std::string::npos) {
+        LOG(ERROR) << "Failed to receive message from snapuserd daemon with socket " << socketname;
+        DisconnectFromServer();
+        return false;
+    }
+
+    // If the daemon is passive then fallback to secondary active daemon. Daemon
+    // is passive during transition phase. Please see RestartSnapuserd()
+    if (str.find("passive") != std::string::npos) {
+        LOG(DEBUG) << "Snapuserd is passive with socket " << socketname;
+        DisconnectFromServer();
+        return false;
+    }
+
+    CHECK(str.find("active") != std::string::npos);
+
+    return true;
+}
+
+bool SnapuserdClient::ConnectToServer() {
+    if (ConnectToServerSocket(GetSocketNameFirstStage())) return true;
+
+    if (ConnectToServerSocket(GetSocketNameSecondStage())) return true;
+
+    return false;
+}
+
+int SnapuserdClient::Sendmsg(const char* msg, size_t size) {
+    int numBytesSent = TEMP_FAILURE_RETRY(send(sockfd_, msg, size, 0));
+    if (numBytesSent < 0) {
+        LOG(ERROR) << "Send failed " << strerror(errno);
+        return -1;
+    }
+
+    if ((uint)numBytesSent < size) {
+        LOG(ERROR) << "Partial data sent " << strerror(errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+std::string SnapuserdClient::Receivemsg() {
+    char msg[PACKET_SIZE];
+    std::string msgStr("fail");
+    int ret;
+
+    ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, PACKET_SIZE, 0));
+    if (ret <= 0) {
+        LOG(ERROR) << "recv failed " << strerror(errno);
+        return msgStr;
+    }
+
+    msgStr.clear();
+    msgStr = msg;
+    return msgStr;
+}
+
+int SnapuserdClient::StopSnapuserd(bool firstStageDaemon) {
+    if (firstStageDaemon) {
+        sockfd_ = socket_local_client(GetSocketNameFirstStage().c_str(),
+                                      ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+        if (sockfd_ < 0) {
+            LOG(ERROR) << "Failed to connect to " << GetSocketNameFirstStage();
+            return -1;
+        }
+    } else {
+        if (!ConnectToServer()) {
+            LOG(ERROR) << "Failed to connect to socket " << GetSocketNameSecondStage();
+            return -1;
+        }
+    }
+
+    std::string msg = "stop";
+
+    int sendRet = Sendmsg(msg.c_str(), msg.size());
+    if (sendRet < 0) {
+        LOG(ERROR) << "Failed to send stop message to snapuserd daemon";
+        return -1;
+    }
+
+    DisconnectFromServer();
+
+    return 0;
+}
+
+int SnapuserdClient::StartSnapuserdaemon(std::string socketname) {
+    int retry_count = 0;
+
+    if (fork() == 0) {
+        const char* argv[] = {"/system/bin/snapuserd", socketname.c_str(), nullptr};
+        if (execv(argv[0], const_cast<char**>(argv))) {
+            LOG(ERROR) << "Failed to exec snapuserd daemon";
+            return -1;
+        }
+    }
+
+    // snapuserd is a daemon and will never exit; parent can't wait here
+    // to get the return code. Since Snapuserd starts the socket server,
+    // give it some time to fully launch.
+    //
+    // Try to connect to server to verify snapuserd server is started
+    while (retry_count < MAX_CONNECT_RETRY_COUNT) {
+        if (!ConnectToServer()) {
+            retry_count++;
+            std::this_thread::sleep_for(std::chrono::milliseconds(500));
+        } else {
+            close(sockfd_);
+            return 0;
+        }
+    }
+
+    LOG(ERROR) << "Failed to start snapuserd daemon";
+    return -1;
+}
+
+int SnapuserdClient::StartSnapuserd() {
+    if (StartSnapuserdaemon(GetSocketNameFirstStage()) < 0) return -1;
+
+    return 0;
+}
+
+int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device) {
+    int ret = 0;
+
+    if (!ConnectToServer()) {
+        LOG(ERROR) << "Failed to connect to server ";
+        return -1;
+    }
+
+    std::string msg = "start," + cow_device + "," + backing_device;
+
+    ret = Sendmsg(msg.c_str(), msg.size());
+    if (ret < 0) {
+        LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
+        return -1;
+    }
+
+    std::string str = Receivemsg();
+
+    if (str.find("fail") != std::string::npos) {
+        LOG(ERROR) << "Failed to receive ack for " << msg << " from snapuserd daemon";
+        return -1;
+    }
+
+    DisconnectFromServer();
+
+    LOG(DEBUG) << "Snapuserd daemon initialized with " << msg;
+    return 0;
+}
+
+/*
+ * Transition from first stage snapuserd daemon to second stage daemon involves
+ * series of steps viz:
+ *
+ * 1: Create new dm-user devices - This is done by libsnapshot
+ *
+ * 2: Spawn the new snapuserd daemon - This is the second stage daemon which
+ * will start the server but the dm-user misc devices is not binded yet.
+ *
+ * 3: Vector to this function contains pair of cow_device and source device.
+ *    Ex: {{system_cow,system_a}, {product_cow, product_a}, {vendor_cow,
+ *    vendor_a}}. This vector will be populated by the libsnapshot.
+ *
+ * 4: Initialize the Second stage daemon passing the information from the
+ * vector. This will bind the daemon with dm-user misc device and will be ready
+ * to serve the IO. Up until this point, first stage daemon is still active.
+ * However, client library will mark the first stage daemon as passive and hence
+ * all the control message from hereon will be sent to active second stage
+ * daemon.
+ *
+ * 5: Create new dm-snapshot table. This is done by libsnapshot. When new table
+ * is created, kernel will issue metadata read once again which will be served
+ * by second stage daemon. However, any active IO will still be served by first
+ * stage daemon.
+ *
+ * 6: Swap the snapshot table atomically - This is done by libsnapshot. Once
+ * the swapping is done, all the IO will be served by second stage daemon.
+ *
+ * 7: Stop the first stage daemon. After this point second stage daemon is
+ * completely active to serve the IO and merging process.
+ *
+ */
+int SnapuserdClient::RestartSnapuserd(std::vector<std::pair<std::string, std::string>>& vec) {
+    // Connect to first-stage daemon and send a terminate-request control
+    // message. This will not terminate the daemon but will mark the daemon as
+    // passive.
+    if (!ConnectToServer()) {
+        LOG(ERROR) << "Failed to connect to server ";
+        return -1;
+    }
+
+    std::string msg = "terminate-request";
+
+    int sendRet = Sendmsg(msg.c_str(), msg.size());
+    if (sendRet < 0) {
+        LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
+        return -1;
+    }
+
+    std::string str = Receivemsg();
+
+    if (str.find("fail") != std::string::npos) {
+        LOG(ERROR) << "Failed to receive ack for " << msg << " from snapuserd daemon";
+        return -1;
+    }
+
+    CHECK(str.find("success") != std::string::npos);
+
+    DisconnectFromServer();
+
+    // Start the new daemon
+    if (StartSnapuserdaemon(GetSocketNameSecondStage()) < 0) {
+        LOG(ERROR) << "Failed to start new daemon at socket " << GetSocketNameSecondStage();
+        return -1;
+    }
+
+    LOG(DEBUG) << "Second stage Snapuserd daemon created successfully at socket "
+               << GetSocketNameSecondStage();
+    CHECK(vec.size() % 2 == 0);
+
+    for (int i = 0; i < vec.size(); i++) {
+        std::string& cow_device = vec[i].first;
+        std::string& base_device = vec[i].second;
+
+        InitializeSnapuserd(cow_device, base_device);
+        LOG(DEBUG) << "Daemon initialized with " << cow_device << " and " << base_device;
+    }
+
+    return 0;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
new file mode 100644
index 0000000..c1008b9
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
@@ -0,0 +1,53 @@
+#include <android-base/logging.h>
+#include <libsnapshot/snapuserd_daemon.h>
+
+namespace android {
+namespace snapshot {
+
+int Daemon::StartServer(std::string socketname) {
+    int ret;
+
+    ret = server_.Start(socketname);
+    if (ret < 0) {
+        LOG(ERROR) << "Snapuserd daemon failed to start...";
+        exit(EXIT_FAILURE);
+    }
+
+    return ret;
+}
+
+Daemon::Daemon() {
+    is_running_ = true;
+    // TODO: Mask other signals - Bug 168258493
+    signal(SIGINT, Daemon::SignalHandler);
+    signal(SIGTERM, Daemon::SignalHandler);
+}
+
+bool Daemon::IsRunning() {
+    return is_running_;
+}
+
+void Daemon::Run() {
+    while (IsRunning()) {
+        if (server_.AcceptClient() == static_cast<int>(DaemonOperations::STOP)) {
+            Daemon::Instance().is_running_ = false;
+        }
+    }
+}
+
+void Daemon::SignalHandler(int signal) {
+    LOG(DEBUG) << "Snapuserd received signal: " << signal;
+    switch (signal) {
+        case SIGINT:
+        case SIGTERM: {
+            Daemon::Instance().is_running_ = false;
+            break;
+        }
+        default:
+            LOG(ERROR) << "Received unknown signal " << signal;
+            break;
+    }
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
new file mode 100644
index 0000000..1e8b642
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -0,0 +1,215 @@
+#include <android-base/logging.h>
+#include <libsnapshot/snapuserd.h>
+#include <libsnapshot/snapuserd_server.h>
+
+namespace android {
+namespace snapshot {
+
+DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
+    if (input == "start") return DaemonOperations::START;
+    if (input == "stop") return DaemonOperations::STOP;
+    if (input == "terminate-request") return DaemonOperations::TERMINATING;
+    if (input == "query") return DaemonOperations::QUERY;
+
+    return DaemonOperations::INVALID;
+}
+
+std::string SnapuserdServer::GetDaemonStatus() {
+    std::string msg = "";
+
+    if (IsTerminating())
+        msg = "passive";
+    else
+        msg = "active";
+
+    return msg;
+}
+
+void SnapuserdServer::Parsemsg(std::string const& msg, const char delim,
+                               std::vector<std::string>& out) {
+    std::stringstream ss(msg);
+    std::string s;
+
+    while (std::getline(ss, s, delim)) {
+        out.push_back(s);
+    }
+}
+
+// new thread
+void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device) {
+    Snapuserd snapd(cow_device, backing_device);
+    if (snapd.Init()) {
+        PLOG(ERROR) << "Snapuserd: Init failed";
+        exit(EXIT_FAILURE);
+    }
+
+    while (StopRequested() == false) {
+        int ret = snapd.Run();
+
+        if (ret == -ETIMEDOUT) continue;
+
+        if (ret < 0) {
+            PLOG(ERROR) << "snapd.Run() failed..." << ret;
+        }
+    }
+}
+
+void SnapuserdServer::ShutdownThreads() {
+    StopThreads();
+
+    for (auto& client : clients_vec_) {
+        auto& th = client->GetThreadHandler();
+
+        if (th->joinable()) th->join();
+    }
+}
+
+int SnapuserdServer::Sendmsg(int fd, char* msg, size_t size) {
+    int ret = TEMP_FAILURE_RETRY(send(fd, (char*)msg, size, 0));
+    if (ret < 0) {
+        PLOG(ERROR) << "Snapuserd:server: send() failed";
+        return -1;
+    }
+
+    if (ret < size) {
+        PLOG(ERROR) << "Partial data sent";
+        return -1;
+    }
+
+    return 0;
+}
+
+std::string SnapuserdServer::Recvmsg(int fd, int* ret) {
+    struct timeval tv;
+    fd_set set;
+    char msg[MAX_PACKET_SIZE];
+
+    tv.tv_sec = 2;
+    tv.tv_usec = 0;
+    FD_ZERO(&set);
+    FD_SET(fd, &set);
+    *ret = select(fd + 1, &set, NULL, NULL, &tv);
+    if (*ret == -1) {  // select failed
+        return {};
+    } else if (*ret == 0) {  // timeout
+        return {};
+    } else {
+        *ret = TEMP_FAILURE_RETRY(recv(fd, msg, MAX_PACKET_SIZE, 0));
+        if (*ret < 0) {
+            PLOG(ERROR) << "Snapuserd:server: recv failed";
+            return {};
+        } else if (*ret == 0) {
+            LOG(DEBUG) << "Snapuserd client disconnected";
+            return {};
+        } else {
+            std::string str(msg);
+            return str;
+        }
+    }
+}
+
+int SnapuserdServer::Receivemsg(int fd) {
+    char msg[MAX_PACKET_SIZE];
+    std::unique_ptr<Client> newClient;
+    int ret = 0;
+
+    while (1) {
+        memset(msg, '\0', MAX_PACKET_SIZE);
+        std::string str = Recvmsg(fd, &ret);
+
+        if (ret <= 0) {
+            LOG(DEBUG) << "recv failed with ret: " << ret;
+            return 0;
+        }
+
+        const char delim = ',';
+
+        std::vector<std::string> out;
+        Parsemsg(str, delim, out);
+        DaemonOperations op = Resolveop(out[0]);
+        memset(msg, '\0', MAX_PACKET_SIZE);
+
+        switch (op) {
+            case DaemonOperations::START: {
+                // Message format:
+                // start,<cow_device_path>,<source_device_path>
+                //
+                // Start the new thread which binds to dm-user misc device
+                newClient = std::make_unique<Client>();
+                newClient->SetThreadHandler(
+                        std::bind(&SnapuserdServer::ThreadStart, this, out[1], out[2]));
+                clients_vec_.push_back(std::move(newClient));
+                sprintf(msg, "success");
+                Sendmsg(fd, msg, MAX_PACKET_SIZE);
+                return 0;
+            }
+            case DaemonOperations::STOP: {
+                // Message format: stop
+                //
+                // Stop all the threads gracefully and then shutdown the
+                // main thread
+                ShutdownThreads();
+                return static_cast<int>(DaemonOperations::STOP);
+            }
+            case DaemonOperations::TERMINATING: {
+                // Message format: terminate-request
+                //
+                // This is invoked during transition. First stage
+                // daemon will receive this request. First stage daemon
+                // will be considered as a passive daemon from hereon.
+                SetTerminating();
+                sprintf(msg, "success");
+                Sendmsg(fd, msg, MAX_PACKET_SIZE);
+                return 0;
+            }
+            case DaemonOperations::QUERY: {
+                // Message format: query
+                //
+                // As part of transition, Second stage daemon will be
+                // created before terminating the first stage daemon. Hence,
+                // for a brief period client may have to distiguish between
+                // first stage daemon and second stage daemon.
+                //
+                // Second stage daemon is marked as active and hence will
+                // be ready to receive control message.
+                std::string dstr = GetDaemonStatus();
+                memcpy(msg, dstr.c_str(), dstr.size());
+                Sendmsg(fd, msg, MAX_PACKET_SIZE);
+                if (dstr == "active")
+                    break;
+                else
+                    return 0;
+            }
+            default: {
+                sprintf(msg, "fail");
+                Sendmsg(fd, msg, MAX_PACKET_SIZE);
+                return 0;
+            }
+        }
+    }
+}
+
+int SnapuserdServer::Start(std::string socketname) {
+    sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                      SOCK_STREAM));
+    if (sockfd_ < 0) {
+        PLOG(ERROR) << "Failed to create server socket " << socketname;
+        return -1;
+    }
+
+    LOG(DEBUG) << "Snapuserd server successfully started with socket name " << socketname;
+    return 0;
+}
+
+int SnapuserdServer::AcceptClient() {
+    int fd = accept(sockfd_.get(), NULL, NULL);
+    if (fd < 0) {
+        PLOG(ERROR) << "Socket accept failed: " << strerror(errno);
+        return -1;
+    }
+
+    return Receivemsg(fd);
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 6104c82..b07bf91 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -127,48 +127,6 @@
     return true;
 }
 
-bool WriteRandomData(ICowWriter* writer, std::string* hash) {
-    unique_fd rand(open("/dev/urandom", O_RDONLY));
-    if (rand < 0) {
-        PLOG(ERROR) << "open /dev/urandom";
-        return false;
-    }
-
-    SHA256_CTX ctx;
-    if (hash) {
-        SHA256_Init(&ctx);
-    }
-
-    if (!writer->options().max_blocks) {
-        LOG(ERROR) << "CowWriter must specify maximum number of blocks";
-        return false;
-    }
-    uint64_t num_blocks = writer->options().max_blocks.value();
-
-    size_t block_size = writer->options().block_size;
-    std::string block(block_size, '\0');
-    for (uint64_t i = 0; i < num_blocks; i++) {
-        if (!ReadFully(rand, block.data(), block.size())) {
-            PLOG(ERROR) << "read /dev/urandom";
-            return false;
-        }
-        if (!writer->AddRawBlocks(i, block.data(), block.size())) {
-            LOG(ERROR) << "Failed to add raw block " << i;
-            return false;
-        }
-        if (hash) {
-            SHA256_Update(&ctx, block.data(), block.size());
-        }
-    }
-
-    if (hash) {
-        uint8_t out[32];
-        SHA256_Final(out, &ctx);
-        *hash = ToHexString(out, sizeof(out));
-    }
-    return true;
-}
-
 std::optional<std::string> GetHash(const std::string& path) {
     std::string content;
     if (!android::base::ReadFileToString(path, &content, true)) {
diff --git a/include/android/log.h b/include/android/log.h
deleted file mode 120000
index 736c448..0000000
--- a/include/android/log.h
+++ /dev/null
@@ -1 +0,0 @@
-../../liblog/include/android/log.h
\ No newline at end of file
diff --git a/include/log b/include/log
deleted file mode 120000
index 714065f..0000000
--- a/include/log
+++ /dev/null
@@ -1 +0,0 @@
-../liblog/include/log
\ No newline at end of file
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
deleted file mode 120000
index f28a564..0000000
--- a/include/private/android_filesystem_config.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/android_filesystem_config.h
\ No newline at end of file
diff --git a/init/Android.bp b/init/Android.bp
index c3dd7f6..3f2cd07 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -129,7 +129,6 @@
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
-        "libsnapshot_cow",
         "libsnapshot_init",
         "libxml2",
         "lib_apex_manifest_proto_lite",
diff --git a/init/Android.mk b/init/Android.mk
index 998e0fd..da94daf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -112,7 +112,6 @@
     libmodprobe \
     libext2_uuid \
     libprotobuf-cpp-lite \
-    libsnapshot_cow \
     libsnapshot_init \
     update_metadata-protos \
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 524b715..b749d87 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -14,6 +14,11 @@
 // limitations under the License.
 //
 
+filegroup {
+    name: "android_filesystem_config_header",
+    srcs: ["include/private/android_filesystem_config.h"],
+}
+
 // some files must not be compiled when building against Mingw
 // they correspond to features not used by our host development tools
 // which are also hard or even impossible to port to native Win32
@@ -55,6 +60,7 @@
     name: "libcutils_sockets",
     vendor_available: true,
     recovery_available: true,
+    ramdisk_available: true,
     host_supported: true,
     native_bridge_supported: true,
     apex_available: [
diff --git a/libutils/FuzzFormatTypes.h b/libutils/FuzzFormatTypes.h
index 5d58a1a..aa9e503 100644
--- a/libutils/FuzzFormatTypes.h
+++ b/libutils/FuzzFormatTypes.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright 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 <string>
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 108f003..6e6aa1f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -573,7 +573,7 @@
     mkdir /data/apex/backup 0700 root system
     mkdir /data/apex/hashtree 0700 root system
     mkdir /data/apex/sessions 0700 root system
-    mkdir /data/app-staging 0750 system system encryption=None
+    mkdir /data/app-staging 0750 system system encryption=DeleteIfNecessary
     start apexd
 
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
diff --git a/trusty/utils/rpmb_dev/rpmb_dev.c b/trusty/utils/rpmb_dev/rpmb_dev.c
index 5de1efa..2025621 100644
--- a/trusty/utils/rpmb_dev/rpmb_dev.c
+++ b/trusty/utils/rpmb_dev/rpmb_dev.c
@@ -283,6 +283,7 @@
                 {
                         .func = rpmb_dev_data_read,
                         .resp = RPMB_RESP_DATA_READ,
+                        .check_key_programmed = true,
                         .check_addr = true,
                         .multi_packet_res = true,
                         .res_mac = true,