Merge "Make fs_mgr_overlayfs_mount_fstab_entry() available for user builds"
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d5b8a61..c4874b8 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -35,6 +35,10 @@
 
 #include "utility.h"
 
+#ifndef DM_DEFERRED_REMOVE
+#define DM_DEFERRED_REMOVE (1 << 17)
+#endif
+
 namespace android {
 namespace dm {
 
@@ -133,6 +137,25 @@
     return DeleteDevice(name, 0ms);
 }
 
+bool DeviceMapper::DeleteDeviceDeferred(const std::string& name) {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+
+    io.flags |= DM_DEFERRED_REMOVE;
+    if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
+        PLOG(ERROR) << "DM_DEV_REMOVE with DM_DEFERRED_REMOVE failed for [" << name << "]";
+        return false;
+    }
+    return true;
+}
+
+bool DeviceMapper::DeleteDeviceIfExistsDeferred(const std::string& name) {
+    if (GetState(name) == DmDeviceState::INVALID) {
+        return true;
+    }
+    return DeleteDeviceDeferred(name);
+}
+
 static std::string GenerateUuid() {
     uuid_t uuid_bytes;
     uuid_generate(uuid_bytes);
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 41d3145..8006db2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -35,6 +35,7 @@
 #include <libdm/dm.h>
 #include <libdm/loop_control.h>
 #include "test_util.h"
+#include "utility.h"
 
 using namespace std;
 using namespace std::chrono_literals;
@@ -617,3 +618,64 @@
     auto sub_block_device = dm.GetParentBlockDeviceByPath(dev.path());
     ASSERT_EQ(loop.device(), *sub_block_device);
 }
+
+TEST(libdm, DeleteDeviceDeferredNoReferences) {
+    unique_fd tmp(CreateTempFile("file_1", 4096));
+    ASSERT_GE(tmp, 0);
+    LoopDevice loop(tmp, 10s);
+    ASSERT_TRUE(loop.valid());
+
+    DmTable table;
+    ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop.device(), 0));
+    ASSERT_TRUE(table.valid());
+    TempDevice dev("libdm-test-dm-linear", table);
+    ASSERT_TRUE(dev.valid());
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+
+    std::string path;
+    ASSERT_TRUE(dm.GetDmDevicePathByName("libdm-test-dm-linear", &path));
+    ASSERT_EQ(0, access(path.c_str(), F_OK));
+
+    ASSERT_TRUE(dm.DeleteDeviceDeferred("libdm-test-dm-linear"));
+
+    ASSERT_TRUE(WaitForFileDeleted(path, 5s));
+    ASSERT_EQ(DmDeviceState::INVALID, dm.GetState("libdm-test-dm-linear"));
+    ASSERT_NE(0, access(path.c_str(), F_OK));
+    ASSERT_EQ(ENOENT, errno);
+}
+
+TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) {
+    unique_fd tmp(CreateTempFile("file_1", 4096));
+    ASSERT_GE(tmp, 0);
+    LoopDevice loop(tmp, 10s);
+    ASSERT_TRUE(loop.valid());
+
+    DmTable table;
+    ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop.device(), 0));
+    ASSERT_TRUE(table.valid());
+    TempDevice dev("libdm-test-dm-linear", table);
+    ASSERT_TRUE(dev.valid());
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+
+    std::string path;
+    ASSERT_TRUE(dm.GetDmDevicePathByName("libdm-test-dm-linear", &path));
+    ASSERT_EQ(0, access(path.c_str(), F_OK));
+
+    {
+        // Open a reference to block device.
+        unique_fd fd(TEMP_FAILURE_RETRY(open(dev.path().c_str(), O_RDONLY | O_CLOEXEC)));
+        ASSERT_GE(fd.get(), 0);
+
+        ASSERT_TRUE(dm.DeleteDeviceDeferred("libdm-test-dm-linear"));
+
+        ASSERT_EQ(0, access(path.c_str(), F_OK));
+    }
+
+    // After release device will be removed.
+    ASSERT_TRUE(WaitForFileDeleted(path, 5s));
+    ASSERT_EQ(DmDeviceState::INVALID, dm.GetState("libdm-test-dm-linear"));
+    ASSERT_NE(0, access(path.c_str(), F_OK));
+    ASSERT_EQ(ENOENT, errno);
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 5d6db46..70b14fa 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -95,6 +95,12 @@
     bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
     bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms);
 
+    // Enqueues a deletion of device mapper device with the given name once last reference is
+    // closed.
+    // Returns 'true' on success, false otherwise.
+    bool DeleteDeviceDeferred(const std::string& name);
+    bool DeleteDeviceIfExistsDeferred(const std::string& name);
+
     // Fetches and returns the complete state of the underlying device mapper
     // device with given name.
     std::optional<Info> GetDetailedInfo(const std::string& name) const;
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 3888eb1..767cd04 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -103,6 +103,7 @@
     void ReadSnapshotDeviceAndValidate();
     void Shutdown();
     void MergeInterrupt();
+    void ReadDmUserBlockWithoutDaemon();
 
     std::string snapshot_dev() const { return snapshot_dev_->path(); }
 
@@ -481,6 +482,36 @@
     ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
 }
 
+void CowSnapuserdTest::ReadDmUserBlockWithoutDaemon() {
+    DmTable dmuser_table;
+    std::string dm_user_name = "dm-test-device";
+    unique_fd fd;
+
+    // Create a dm-user block device
+    ASSERT_TRUE(dmuser_table.AddTarget(std::make_unique<DmTargetUser>(0, 123456, dm_user_name)));
+    ASSERT_TRUE(dmuser_table.valid());
+
+    dmuser_dev_ = std::make_unique<TempDevice>(dm_user_name, dmuser_table);
+    ASSERT_TRUE(dmuser_dev_->valid());
+    ASSERT_FALSE(dmuser_dev_->path().empty());
+
+    fd.reset(open(dmuser_dev_->path().c_str(), O_RDONLY));
+    ASSERT_GE(fd, 0);
+
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(1_MiB);
+
+    loff_t offset = 0;
+    // Every IO should fail as there is no daemon to process the IO
+    for (size_t j = 0; j < 10; j++) {
+        ASSERT_EQ(ReadFullyAtOffset(fd, (char*)buffer.get() + offset, BLOCK_SZ, offset), false);
+
+        offset += BLOCK_SZ;
+    }
+
+    fd = {};
+    ASSERT_TRUE(dmuser_dev_->Destroy());
+}
+
 void CowSnapuserdTest::InitDaemon() {
     bool ok = client_->AttachDmUser(system_device_ctrl_name_);
     ASSERT_TRUE(ok);
@@ -909,6 +940,11 @@
     harness.Shutdown();
 }
 
+TEST(Snapuserd_Test, ReadDmUserBlockWithoutDaemon) {
+    CowSnapuserdTest harness;
+    harness.ReadDmUserBlockWithoutDaemon();
+}
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 5eb2003..67189d4 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -36,7 +36,9 @@
                  "  dump\n"
                  "    Print snapshot states.\n"
                  "  merge\n"
-                 "    Deprecated.\n";
+                 "    Deprecated.\n"
+                 "  map\n"
+                 "    Map all partitions at /dev/block/mapper\n";
     return EX_USAGE;
 }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index ab0e48e..0e788e4 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -478,6 +478,11 @@
     // cut the last "\n"
     backing_dev.erase(backing_dev.length() - 1);
 
+    if (android::base::StartsWith(backing_dev, "none")) {
+        LOG(INFO) << "No zram backing device configured";
+        return {};
+    }
+
     // shutdown zram handle
     Timer swap_timer;
     LOG(INFO) << "swapoff() start...";
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 8f22d89..c471fa0 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -127,7 +127,7 @@
 #define AID_EXT_DATA_RW 1078      /* GID for app-private data directories on external storage */
 #define AID_EXT_OBB_RW 1079       /* GID for OBB directories on external storage */
 #define AID_CONTEXT_HUB 1080      /* GID for access to the Context Hub */
-#define AID_VIRTMANAGER 1081      /* VirtManager daemon */
+#define AID_VIRTUALIZATIONSERVICE 1081 /* VirtualizationService daemon */
 #define AID_ARTD 1082             /* ART Service daemon */
 #define AID_UWB 1083              /* UWB subsystem */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 56e774b..3101974 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -67,9 +67,9 @@
 # CDMA radio interface MUX
 /dev/ppp                  0660   radio      vpn
 
-# Virtualisation is managed by Virt Manager
-/dev/kvm                  0600   virtmanager root
-/dev/vhost-vsock          0600   virtmanager root
+# Virtualization is managed by VirtualizationService.
+/dev/kvm                  0600   virtualizationservice root
+/dev/vhost-vsock          0600   virtualizationservice root
 
 # sysfs properties
 /sys/devices/platform/trusty.*      trusty_version        0440  root   log