vm_tools: arcvm: Add support for Android fstab.

Android uses device tree to do first stage mount. Android Pie
and crosvm both support it already. We just need to enable it with
--android-fstab command line flag.

BUG=b:140846468
TEST=manual - Boot ARCVM to check /proc/device-tree/firmware/android/fstab

Change-Id: Ie62f1be94b0b1e5a2a77ebb59f33cda7c70c2fe9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/1820040
Reviewed-by: Yusuke Sato <yusukes@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Tested-by: Lepton Wu <lepton@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
diff --git a/arc/vm/launch/arcvm_launch.cc b/arc/vm/launch/arcvm_launch.cc
index 2887d56..9fbabc4 100644
--- a/arc/vm/launch/arcvm_launch.cc
+++ b/arc/vm/launch/arcvm_launch.cc
@@ -44,6 +44,7 @@
 constexpr char kKernel[] = "vmlinux";
 constexpr char kRootFs[] = "system.raw.img";
 constexpr char kVendorImage[] = "vendor.raw.img";
+constexpr char kFstab[] = "fstab";
 
 constexpr auto DEFAULT_TIMEOUT = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
 
@@ -305,6 +306,9 @@
   disk_image->set_writable(false);
   disk_image->set_do_mount(true);
 
+  // Add Android fstab
+  request.set_fstab(SelectDlcOrBuiltin(base::FilePath(kFstab)).value());
+
   return request;
 }
 
diff --git a/system_api/dbus/vm_concierge/service.proto b/system_api/dbus/vm_concierge/service.proto
index 7fe7d15..3fb6b58 100644
--- a/system_api/dbus/vm_concierge/service.proto
+++ b/system_api/dbus/vm_concierge/service.proto
@@ -162,6 +162,9 @@
 
   // Parameters to pass to the ARCVM's init process.
   repeated string params = 5;
+
+  // Path to Android fstab.
+  string fstab = 6;
 }
 
 enum VmStatus {
diff --git a/vm_tools/concierge/arc_vm.cc b/vm_tools/concierge/arc_vm.cc
index cadf922..4eaee36 100644
--- a/vm_tools/concierge/arc_vm.cc
+++ b/vm_tools/concierge/arc_vm.cc
@@ -86,6 +86,7 @@
 std::unique_ptr<ArcVm> ArcVm::Create(
     base::FilePath kernel,
     base::FilePath rootfs,
+    base::FilePath fstab,
     std::vector<ArcVm::Disk> disks,
     arc_networkd::MacAddress mac_addr,
     std::unique_ptr<arc_networkd::Subnet> subnet,
@@ -98,8 +99,8 @@
       std::move(mac_addr), std::move(subnet), vsock_cid,
       std::move(seneschal_server_proxy), std::move(runtime_dir), features));
 
-  if (!vm->Start(std::move(kernel), std::move(rootfs), std::move(disks),
-                 std::move(params))) {
+  if (!vm->Start(std::move(kernel), std::move(rootfs), std::move(fstab),
+                 std::move(disks), std::move(params))) {
     vm.reset();
   }
 
@@ -112,6 +113,7 @@
 
 bool ArcVm::Start(base::FilePath kernel,
                   base::FilePath rootfs,
+                  base::FilePath fstab,
                   std::vector<ArcVm::Disk> disks,
                   std::vector<string> params) {
   // Set up the tap device.
@@ -138,6 +140,7 @@
     "--syslog-tag",   base::StringPrintf("ARCVM(%u)", vsock_cid_),
     "--cras-audio",
     "--cras-capture",
+    "--android-fstab", fstab.value(),
     "--params",       base::JoinString(params, " "),
   };
   // clang-format on
diff --git a/vm_tools/concierge/arc_vm.h b/vm_tools/concierge/arc_vm.h
index ea389a7..73bee61 100644
--- a/vm_tools/concierge/arc_vm.h
+++ b/vm_tools/concierge/arc_vm.h
@@ -49,6 +49,7 @@
   static std::unique_ptr<ArcVm> Create(
       base::FilePath kernel,
       base::FilePath rootfs,
+      base::FilePath fstab,
       std::vector<Disk> disks,
       arc_networkd::MacAddress mac_addr,
       std::unique_ptr<arc_networkd::Subnet> subnet,
@@ -126,6 +127,7 @@
   // Starts the VM with the given kernel and root file system.
   bool Start(base::FilePath kernel,
              base::FilePath rootfs,
+             base::FilePath fstab,
              std::vector<Disk> disks,
              std::vector<std::string> params);
 
diff --git a/vm_tools/concierge/client.cc b/vm_tools/concierge/client.cc
index 08a2fbe..e3534a6 100644
--- a/vm_tools/concierge/client.cc
+++ b/vm_tools/concierge/client.cc
@@ -1009,6 +1009,7 @@
                string name,
                string kernel,
                string rootfs,
+               string fstab,
                string extra_disks,
                const std::vector<string>& params) {
   constexpr char arcvm_prefix[] = "/opt/google/vms/android";
@@ -1033,6 +1034,16 @@
     LOG(INFO) << "using default rootfs " << rootfs;
   }
 
+  if (fstab.empty()) {
+    fstab = base::StringPrintf("%s/fstab", arcvm_prefix);
+    if (base::PathExists(base::FilePath(fstab))) {
+      LOG(INFO) << "using default fstab " << fstab;
+    } else {
+      LOG(ERROR) << fstab << " does not exist";
+      return -1;
+    }
+  }
+
   if (extra_disks.empty()) {
     std::string disk_name;
     base::Base64UrlEncode(name, base::Base64UrlEncodePolicy::INCLUDE_PADDING,
@@ -1063,6 +1074,7 @@
   vm_tools::concierge::StartArcVmRequest request;
   request.set_owner_id(std::move(cryptohome_id));
   request.set_name(std::move(name));
+  request.set_fstab(std::move(fstab));
 
   request.mutable_vm()->set_kernel(std::move(kernel));
   request.mutable_vm()->set_rootfs(std::move(rootfs));
@@ -1457,6 +1469,7 @@
   DEFINE_string(container_name, "", "Name of the container within the VM");
   DEFINE_string(removable_media, "", "Name of the removable media to use");
   DEFINE_string(image_name, "", "Name of the file on removable media to use");
+  DEFINE_string(android_fstab, "", "Path to the Android fstab");
 
   // create_disk parameters.
   DEFINE_string(cryptohome_id, "", "User cryptohome id");
@@ -1584,7 +1597,8 @@
   } else if (FLAGS_start_arc_vm) {
     return StartArcVm(proxy, std::move(FLAGS_cryptohome_id),
                       std::move(FLAGS_name), std::move(FLAGS_kernel),
-                      std::move(FLAGS_rootfs), std::move(FLAGS_extra_disks),
+                      std::move(FLAGS_rootfs), std::move(FLAGS_android_fstab),
+                      std::move(FLAGS_extra_disks),
                       base::CommandLine::ForCurrentProcess()->GetArgs());
   } else if (FLAGS_sync_time) {
     return SyncVmTimes(proxy);
diff --git a/vm_tools/concierge/service.cc b/vm_tools/concierge/service.cc
index 26976e2..3989dc3 100644
--- a/vm_tools/concierge/service.cc
+++ b/vm_tools/concierge/service.cc
@@ -1595,6 +1595,7 @@
 
   const base::FilePath kernel(request.vm().kernel());
   const base::FilePath rootfs(request.vm().rootfs());
+  const base::FilePath fstab(request.fstab());
 
   if (!base::PathExists(kernel)) {
     LOG(ERROR) << "Missing VM kernel path: " << kernel.value();
@@ -1612,6 +1613,14 @@
     return dbus_response;
   }
 
+  if (!base::PathExists(fstab)) {
+    LOG(ERROR) << "Missing VM fstab path: " << fstab.value();
+
+    response.set_failure_reason("Fstab path does not exist");
+    writer.AppendProtoAsArrayOfBytes(response);
+    return dbus_response;
+  }
+
   std::vector<ArcVm::Disk> disks;
   for (const auto& disk : request.disks()) {
     if (!base::PathExists(base::FilePath(disk.path()))) {
@@ -1682,8 +1691,8 @@
   features.gpu = base::SysInfo::OperatingSystemArchitecture() == "x86_64";
 
   auto vm = ArcVm::Create(std::move(kernel), std::move(rootfs),
-                          std::move(disks), kArcVmMacAddress, std::move(subnet),
-                          vsock_cid, std::move(server_proxy),
+                          std::move(fstab), std::move(disks), kArcVmMacAddress,
+                          std::move(subnet), vsock_cid, std::move(server_proxy),
                           std::move(runtime_dir), features, std::move(params));
   if (!vm) {
     LOG(ERROR) << "Unable to start VM";