Add basic support for remounting ext4 userdata into checkpoint

Metadata encrypted ext4 userdata and v2 encryption keys will be
supported in follow up CLs.

Test: adb shell /system/bin/vdc checkpoint startCheckpoint 1
Test: adb reboot userspace
Bug: 135984674
Bug: 143970043
Change-Id: I8dbf3bddd811cf54d3f2b2ee2c1ea64159d8c6e0
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index cb69037..2dc47bb 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1118,6 +1118,12 @@
             continue;
         }
 
+        // Terrible hack to make it possible to remount /data.
+        // TODO: refact fs_mgr_mount_all and get rid of this.
+        if (mount_mode == MOUNT_MODE_ONLY_USERDATA && current_entry.mount_point != "/data") {
+            continue;
+        }
+
         // Translate LABEL= file system labels into block devices.
         if (is_extfs(current_entry.fs_type)) {
             if (!TranslateExtLabels(&current_entry)) {
@@ -1351,6 +1357,7 @@
     return ret;
 }
 
+// TODO(b/143970043): return different error codes based on which step failed.
 int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
     auto entry = GetMountedEntryForUserdata(fstab);
     if (entry == nullptr) {
@@ -1374,12 +1381,29 @@
         }
         if (mount(entry->blk_device.c_str(), entry->mount_point.c_str(), "none",
                   MS_REMOUNT | entry->flags, entry->fs_options.c_str()) != 0) {
-            LERROR << "Failed to remount userdata in checkpointing mode";
+            PERROR << "Failed to remount userdata in checkpointing mode";
             return -1;
         }
     } else {
-        // STOPSHIP(b/143970043): support remounting for ext4.
-        LWARNING << "Remounting into checkpointing is not supported for ex4. Proceed with caution";
+        // STOPSHIP(b/143970043): support remounting for ext4 + metadata encryption.
+        if (should_use_metadata_encryption(*entry)) {
+            LWARNING << "Remounting into checkpointing is not supported for metadata encrypted "
+                     << "ext4 userdata. Proceed with caution";
+            return 0;
+        }
+        if (umount2("/data", UMOUNT_NOFOLLOW) != 0) {
+            PERROR << "Failed to umount /data";
+            return -1;
+        }
+        DeviceMapper& dm = DeviceMapper::Instance();
+        // TODO(b/143970043): need to delete every dm-device under the one userdata is mounted on.
+        if (!dm.DeleteDeviceIfExists("bow")) {
+            LERROR << "Failed to delete dm-bow";
+            return -1;
+        }
+        // TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
+        int result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
+        return result == FS_MGR_MNTALL_FAIL ? -1 : 0;
     }
     return 0;
 }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index ca67f37..9bc38f9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -46,7 +46,9 @@
 enum mount_mode {
     MOUNT_MODE_DEFAULT = 0,
     MOUNT_MODE_EARLY = 1,
-    MOUNT_MODE_LATE = 2
+    MOUNT_MODE_LATE = 2,
+    // TODO(b/135984674): remove this after refactoring fs_mgr_mount_all.
+    MOUNT_MODE_ONLY_USERDATA = 3
 };
 
 #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
diff --git a/init/reboot.cpp b/init/reboot.cpp
index c9b521a..b04db7f 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -186,17 +186,17 @@
     }
 }
 
-static Result<void> ShutdownVold() {
-    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
+static Result<void> CallVdc(const std::string& system, const std::string& cmd) {
+    const char* vdc_argv[] = {"/system/bin/vdc", system.c_str(), cmd.c_str()};
     int status;
     if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
                             nullptr) != 0) {
-        return ErrnoError() << "Failed to call 'vdc volume shutdown'";
+        return ErrnoError() << "Failed to call '/system/bin/vdc " << system << " " << cmd << "'";
     }
     if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
         return {};
     }
-    return Error() << "'vdc volume shutdown' failed : " << status;
+    return Error() << "'/system/bin/vdc " << system << " " << cmd << "' failed : " << status;
 }
 
 static void LogShutdownTime(UmountStat stat, Timer* t) {
@@ -658,7 +658,7 @@
     // 3. send volume shutdown to vold
     Service* vold_service = ServiceList::GetInstance().FindService("vold");
     if (vold_service != nullptr && vold_service->IsRunning()) {
-        ShutdownVold();
+        CallVdc("volume", "shutdown");
         vold_service->Stop();
     } else {
         LOG(INFO) << "vold not running, skipping vold shutdown";
@@ -774,8 +774,12 @@
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " post-data services are still running";
     }
-    // TODO(b/143970043): in case of ext4 we probably we will need to restart vold and kill zram
-    //  backing device.
+    if (auto result = KillZramBackingDevice(); !result) {
+        return result;
+    }
+    if (auto result = CallVdc("volume", "reset"); !result) {
+        return result;
+    }
     if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
                                              false /* SIGKILL */);
         r > 0) {