Add options to specify using a blank userdata image.

Bug: 71817605
Test: Create and use the userdata_blank.img successfully
Change-Id: Ic37ab9dc0d7c49628faeafb3c6d03b03b29227f5
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 435d2b2..dbcce2b 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -57,6 +57,12 @@
 DEFINE_string(cache_image, "", "Location of the cache partition image.");
 DEFINE_int32(cpus, 2, "Virtual CPU count.");
 DEFINE_string(data_image, "", "Location of the data partition image.");
+DEFINE_string(data_policy, "use_existing", "How to handle userdata partition."
+            " Either 'use_existing', 'create_if_missing', or 'always_create'.");
+DEFINE_int32(blank_data_image_mb, 0,
+             "The size of the blank data image to generate, MB.");
+DEFINE_string(blank_data_image_fmt, "ext4",
+              "The fs format for the blank data image. Used with mkfs.");
 DEFINE_bool(disable_app_armor_security, false,
             "Disable AppArmor security in libvirt. For debug only.");
 DEFINE_bool(disable_dac_security, false,
@@ -98,10 +104,14 @@
 DEFINE_string(uuid, g_default_uuid.c_str(),
               "UUID to use for the device. Random if not specified");
 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
-            "host kernel. This is only used during transition of our clients."
-            "Will be deprecated soon.");
+            " host kernel. This is only used during transition of our clients."
+            " Will be deprecated soon.");
 
 namespace {
+const std::string kDataPolicyUseExisting = "use_existing";
+const std::string kDataPolicyCreateIfMissing = "create_if_missing";
+const std::string kDataPolicyAlwaysCreate = "always_create";
+
 Json::Value LoadLayoutFile(const std::string& file) {
   char real_file_path[PATH_MAX];
   if (realpath(file.c_str(), real_file_path) == nullptr) {
@@ -223,8 +233,6 @@
   KernelLogMonitor& operator=(const KernelLogMonitor&) = delete;
 };
 
-}  // anonymous namespace
-
 void subprocess(const char* const* command) {
   pid_t pid = fork();
   if (!pid) {
@@ -242,6 +250,29 @@
   }
 }
 
+void CreateBlankImage(
+    const std::string& image, int image_mb, const std::string& image_fmt) {
+  LOG(INFO) << "Creating " << image;
+  std::string of = "of=";
+  of += image;
+  std::string count = "count=";
+  count += std::to_string(image_mb);
+  const char* dd_command[]{
+    "/bin/dd", "if=/dev/zero", of.c_str(), "bs=1M", count.c_str(), NULL};
+  subprocess(dd_command);
+  const char* mkfs_command[]{
+    "/usr/bin/sudo", "/sbin/mkfs", "-t", image_fmt.c_str(), image.c_str(), NULL};
+  subprocess(mkfs_command);
+}
+
+void RemoveFile(const std::string& file) {
+  LOG(INFO) << "Removing " << file;
+  const char* rm_command[]{
+    "/usr/bin/sudo", "/bin/rm", "-f", file.c_str(), NULL};
+  subprocess(rm_command);
+}
+}  // anonymous namespace
+
 int main(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, true);
@@ -283,6 +314,38 @@
     FLAGS_cache_image = FLAGS_system_image_dir + "/cache.img";
   }
 
+  if (FLAGS_data_policy == kDataPolicyCreateIfMissing) {
+    FLAGS_data_image = FLAGS_system_image_dir + "/userdata_blank.img";
+    if (FLAGS_blank_data_image_mb <= 0) {
+      LOG(FATAL) << "You should use -blank_data_image_mb with -data_policy="
+                 << kDataPolicyCreateIfMissing;
+    }
+    // Create a blank data image if the image doesn't exist yet
+    if ((stat(FLAGS_data_image.c_str(), &unused) == -1) && (errno == ENOENT)) {
+      CreateBlankImage(
+          FLAGS_data_image, FLAGS_blank_data_image_mb, FLAGS_blank_data_image_fmt);
+    } else {
+      LOG(INFO) << FLAGS_data_image << " exists. Not creating it.";
+    }
+  } else if (FLAGS_data_policy == kDataPolicyAlwaysCreate) {
+    FLAGS_data_image = FLAGS_system_image_dir + "/userdata_blank.img";
+    if (FLAGS_blank_data_image_mb <= 0) {
+      LOG(FATAL) << "You should use -blank_data_image_mb with -data_policy="
+                 << kDataPolicyAlwaysCreate;
+    }
+    RemoveFile(FLAGS_data_image);
+    CreateBlankImage(
+        FLAGS_data_image, FLAGS_blank_data_image_mb, FLAGS_blank_data_image_fmt);
+  } else if (FLAGS_data_policy == kDataPolicyUseExisting) {
+    // Do nothing. Use FLAGS_data_image.
+    if (FLAGS_blank_data_image_mb > 0) {
+      LOG(FATAL) << "You should NOT use -blank_data_image_mb with -data_policy="
+                 << kDataPolicyUseExisting;
+    }
+  } else {
+    LOG(FATAL) << "Invalid data_policy: " << FLAGS_data_policy;
+  }
+
   if (FLAGS_data_image.empty()) {
     FLAGS_data_image = FLAGS_system_image_dir + "/userdata.img";
   }