Merge "ueventd: Put dm-user devices in a folder"
diff --git a/OWNERS b/OWNERS
index 4f8e433..682a067 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1 @@
 enh@google.com
-baligh@google.com
diff --git a/adb/Android.bp b/adb/Android.bp
index 5c1e1fe..c361a14 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -293,8 +293,9 @@
     export_include_dirs: ["."],
 
     visibility: [
-        "//system/core/adb:__subpackages__",
         "//bootable/recovery/minadbd:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
+        "//system/core/adb:__subpackages__",
     ],
 
     apex_available: [
@@ -499,6 +500,7 @@
     ],
     visibility: [
         "//bootable/recovery/minadbd",
+        "//packages/modules/adb:__subpackages__",
         "//system/core/adb",
     ],
 }
@@ -578,6 +580,7 @@
         "com.android.adbd",
     ],
     visibility: [
+        "//packages/modules/adb",
         "//system/core/adb",
     ],
 
@@ -636,6 +639,7 @@
 
     visibility: [
         "//bootable/recovery/minadbd",
+        "//packages/modules/adb",
         "//system/core/adb",
     ],
 }
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index e2c27f1..c4052c3 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -39,8 +39,9 @@
     export_include_dirs: ["include"],
 
     visibility: [
-        "//system/core/adb:__subpackages__",
         "//bootable/recovery/minadbd:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
+        "//system/core/adb:__subpackages__",
     ],
 
     host_supported: true,
diff --git a/adb/libs/adbconnection/Android.bp b/adb/libs/adbconnection/Android.bp
index f7d2dc1..29ae060 100644
--- a/adb/libs/adbconnection/Android.bp
+++ b/adb/libs/adbconnection/Android.bp
@@ -39,6 +39,7 @@
     defaults: ["adbd_defaults"],
     visibility: [
         "//art:__subpackages__",
+        "//packages/modules/adb/apex:__subpackages__",
         "//system/core/adb/apex:__subpackages__",
     ],
     apex_available: [
diff --git a/adb/pairing_auth/Android.bp b/adb/pairing_auth/Android.bp
index a43f4d0..806879d 100644
--- a/adb/pairing_auth/Android.bp
+++ b/adb/pairing_auth/Android.bp
@@ -40,6 +40,7 @@
 
     visibility: [
         "//art:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
         "//system/core/adb:__subpackages__",
     ],
 
diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp
index 9595511..1886885 100644
--- a/adb/pairing_connection/Android.bp
+++ b/adb/pairing_connection/Android.bp
@@ -39,8 +39,9 @@
 
     visibility: [
         "//art:__subpackages__",
-        "//system/core/adb:__subpackages__",
         "//frameworks/base/services:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
+        "//system/core/adb:__subpackages__",
 
         // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
         "//bootable/recovery/minadbd:__subpackages__",
@@ -129,8 +130,9 @@
 
     visibility: [
         "//art:__subpackages__",
-        "//system/core/adb:__subpackages__",
         "//frameworks/base/services:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
+        "//system/core/adb:__subpackages__",
     ],
 
     recovery_available: false,
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index 086d10e..ef97208 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -40,6 +40,7 @@
     },
 
     visibility: [
+        "//packages/modules/adb:__subpackages__",
         "//system/core/adb:__subpackages__",
 
         // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
@@ -94,6 +95,7 @@
     },
 
     visibility: [
+        "//packages/modules/adb:__subpackages__",
         "//system/core/adb:__subpackages__",
 
         // This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
index e5204f3..1e00548 100644
--- a/adb/tls/Android.bp
+++ b/adb/tls/Android.bp
@@ -40,6 +40,7 @@
 
     visibility: [
         "//bootable/recovery/minadbd:__subpackages__",
+        "//packages/modules/adb:__subpackages__",
         "//system/core/adb:__subpackages__",
     ],
 
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 8788b5a..ef46eb9 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -284,6 +284,7 @@
     std::vector<std::string> argv;
     argv.push_back(std::to_string(start()));
     argv.push_back(std::to_string(size()));
+    argv.push_back(control_device());
     return android::base::Join(argv, " ");
 }
 
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 57e3884..478a3c6 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -311,10 +311,15 @@
 
 class DmTargetUser final : public DmTarget {
   public:
-    DmTargetUser(uint64_t start, uint64_t length) : DmTarget(start, length) {}
+    DmTargetUser(uint64_t start, uint64_t length, std::string control_device)
+        : DmTarget(start, length), control_device_(control_device) {}
 
     std::string name() const override { return "user"; }
+    std::string control_device() const { return control_device_; }
     std::string GetParameterString() const override;
+
+  private:
+    std::string control_device_;
 };
 
 }  // namespace dm
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ad592e9..b239f31 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -28,6 +28,7 @@
         "liblog",
     ],
     static_libs: [
+        "libbrotli",
         "libdm",
         "libfstab",
         "libsnapshot_cow",
@@ -74,6 +75,7 @@
         "android/snapshot/snapshot.proto",
         "device_info.cpp",
         "snapshot.cpp",
+        "snapshot_reader.cpp",
         "snapshot_stats.cpp",
         "snapshot_stub.cpp",
         "snapshot_metadata_updater.cpp",
@@ -108,6 +110,9 @@
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
+    cflags: [
+        "-DLIBSNAPSHOT_NO_COW_WRITE",
+    ],
     static_libs: [
         "libfs_mgr",
     ],
@@ -121,6 +126,9 @@
     ],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
+    cflags: [
+        "-DLIBSNAPSHOT_NO_COW_WRITE",
+    ],
     static_libs: [
         "libfs_mgr",
     ],
@@ -243,6 +251,7 @@
     static_libs: [
         "android.hardware.boot@1.0",
         "android.hardware.boot@1.1",
+        "libbrotli",
         "libfs_mgr",
         "libgsi",
         "libgmock",
@@ -275,9 +284,11 @@
         "snapshotctl.cpp",
     ],
     static_libs: [
+        "libbrotli",
         "libfstab",
         "libsnapshot",
         "libsnapshot_cow",
+        "libz",
         "update_metadata-protos",
     ],
     shared_libs: [
@@ -331,6 +342,7 @@
     ],
     static_libs: [
         "libbase",
+        "libbrotli",
         "libcrypto_static",
         "libcutils",
         "libext2_uuid",
@@ -344,6 +356,7 @@
         "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libprotobuf-mutator",
+        "libz",
     ],
     header_libs: [
         "libchrome",
@@ -544,9 +557,11 @@
 	"libsnapshot_snapuserd",
         "libcutils_sockets",
         "libz",
+	"libdm",
     ],
     header_libs: [
         "libstorage_literals_headers",
+        "libfiemap_headers",
     ],
     test_min_api_level: 30,
     auto_gen_config: true,
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 75e54f7..1d6c104 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <fcntl.h>
 #include <linux/fs.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <iostream>
 #include <memory>
 #include <string_view>
@@ -25,6 +25,7 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
+#include <libdm/loop_control.h>
 #include <libsnapshot/cow_writer.h>
 #include <libsnapshot/snapuserd_client.h>
 #include <storage_literals/storage_literals.h>
@@ -34,6 +35,8 @@
 
 using namespace android::storage_literals;
 using android::base::unique_fd;
+using LoopDevice = android::dm::LoopDevice;
+using namespace std::chrono_literals;
 
 class SnapuserdTest : public ::testing::Test {
   protected:
@@ -50,6 +53,18 @@
         cow_product_1_ = std::make_unique<TemporaryFile>();
         ASSERT_GE(cow_product_1_->fd, 0) << strerror(errno);
 
+        // Create temp files in the PWD as selinux
+        // allows kernel domin to read from that directory only
+        // on userdebug/eng builds. Creating files under /data/local/tmp
+        // will have selinux denials.
+        std::string path = android::base::GetExecutableDirectory();
+
+        system_a_ = std::make_unique<TemporaryFile>(path);
+        ASSERT_GE(system_a_->fd, 0) << strerror(errno);
+
+        product_a_ = std::make_unique<TemporaryFile>(path);
+        ASSERT_GE(product_a_->fd, 0) << strerror(errno);
+
         size_ = 100_MiB;
     }
 
@@ -61,6 +76,12 @@
         cow_product_1_ = nullptr;
     }
 
+    std::unique_ptr<TemporaryFile> system_a_;
+    std::unique_ptr<TemporaryFile> product_a_;
+
+    std::unique_ptr<LoopDevice> system_a_loop_;
+    std::unique_ptr<LoopDevice> product_a_loop_;
+
     std::unique_ptr<TemporaryFile> cow_system_;
     std::unique_ptr<TemporaryFile> cow_product_;
 
@@ -76,6 +97,9 @@
     std::string system_device_name_;
     std::string product_device_name_;
 
+    std::string system_device_ctrl_name_;
+    std::string product_device_ctrl_name_;
+
     std::unique_ptr<uint8_t[]> random_buffer_1_;
     std::unique_ptr<uint8_t[]> random_buffer_2_;
     std::unique_ptr<uint8_t[]> zero_buffer_;
@@ -86,10 +110,18 @@
     void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
     void CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow);
     void CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow);
+    void DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device);
     void StartSnapuserdDaemon();
     void CreateSnapshotDevices();
     void SwitchSnapshotDevices();
 
+    std::string GetSystemControlPath() {
+        return std::string("/dev/dm-user-") + system_device_ctrl_name_;
+    }
+    std::string GetProductControlPath() {
+        return std::string("/dev/dm-user-") + product_device_ctrl_name_;
+    }
+
     void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer);
     SnapuserdClient client_;
 };
@@ -97,6 +129,7 @@
 void SnapuserdTest::Init() {
     unique_fd rnd_fd;
     loff_t offset = 0;
+    std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
 
     rnd_fd.reset(open("/dev/random", O_RDONLY));
     ASSERT_TRUE(rnd_fd > 0);
@@ -118,10 +151,27 @@
         offset += 1_MiB;
     }
 
-    sys_fd_.reset(open("/dev/block/mapper/system_a", O_RDONLY));
+    for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+        ASSERT_EQ(android::base::WriteFully(system_a_->fd, random_buffer.get(), 1_MiB), true);
+    }
+
+    for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+        ASSERT_EQ(android::base::WriteFully(product_a_->fd, random_buffer.get(), 1_MiB), true);
+    }
+
+    // Create loopback devices
+    system_a_loop_ = std::make_unique<LoopDevice>(std::string(system_a_->path), 10s);
+    ASSERT_TRUE(system_a_loop_->valid());
+
+    product_a_loop_ = std::make_unique<LoopDevice>(std::string(product_a_->path), 10s);
+    ASSERT_TRUE(product_a_loop_->valid());
+
+    sys_fd_.reset(open(system_a_loop_->device().c_str(), O_RDONLY));
     ASSERT_TRUE(sys_fd_ > 0);
 
-    product_fd_.reset(open("/dev/block/mapper/product_a", O_RDONLY));
+    product_fd_.reset(open(product_a_loop_->device().c_str(), O_RDONLY));
     ASSERT_TRUE(product_fd_ > 0);
 
     // Read from system partition from offset 0 of size 100MB
@@ -183,47 +233,65 @@
 }
 
 void SnapuserdTest::CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow) {
-    unique_fd system_a_fd;
     std::string cmd;
     system_device_name_.clear();
+    system_device_ctrl_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
 
-    system_a_fd.reset(open("/dev/block/mapper/system_a", O_RDONLY));
-    ASSERT_TRUE(system_a_fd > 0);
-
-    int err = ioctl(system_a_fd.get(), BLKGETSIZE, &system_blksize_);
+    int err = ioctl(sys_fd_.get(), BLKGETSIZE, &system_blksize_);
     ASSERT_GE(err, 0);
 
     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);
+
+    // Create a control device
+    system_device_ctrl_name_ = system_device_name_ + "-ctrl";
     cmd = "dmctl create " + system_device_name_ + " user 0 " + std::to_string(system_blksize_);
+    cmd += " " + system_device_ctrl_name_;
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device) {
+    std::string cmd;
+
+    cmd = "dmctl delete " + snapshot_device;
+    system(cmd.c_str());
+
+    cmd.clear();
+
+    std::string str(cow->path);
+    std::size_t found = str.find_last_of("/\\");
+    ASSERT_NE(found, std::string::npos);
+    std::string device_name = str.substr(found + 1);
+
+    cmd = "dmctl delete " + device_name;
 
     system(cmd.c_str());
 }
 
 void SnapuserdTest::CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow) {
-    unique_fd product_a_fd;
     std::string cmd;
     product_device_name_.clear();
+    product_device_ctrl_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
 
-    product_a_fd.reset(open("/dev/block/mapper/product_a", O_RDONLY));
-    ASSERT_TRUE(product_a_fd > 0);
-
-    int err = ioctl(product_a_fd.get(), BLKGETSIZE, &product_blksize_);
+    int err = ioctl(product_fd_.get(), BLKGETSIZE, &product_blksize_);
     ASSERT_GE(err, 0);
 
     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);
+    product_device_ctrl_name_ = product_device_name_ + "-ctrl";
     cmd = "dmctl create " + product_device_name_ + " user 0 " + std::to_string(product_blksize_);
+    cmd += " " + product_device_ctrl_name_;
 
     system(cmd.c_str());
 }
@@ -234,10 +302,12 @@
     ret = client_.StartSnapuserd();
     ASSERT_EQ(ret, 0);
 
-    ret = client_.InitializeSnapuserd(cow_system_->path, "/dev/block/mapper/system_a");
+    ret = client_.InitializeSnapuserd(cow_system_->path, system_a_loop_->device(),
+                                      GetSystemControlPath());
     ASSERT_EQ(ret, 0);
 
-    ret = client_.InitializeSnapuserd(cow_product_->path, "/dev/block/mapper/product_a");
+    ret = client_.InitializeSnapuserd(cow_product_->path, product_a_loop_->device(),
+                                      GetProductControlPath());
     ASSERT_EQ(ret, 0);
 }
 
@@ -245,7 +315,7 @@
     std::string cmd;
 
     cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(system_blksize_);
-    cmd += " /dev/block/mapper/system_a";
+    cmd += " " + system_a_loop_->device();
     cmd += " /dev/block/mapper/" + system_device_name_;
     cmd += " P 8";
 
@@ -254,7 +324,7 @@
     cmd.clear();
 
     cmd = "dmctl create product-snapshot -ro snapshot 0 " + std::to_string(product_blksize_);
-    cmd += " /dev/block/mapper/product_a";
+    cmd += " " + product_a_loop_->device();
     cmd += " /dev/block/mapper/" + product_device_name_;
     cmd += " P 8";
 
@@ -265,7 +335,7 @@
     std::string cmd;
 
     cmd = "dmctl create system-snapshot-1 -ro snapshot 0 " + std::to_string(system_blksize_);
-    cmd += " /dev/block/mapper/system_a";
+    cmd += " " + system_a_loop_->device();
     cmd += " /dev/block/mapper/" + system_device_name_;
     cmd += " P 8";
 
@@ -274,7 +344,7 @@
     cmd.clear();
 
     cmd = "dmctl create product-snapshot-1 -ro snapshot 0 " + std::to_string(product_blksize_);
-    cmd += " /dev/block/mapper/product_a";
+    cmd += " " + product_a_loop_->device();
     cmd += " /dev/block/mapper/" + product_device_name_;
     cmd += " P 8";
 
@@ -318,7 +388,7 @@
     //
     // IO path:
     //
-    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_system_a_partition
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_(system_a/product_a) partition
     // (copy op) -> return
     ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
 
@@ -379,24 +449,33 @@
     ASSERT_TRUE(snapshot_fd > 0);
     TestIO(snapshot_fd, product_buffer_);
 
+    snapshot_fd.reset(-1);
+
     // Sequence of operations for transition
     CreateCowDevice(cow_system_1_);
     CreateCowDevice(cow_product_1_);
 
+    // Create dm-user which creates new control devices
     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"));
+    // Send the path information to second stage daemon through vector
+    std::vector<std::vector<std::string>> vec{
+            {cow_system_1_->path, system_a_loop_->device(), GetSystemControlPath()},
+            {cow_product_1_->path, product_a_loop_->device(), GetProductControlPath()}};
 
-    // Start the second stage deamon and send the devices
+    // Start the second stage deamon and send the devices information through
+    // vector.
     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.
+    // Second stage daemon will be ready to serve the IO request. From now
+    // onwards, we can go ahead and shutdown the first stage daemon
     SwitchSnapshotDevices();
 
+    DeleteDmUser(cow_system_, "system-snapshot");
+    DeleteDmUser(cow_product_, "product-snapshot");
+
     // Stop the first stage daemon
     ASSERT_EQ(client_.StopSnapuserd(true), 0);
 
@@ -409,6 +488,11 @@
     ASSERT_TRUE(snapshot_fd > 0);
     TestIO(snapshot_fd, product_buffer_);
 
+    snapshot_fd.reset(-1);
+
+    DeleteDmUser(cow_system_1_, "system-snapshot-1");
+    DeleteDmUser(cow_product_1_, "product-snapshot-1");
+
     // Stop the second stage daemon
     ASSERT_EQ(client_.StopSnapuserd(false), 0);
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 1bc972e..403e350 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -532,8 +532,8 @@
         // 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;
+        // COW name (eg system_cow). Not present if no COW is needed.
+        std::string cow_device_name;
 
         // dm-snapshot instance. Not present in Update mode for VABC.
         std::string snapshot_device;
@@ -626,6 +626,9 @@
     bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
                                           std::string* device_string_or_mapped_path);
 
+    // Same as above, but for paths only (no major:minor device strings).
+    bool GetMappedImageDevicePath(const std::string& device_name, std::string* device_path);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index bf57a00..da058f9 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -42,6 +42,29 @@
     android::base::unique_fd source_fd_;
 };
 
+// Send writes to a COW or a raw device directly, based on a threshold.
+class CompressedSnapshotWriter : public ISnapshotWriter {
+  public:
+    CompressedSnapshotWriter(const CowOptions& options);
+
+    // Sets the COW device, if needed.
+    bool SetCowDevice(android::base::unique_fd&& cow_device);
+
+    bool Flush() override;
+    uint64_t GetCowSize() override;
+    std::unique_ptr<FileDescriptor> OpenReader() override;
+
+  protected:
+    bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+    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;
+
+  private:
+    android::base::unique_fd cow_device_;
+
+    std::unique_ptr<CowWriter> cow_;
+};
+
 // Write directly to a dm-snapshot device.
 class OnlineKernelSnapshotWriter : public ISnapshotWriter {
   public:
@@ -52,7 +75,7 @@
 
     bool Flush() override;
     uint64_t GetCowSize() override { return cow_size_; }
-    virtual std::unique_ptr<FileDescriptor> OpenReader() override;
+    std::unique_ptr<FileDescriptor> OpenReader() override;
 
   protected:
     bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
index d495014..2f727d6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -60,9 +60,11 @@
 
 class Snapuserd final {
   public:
-    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device)
+    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device,
+              const std::string& in_control_device)
         : cow_device_(in_cow_device),
           backing_store_device_(in_backing_store_device),
+          control_device_(in_control_device),
           metadata_read_done_(false) {}
 
     bool Init();
@@ -75,6 +77,8 @@
     int ReadDiskExceptions(chunk_t chunk, size_t size);
     int ReadData(chunk_t chunk, size_t size);
 
+    std::string GetControlDevicePath() { return control_device_; }
+
   private:
     int ProcessReplaceOp(const CowOperation* cow_op);
     int ProcessCopyOp(const CowOperation* cow_op);
@@ -82,6 +86,7 @@
 
     std::string cow_device_;
     std::string backing_store_device_;
+    std::string control_device_;
 
     unique_fd cow_fd_;
     unique_fd backing_store_fd_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index 535e923..ab2149e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -51,8 +51,9 @@
   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);
+    int RestartSnapuserd(std::vector<std::vector<std::string>>& vec);
+    int InitializeSnapuserd(std::string cow_device, std::string backing_device,
+                            std::string control_device);
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
index 1a6ba8f..1037c12 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -80,7 +80,6 @@
     __u64 flags;
     __u64 sector;
     __u64 len;
-    __u64 io_in_progress;
 } __attribute__((packed));
 
 struct dm_user_payload {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
index 584fe71..a1ebd3a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
@@ -60,7 +60,8 @@
 
     virtual ~Stoppable() {}
 
-    virtual void ThreadStart(std::string cow_device, std::string backing_device) = 0;
+    virtual void ThreadStart(std::string cow_device, std::string backing_device,
+                             std::string control_device) = 0;
 
     bool StopRequested() {
         // checks if value in future object is available
@@ -78,7 +79,8 @@
     bool terminating_;
     std::vector<std::unique_ptr<Client>> clients_vec_;
 
-    void ThreadStart(std::string cow_device, std::string backing_device) override;
+    void ThreadStart(std::string cow_device, std::string backing_device,
+                     std::string control_device) override;
     void ShutdownThreads();
     DaemonOperations Resolveop(std::string& input);
     std::string GetDaemonStatus();
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 2df2c94..3541ef6 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -44,6 +44,7 @@
 #include "device_info.h"
 #include "partition_cow_creator.h"
 #include "snapshot_metadata_updater.h"
+#include "snapshot_reader.h"
 #include "utility.h"
 
 namespace android {
@@ -270,7 +271,7 @@
         return false;
     }
 
-    if (!EnsureNoOverflowSnapshot(lock.get())) {
+    if (!IsCompressionEnabled() && !EnsureNoOverflowSnapshot(lock.get())) {
         LOG(ERROR) << "Cannot ensure there are no overflow snapshots.";
         return false;
     }
@@ -1715,7 +1716,7 @@
         return false;
     }
     if (paths) {
-        paths->cow_device = cow_device;
+        paths->cow_device_name = cow_name;
     }
 
     remaining_time = GetRemainingTime(params.timeout_ms, begin);
@@ -1723,6 +1724,7 @@
 
     if (context == SnapshotContext::Update && IsCompressionEnabled()) {
         // Stop here, we can't run dm-user yet, the COW isn't built.
+        created_devices.Release();
         return true;
     }
 
@@ -2470,6 +2472,12 @@
 
 std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
         const android::fs_mgr::CreateLogicalPartitionParams& params) {
+#if defined(LIBSNAPSHOT_NO_COW_WRITE)
+    (void)params;
+
+    LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
+    return nullptr;
+#else
     // First unmap any existing mapping.
     auto lock = LockShared();
     if (!lock) return nullptr;
@@ -2485,7 +2493,7 @@
     }
 
     SnapshotStatus status;
-    if (!paths.cow_device.empty()) {
+    if (!paths.cow_device_name.empty()) {
         if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
             return nullptr;
         }
@@ -2503,12 +2511,49 @@
         return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
     }
     return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
+#endif
 }
 
+#if !defined(LIBSNAPSHOT_NO_COW_WRITE)
 std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
-        LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
-    LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
-    return nullptr;
+        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
+        const SnapshotStatus& status, const SnapshotPaths& paths) {
+    CHECK(lock);
+
+    CowOptions cow_options;
+    cow_options.compression = "gz";
+    cow_options.max_blocks = {status.device_size() / cow_options.block_size};
+
+    // Currently we don't support partial snapshots, since partition_cow_creator
+    // never creates this scenario.
+    CHECK(status.snapshot_size() == status.device_size());
+
+    auto writer = std::make_unique<CompressedSnapshotWriter>(cow_options);
+
+    unique_fd base_fd(open(paths.target_device.c_str(), O_RDWR | O_CLOEXEC));
+    if (base_fd < 0) {
+        PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << paths.target_device;
+        return nullptr;
+    }
+    writer->SetSourceDevice(std::move(base_fd));
+
+    std::string cow_path;
+    if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
+        LOG(ERROR) << "Could not determine path for " << paths.cow_device_name;
+        return nullptr;
+    }
+
+    unique_fd cow_fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
+    if (cow_fd < 0) {
+        PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path;
+        return nullptr;
+    }
+    if (!writer->SetCowDevice(std::move(cow_fd))) {
+        LOG(ERROR) << "Could not create COW writer from " << cow_path;
+        return nullptr;
+    }
+
+    return writer;
 }
 
 std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
@@ -2533,6 +2578,7 @@
 
     return writer;
 }
+#endif  // !defined(LIBSNAPSHOT_NO_COW_WRITE)
 
 bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
     auto lock = LockShared();
@@ -2871,6 +2917,22 @@
     return SnapshotMergeStats::GetInstance(*this);
 }
 
+// This is only to be used in recovery or normal Android (not first-stage init).
+// We don't guarantee dm paths are available in first-stage init, because ueventd
+// isn't running yet.
+bool SnapshotManager::GetMappedImageDevicePath(const std::string& device_name,
+                                               std::string* device_path) {
+    auto& dm = DeviceMapper::Instance();
+
+    // Try getting the device string if it is a device mapper device.
+    if (dm.GetState(device_name) != DmDeviceState::INVALID) {
+        return dm.GetDmDevicePathByName(device_name, device_path);
+    }
+
+    // Otherwise, get path from IImageManager.
+    return images_->GetMappedImageDevice(device_name, device_path);
+}
+
 bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
                                                        std::string* device_string_or_mapped_path) {
     auto& dm = DeviceMapper::Instance();
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
new file mode 100644
index 0000000..0d47468
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.cpp
@@ -0,0 +1,77 @@
+//
+// 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
new file mode 100644
index 0000000..1f2ffe2
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.h
@@ -0,0 +1,50 @@
+//
+// 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_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 1958f18..aa49ab1 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -19,10 +19,12 @@
 #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) {}
@@ -31,6 +33,40 @@
     source_fd_ = std::move(source_fd);
 }
 
+CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options)
+    : ISnapshotWriter(options) {}
+
+bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
+    cow_device_ = std::move(cow_device);
+    cow_ = std::make_unique<CowWriter>(options_);
+
+    return cow_->Initialize(cow_device_);
+}
+bool CompressedSnapshotWriter::Flush() {
+    return cow_->Flush();
+}
+
+uint64_t CompressedSnapshotWriter::GetCowSize() {
+    return cow_->GetCowSize();
+}
+
+std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
+    return nullptr;
+}
+
+bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+    return cow_->AddCopy(new_block, old_block);
+}
+
+bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
+                                             size_t size) {
+    return cow_->AddRawBlocks(new_block_start, data, size);
+}
+
+bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+    return cow_->AddZeroBlocks(new_block_start, num_blocks);
+}
+
 OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
     : ISnapshotWriter(options) {}
 
@@ -83,8 +119,12 @@
 }
 
 std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
-    LOG(ERROR) << "OnlineKernelSnapshotWriter::OpenReader not yet implemented";
-    return nullptr;
+    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
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 3ed853f..62ef1b0 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -34,18 +34,6 @@
 
 static_assert(PAYLOAD_SIZE >= BLOCK_SIZE);
 
-class Target {
-  public:
-    // Represents an already-created Target, which is referenced by UUID.
-    Target(std::string uuid) : uuid_(uuid) {}
-
-    const auto& uuid() { return uuid_; }
-    std::string control_path() { return std::string("/dev/dm-user-") + uuid(); }
-
-  private:
-    const std::string uuid_;
-};
-
 void BufferSink::Initialize(size_t size) {
     buffer_size_ = size;
     buffer_offset_ = 0;
@@ -498,26 +486,13 @@
         return false;
     }
 
-    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);
+    std::string control_path = GetControlDevicePath();
 
-    LOG(DEBUG) << "Fetching UUID for: " << device_name;
+    LOG(DEBUG) << "Opening control device " << control_path;
 
-    auto& dm = dm::DeviceMapper::Instance();
-    std::string uuid;
-    if (!dm.GetDmDeviceUuidByName(device_name, &uuid)) {
-        LOG(ERROR) << "Unable to find UUID for " << cow_device_;
-        return false;
-    }
-
-    LOG(DEBUG) << "UUID: " << uuid;
-    Target t(uuid);
-
-    ctrl_fd_.reset(open(t.control_path().c_str(), O_RDWR));
+    ctrl_fd_.reset(open(control_path.c_str(), O_RDWR));
     if (ctrl_fd_ < 0) {
-        LOG(ERROR) << "Unable to open " << t.control_path();
+        LOG(ERROR) << "Unable to open " << control_path;
         return false;
     }
 
@@ -553,7 +528,6 @@
         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);
@@ -619,7 +593,6 @@
                 if (remaining_size) {
                     LOG(DEBUG) << "Write done ret: " << ret
                                << " remaining size: " << remaining_size;
-                    bufsink_.GetHeaderPtr()->io_in_progress = 1;
                 }
             } while (remaining_size);
 
diff --git a/fs_mgr/libsnapshot/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
index bef8f5c..78dbada 100644
--- a/fs_mgr/libsnapshot/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -127,24 +127,6 @@
     return msgStr;
 }
 
-#if 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;
-}
-#endif
-
 int SnapuserdClient::StopSnapuserd(bool firstStageDaemon) {
     if (firstStageDaemon) {
         sockfd_ = socket_local_client(GetSocketNameFirstStage().c_str(),
@@ -209,7 +191,8 @@
     return 0;
 }
 
-int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device) {
+int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device,
+                                         std::string control_device) {
     int ret = 0;
 
     if (!ConnectToServer()) {
@@ -217,7 +200,7 @@
         return -1;
     }
 
-    std::string msg = "start," + cow_device + "," + backing_device;
+    std::string msg = "start," + cow_device + "," + backing_device + "," + control_device;
 
     ret = Sendmsg(msg.c_str(), msg.size());
     if (ret < 0) {
@@ -270,7 +253,7 @@
  * completely active to serve the IO and merging process.
  *
  */
-int SnapuserdClient::RestartSnapuserd(std::vector<std::pair<std::string, std::string>>& vec) {
+int SnapuserdClient::RestartSnapuserd(std::vector<std::vector<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.
@@ -306,14 +289,19 @@
 
     LOG(DEBUG) << "Second stage Snapuserd daemon created successfully at socket "
                << GetSocketNameSecondStage();
-    CHECK(vec.size() % 2 == 0);
 
+    // Vector contains all the device information to be passed to the new
+    // daemon. Note that the caller can choose to initialize separately
+    // by calling InitializeSnapuserd() API as well. In that case, vector
+    // should be empty
     for (int i = 0; i < vec.size(); i++) {
-        std::string& cow_device = vec[i].first;
-        std::string& base_device = vec[i].second;
+        std::string& cow_device = vec[i][0];
+        std::string& base_device = vec[i][1];
+        std::string& control_device = vec[i][2];
 
-        InitializeSnapuserd(cow_device, base_device);
-        LOG(DEBUG) << "Daemon initialized with " << cow_device << " and " << base_device;
+        InitializeSnapuserd(cow_device, base_device, control_device);
+        LOG(DEBUG) << "Daemon initialized with " << cow_device << ", " << base_device << " and "
+                   << control_device;
     }
 
     return 0;
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 1f8dd63..53101aa 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -63,8 +63,9 @@
 }
 
 // new thread
-void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device) {
-    Snapuserd snapd(cow_device, backing_device);
+void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device,
+                                  std::string control_device) {
+    Snapuserd snapd(cow_device, backing_device, control_device);
     if (!snapd.Init()) {
         PLOG(ERROR) << "Snapuserd: Init failed";
         return;
@@ -73,10 +74,9 @@
     while (StopRequested() == false) {
         int ret = snapd.Run();
 
-        if (ret == -ETIMEDOUT) continue;
-
         if (ret < 0) {
-            PLOG(ERROR) << "snapd.Run() failed..." << ret;
+            LOG(ERROR) << "Snapuserd: Thread terminating as control device is de-registered";
+            break;
         }
     }
 }
@@ -159,12 +159,12 @@
         switch (op) {
             case DaemonOperations::START: {
                 // Message format:
-                // start,<cow_device_path>,<source_device_path>
+                // start,<cow_device_path>,<source_device_path>,<control_device>
                 //
                 // 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]));
+                        std::bind(&SnapuserdServer::ThreadStart, this, out[1], out[2], out[3]));
                 clients_vec_.push_back(std::move(newClient));
                 sprintf(msg, "success");
                 Sendmsg(fd, msg, MAX_PACKET_SIZE);
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 9edcda7..62ca162 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -177,7 +177,12 @@
             return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
                                                       cow_device, mode, chunk_size);
         } else if (target_type == "user") {
-            return std::make_unique<DmTargetUser>(start_sector, num_sectors);
+            if (!HasArgs(1)) {
+                std::cerr << "Expected \"user\" <control_device_name>" << std::endl;
+                return nullptr;
+            }
+            std::string control_device = NextArg();
+            return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
         } else {
             std::cerr << "Unrecognized target type: " << target_type << std::endl;
             return nullptr;
diff --git a/include/backtrace b/include/backtrace
deleted file mode 120000
index 93ce2b1..0000000
--- a/include/backtrace
+++ /dev/null
@@ -1 +0,0 @@
-../libbacktrace/include/backtrace
\ No newline at end of file
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index ceabf62..b3ae937 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -66,6 +66,7 @@
         deps.emplace_back(prefix + args[0].substr(0, pos));
     } else {
         LOG(ERROR) << "dependency lines must start with name followed by ':'";
+        return false;
     }
 
     // Remaining items are dependencies of our module
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index 5919c49..d50c10d 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -179,3 +179,16 @@
     m.EnableBlocklist(true);
     EXPECT_FALSE(m.LoadWithAliases("test4", true));
 }
+
+TEST(libmodprobe, ModuleDepLineWithoutColonIsSkipped) {
+    TemporaryDir dir;
+    auto dir_path = std::string(dir.path);
+    ASSERT_TRUE(android::base::WriteStringToFile(
+            "no_colon.ko no_colon.ko\n", dir_path + "/modules.dep", 0600, getuid(), getgid()));
+
+    kernel_cmdline = "";
+    test_modules = {dir_path + "/no_colon.ko"};
+
+    Modprobe m({dir.path});
+    EXPECT_FALSE(m.LoadWithAliases("no_colon", true));
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index dd9fea0..e53e89b 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -43,7 +43,13 @@
             header_libs: ["libbacktrace_headers"],
             export_header_lib_headers: ["libbacktrace_headers"],
         },
+        linux_glibc: {
+            header_libs: ["libbacktrace_headers"],
+            export_header_lib_headers: ["libbacktrace_headers"],
+        },
         linux_bionic: {
+            header_libs: ["libbacktrace_headers"],
+            export_header_lib_headers: ["libbacktrace_headers"],
             enabled: true,
         },
         windows: {
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ae10789..2523097 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -21,9 +21,9 @@
 
 #include <android-base/macros.h>
 
-#include <utils/RefBase.h>
+#include <log/log.h>
 
-#include <utils/CallStack.h>
+#include <utils/RefBase.h>
 
 #include <utils/Mutex.h>
 
@@ -55,6 +55,17 @@
 // case.
 #define DEBUG_REFBASE_DESTRUCTION 1
 
+#if !defined(_WIN32)
+// CallStack is only supported on linux type platforms.
+#define CALLSTACK_ENABLED 1
+#else
+#define CALLSTACK_ENABLED 0
+#endif
+
+#if CALLSTACK_ENABLED
+#include <utils/CallStack.h>
+#endif
+
 // ---------------------------------------------------------------------------
 
 namespace android {
@@ -185,7 +196,7 @@
         , mRetain(false)
     {
     }
-    
+
     ~weakref_impl()
     {
         bool dumpStack = false;
@@ -196,7 +207,7 @@
             while (refs) {
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
                 CallStack::logStack(LOG_TAG, refs->stack.get());
 #endif
                 refs = refs->next;
@@ -210,7 +221,7 @@
             while (refs) {
                 char inc = refs->ref >= 0 ? '+' : '-';
                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
                 CallStack::logStack(LOG_TAG, refs->stack.get());
 #endif
                 refs = refs->next;
@@ -218,7 +229,9 @@
         }
         if (dumpStack) {
             ALOGE("above errors at:");
+#if CALLSTACK_ENABLED
             CallStack::logStack(LOG_TAG);
+#endif
         }
     }
 
@@ -261,8 +274,7 @@
         renameRefsId(mWeakRefs, old_id, new_id);
     }
 
-    void trackMe(bool track, bool retain)
-    { 
+    void trackMe(bool track, bool retain) {
         mTrackEnabled = track;
         mRetain = retain;
     }
@@ -306,7 +318,7 @@
     {
         ref_entry* next;
         const void* id;
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
         CallStack::CallStackUPtr stack;
 #endif
         int32_t ref;
@@ -323,7 +335,7 @@
             // decrement the reference count.
             ref->ref = mRef;
             ref->id = id;
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
             ref->stack = CallStack::getCurrent(2);
 #endif
             ref->next = *refs;
@@ -335,7 +347,7 @@
     {
         if (mTrackEnabled) {
             AutoMutex _l(mMutex);
-            
+
             ref_entry* const head = *refs;
             ref_entry* ref = head;
             while (ref != NULL) {
@@ -359,7 +371,9 @@
                 ref = ref->next;
             }
 
+#if CALLSTACK_ENABLED
             CallStack::logStack(LOG_TAG);
+#endif
         }
     }
 
@@ -385,7 +399,7 @@
             snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
                      inc, refs->id, refs->ref);
             out->append(buf);
-#if DEBUG_REFS_CALLSTACK_ENABLED
+#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
             out->append(CallStack::stackToString("\t\t", refs->stack.get()));
 #else
             out->append("\t\t(call stacks disabled)");
@@ -412,7 +426,7 @@
 {
     weakref_impl* const refs = mRefs;
     refs->incWeak(id);
-    
+
     refs->addStrongRef(id);
     const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
     ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
@@ -468,7 +482,7 @@
     // TODO: Better document assumptions.
     weakref_impl* const refs = mRefs;
     refs->incWeak(id);
-    
+
     refs->addStrongRef(id);
     const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
     ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
@@ -550,7 +564,7 @@
 bool RefBase::weakref_type::attemptIncStrong(const void* id)
 {
     incWeak(id);
-    
+
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
 
@@ -567,7 +581,7 @@
         // the strong count has changed on us, we need to re-assert our
         // situation. curCount was updated by compare_exchange_weak.
     }
-    
+
     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
         // we're now in the harder case of either:
         // - there never was a strong reference on us
@@ -624,7 +638,7 @@
             }
         }
     }
-    
+
     impl->addStrongRef(id);
 
 #if PRINT_REFS
@@ -719,7 +733,10 @@
         // Treating this as fatal is prone to causing boot loops. For debugging, it's
         // better to treat as non-fatal.
         ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+
+#if CALLSTACK_ENABLED
         CallStack::logStack(LOG_TAG);
+#endif
 #else
         LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
 #endif
diff --git a/libutils/SharedBuffer_test.cpp b/libutils/SharedBuffer_test.cpp
index 33a4e0c..3f960d2 100644
--- a/libutils/SharedBuffer_test.cpp
+++ b/libutils/SharedBuffer_test.cpp
@@ -23,36 +23,45 @@
 
 #include "SharedBuffer.h"
 
-TEST(SharedBufferTest, TestAlloc) {
-  EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
-  EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+extern "C" void __hwasan_init() __attribute__((weak));
+#define SKIP_WITH_HWASAN \
+    if (&__hwasan_init != 0) GTEST_SKIP()
 
-  // Make sure we don't die here.
-  // Check that null is returned, as we are asking for the whole address space.
-  android::SharedBuffer* buf =
-      android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
-  ASSERT_EQ(nullptr, buf);
-
-  buf = android::SharedBuffer::alloc(0);
-  ASSERT_NE(nullptr, buf);
-  ASSERT_EQ(0U, buf->size());
-  buf->release();
+TEST(SharedBufferTest, alloc_death) {
+    EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX), "");
+    EXPECT_DEATH(android::SharedBuffer::alloc(SIZE_MAX - sizeof(android::SharedBuffer)), "");
 }
 
-TEST(SharedBufferTest, TestEditResize) {
-  android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
-  EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
-  buf = android::SharedBuffer::alloc(10);
-  EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+TEST(SharedBufferTest, alloc_null) {
+    // Big enough to fail, not big enough to abort.
+    SKIP_WITH_HWASAN;  // hwasan has a 2GiB allocation limit.
+    ASSERT_EQ(nullptr, android::SharedBuffer::alloc(SIZE_MAX / 2));
+}
 
-  buf = android::SharedBuffer::alloc(10);
-  // Make sure we don't die here.
-  // Check that null is returned, as we are asking for the whole address space.
-  buf = buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer) - 1);
-  ASSERT_EQ(nullptr, buf);
+TEST(SharedBufferTest, alloc_zero_size) {
+    android::SharedBuffer* buf = android::SharedBuffer::alloc(0);
+    ASSERT_NE(nullptr, buf);
+    ASSERT_EQ(0U, buf->size());
+    buf->release();
+}
 
-  buf = android::SharedBuffer::alloc(10);
-  buf = buf->editResize(0);
-  ASSERT_EQ(0U, buf->size());
-  buf->release();
+TEST(SharedBufferTest, editResize_death) {
+    android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+    EXPECT_DEATH(buf->editResize(SIZE_MAX - sizeof(android::SharedBuffer)), "");
+    buf = android::SharedBuffer::alloc(10);
+    EXPECT_DEATH(buf->editResize(SIZE_MAX), "");
+}
+
+TEST(SharedBufferTest, editResize_null) {
+    // Big enough to fail, not big enough to abort.
+    SKIP_WITH_HWASAN;  // hwasan has a 2GiB allocation limit.
+    android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+    ASSERT_EQ(nullptr, buf->editResize(SIZE_MAX / 2));
+}
+
+TEST(SharedBufferTest, editResize_zero_size) {
+    android::SharedBuffer* buf = android::SharedBuffer::alloc(10);
+    buf = buf->editResize(0);
+    ASSERT_EQ(0U, buf->size());
+    buf->release();
 }
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index 3978593..9892ae7 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -2,6 +2,8 @@
 
 ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
   my_gsi_avb_keys_path := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+else ifeq ($(BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT),true)
+  my_gsi_avb_keys_path := $(TARGET_VENDOR_RAMDISK_OUT)/avb
 else
   my_gsi_avb_keys_path := $(TARGET_RAMDISK_OUT)/avb
 endif
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 7edf3c3..3146f36 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -561,6 +561,11 @@
     # Make sure that apexd is started in the default namespace
     enter_default_mount_ns
 
+    mkdir /data/vendor 0771 root root encryption=Require
+    mkdir /data/vendor_ce 0771 root root encryption=None
+    mkdir /data/vendor_de 0771 root root encryption=None
+    mkdir /data/vendor/hardware 0771 root root
+
     # Start tombstoned early to be able to store tombstones.
     mkdir /data/tombstones 0771 system system encryption=Require
     mkdir /data/vendor/tombstones 0771 root root
@@ -653,11 +658,6 @@
 
     mkdir /data/preloads 0775 system system encryption=None
 
-    mkdir /data/vendor 0771 root root encryption=Require
-    mkdir /data/vendor_ce 0771 root root encryption=None
-    mkdir /data/vendor_de 0771 root root encryption=None
-    mkdir /data/vendor/hardware 0771 root root
-
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell