Support dynamic partitions feature by default

Add a new launcher parameter ("-super_image") which defaults on, to
enable the use of the super partition produced as part of a dynamic
partitions build. This supersedes the use of -system_image,
-vendor_image or -product_image; these parameters will no longer be
inferred by default, unless no super.img file is present.

If a super image is specified, a ramdisk is also required. The ramdisk
contains the fstab for setting up the dynamic partitions -- this means
the gsi_fstab feature is also deprecated, and the parameter becomes
unset. The "androidboot.boot_devices" parameter must also be specified
to tell the kernel where to look for the 'vda' device node when it
appears at early boot, as there is no devfs available at that time. It's
harmless to specify this extra flag even without dynamic partitions, so
just specify it always.

Bug: 113175337
Change-Id: If0613ed168ab83144d1ebff90f69d3a85cce66d1
Merged-In: If0613ed168ab83144d1ebff90f69d3a85cce66d1
Signed-off-by: Alistair Strachan <astrachan@google.com>
diff --git a/host/commands/launch/flags.cc b/host/commands/launch/flags.cc
index 3fa2717..0991d8a 100644
--- a/host/commands/launch/flags.cc
+++ b/host/commands/launch/flags.cc
@@ -92,6 +92,7 @@
               "Location of the system partition images.");
 DEFINE_string(vendor_image, "", "Location of the vendor partition image.");
 DEFINE_string(product_image, "", "Location of the product partition image.");
+DEFINE_string(super_image, "", "Location of the super partition image.");
 
 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
             " host kernel. This is only used during transition of our clients."
@@ -227,6 +228,9 @@
   std::string default_product_image = FLAGS_system_image_dir + "/product.img";
   SetCommandLineOptionWithMode("product_image", default_product_image.c_str(),
                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
+  std::string default_super_image = FLAGS_system_image_dir + "/super.img";
+  SetCommandLineOptionWithMode("super_image", default_super_image.c_str(),
+                               google::FlagSettingMode::SET_FLAGS_DEFAULT);
 
   return true;
 }
@@ -252,6 +256,8 @@
   // TODO(b/77276633): This should be handled as part of the GPU configuration
   tmp_config_obj.add_kernel_cmdline("androidboot.hardware.egl=swiftshader");
 
+  vm_manager::VmManager::ConfigureBootDevices(&tmp_config_obj);
+
   tmp_config_obj.set_serial_number(FLAGS_serial_number);
 
   tmp_config_obj.set_cpus(FLAGS_cpus);
@@ -290,9 +296,16 @@
     ramdisk_path = "";
   }
 
+  // Fallback for older builds, or builds from branches without DAP
+  if (!FLAGS_super_image.empty() && !cvd::FileHasContent(FLAGS_super_image.c_str())) {
+    LOG(INFO) << "No super image detected; assuming non-DAP build";
+    FLAGS_super_image.clear();
+  }
+
   // This needs to be done here because the dtb path depends on the presence of
-  // the ramdisk
-  if (FLAGS_dtb.empty()) {
+  // the ramdisk. If we are booting a super image, the fstab is passed through
+  // from the ramdisk, it should never be defined by dt.
+  if (FLAGS_super_image.empty() && FLAGS_dtb.empty()) {
     if (use_ramdisk) {
       FLAGS_dtb = vsoc::DefaultHostArtifactsPath("config/initrd-root.dtb");
     } else {
@@ -304,6 +317,9 @@
   if (!use_ramdisk) {
     tmp_config_obj.add_kernel_cmdline("root=/dev/vda");
   }
+  if (!FLAGS_super_image.empty()) {
+    tmp_config_obj.add_kernel_cmdline("androidboot.super_partition=vda");
+  }
   tmp_config_obj.add_kernel_cmdline("init=/init");
   tmp_config_obj.add_kernel_cmdline(
       concat("androidboot.serialno=", FLAGS_serial_number));
@@ -349,15 +365,26 @@
     tmp_config_obj.add_kernel_cmdline(FLAGS_extra_kernel_cmdline);
   }
 
+  if (FLAGS_super_image.empty()) {
+    tmp_config_obj.set_system_image_path(FLAGS_system_image);
+    tmp_config_obj.set_vendor_image_path(FLAGS_vendor_image);
+    tmp_config_obj.set_product_image_path(FLAGS_product_image);
+    tmp_config_obj.set_super_image_path("");
+    tmp_config_obj.set_dtb_path(FLAGS_dtb);
+    tmp_config_obj.set_gsi_fstab_path(FLAGS_gsi_fstab);
+  } else {
+    tmp_config_obj.set_system_image_path("");
+    tmp_config_obj.set_vendor_image_path("");
+    tmp_config_obj.set_product_image_path("");
+    tmp_config_obj.set_super_image_path(FLAGS_super_image);
+    tmp_config_obj.set_dtb_path("");
+    tmp_config_obj.set_gsi_fstab_path("");
+  }
+
   tmp_config_obj.set_ramdisk_image_path(ramdisk_path);
-  tmp_config_obj.set_system_image_path(FLAGS_system_image);
   tmp_config_obj.set_cache_image_path(FLAGS_cache_image);
   tmp_config_obj.set_data_image_path(FLAGS_data_image);
-  tmp_config_obj.set_vendor_image_path(FLAGS_vendor_image);
   tmp_config_obj.set_metadata_image_path(FLAGS_metadata_image);
-  tmp_config_obj.set_product_image_path(FLAGS_product_image);
-  tmp_config_obj.set_dtb_path(FLAGS_dtb);
-  tmp_config_obj.set_gsi_fstab_path(FLAGS_gsi_fstab);
 
   tmp_config_obj.set_mempath(FLAGS_mempath);
   tmp_config_obj.set_ivshmem_qemu_socket_path(
@@ -644,10 +671,11 @@
 
   // Check that the files exist
   for (const auto& file :
-       {config->system_image_path(), config->vendor_image_path(),
-        config->cache_image_path(), config->data_image_path(),
-        config->metadata_image_path(), config->product_image_path()}) {
-    if (!cvd::FileHasContent(file.c_str())) {
+       {config->system_image_path(), config->cache_image_path(),
+        config->data_image_path(), config->vendor_image_path(),
+        config->metadata_image_path(),  config->product_image_path(),
+        config->super_image_path()}) {
+    if (!file.empty() && !cvd::FileHasContent(file.c_str())) {
       LOG(ERROR) << "File not found: " << file;
       exit(cvd::kCuttlefishConfigurationInitError);
     }
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index af690ed..af42de8 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -94,6 +94,7 @@
 const char* kVendorImagePath = "vendor_image_path";
 const char* kMetadataImagePath = "metadata_image_path";
 const char* kProductImagePath = "product_image_path";
+const char* kSuperImagePath = "super_image_path";
 const char* kUsbV1SocketName = "usb_v1_socket_name";
 const char* kVhciPort = "vhci_port";
 const char* kUsbIpSocketName = "usb_ip_socket_name";
@@ -360,6 +361,14 @@
   SetPath(kMetadataImagePath, metadata_image_path);
 }
 
+std::string CuttlefishConfig::super_image_path() const {
+  return (*dictionary_)[kSuperImagePath].asString();
+}
+void CuttlefishConfig::set_super_image_path(
+    const std::string& super_image_path) {
+  SetPath(kSuperImagePath, super_image_path);
+}
+
 std::string CuttlefishConfig::product_image_path() const {
   return (*dictionary_)[kProductImagePath].asString();
 }
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 668badc..bc36540 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -138,6 +138,9 @@
   std::string product_image_path() const;
   void set_product_image_path(const std::string& product_image_path);
 
+  std::string super_image_path() const;
+  void set_super_image_path(const std::string& super_image_path);
+
   std::string dtb_path() const;
   void set_dtb_path(const std::string& dtb_path);
 
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index a5abd84..f20d33d 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -95,22 +95,42 @@
     -no-shutdown
     -boot "strict=on"
     -kernel "${kernel_image_path:-${HOME}/kernel}"
-    -append "${kernel_cmdline:-"loop.max_part=7 console=ttyS0 androidboot.console=ttyS1 androidboot.hardware=vsoc enforcing=0 audit=1 androidboot.selinux=permissive mac80211_hwsim.radios=0 security=selinux buildvariant=userdebug  androidboot.serialno=CUTTLEFISHCVD01 androidboot.lcd_density=160"}"
-    -dtb "${dtb_path:-${HOME}/config/cuttlefish.dtb}"
+    -append "${kernel_cmdline:-"loop.max_part=7 console=ttyS0 androidboot.console=ttyS1 androidboot.hardware=vsoc enforcing=0 audit=1 androidboot.selinux=permissive mac80211_hwsim.radios=0 security=selinux buildvariant=userdebug  androidboot.serialno=CUTTLEFISHCVD01 androidboot.lcd_density=160 androidboot.boot_devices=pci0000:00/0000:00:03.0"}"
     -device "piix3-usb-uhci,id=usb,addr=0x1.0x2"
     -device "virtio-serial-pci,id=virtio-serial0"
+)
+
+if [[ -n "${super_image_path}" ]]; then
+  args+=(
+    -drive "file=${super_image_path:-${HOME}/obj/PACKAGING/super.img_intermediates/super.img},format=raw,if=none,id=drive-virtio-disk0,aio=threads"
+    -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk0,id=virtio-disk0"
+  )
+else
+  args+=(
     -drive "file=${system_image_path:-${HOME}/system.img},format=raw,if=none,id=drive-virtio-disk0,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1"
+  )
+fi
+
+args+=(
     -drive "file=${data_image_path:-${HOME}/userdata.img},format=raw,if=none,id=drive-virtio-disk1,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk1,id=virtio-disk1"
     -drive "file=${cache_image_path:-${HOME}/cache.img},format=raw,if=none,id=drive-virtio-disk2,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk2,id=virtio-disk2"
     -drive "file=${metadata_image_path:-${HOME}/metadata.img},format=raw,if=none,id=drive-virtio-disk3,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk3,id=virtio-disk3"
+)
+
+if [[ -z "${super_image_path}" ]]; then
+  args+=(
     -drive "file=${vendor_image_path:-${HOME}/vendor.img},format=raw,if=none,id=drive-virtio-disk4,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk4,id=virtio-disk4"
     -drive "file=${product_image_path:-${HOME}/product.img},format=raw,if=none,id=drive-virtio-disk5,aio=threads"
     -device "virtio-blk-pci,scsi=off,drive=drive-virtio-disk5,id=virtio-disk5"
+  )
+fi
+
+args+=(
     -netdev "tap,id=hostnet0,ifname=${wifi_tap_name:-${default_wifi_tap_name}},script=no,downscript=no"
     -device "virtio-net-pci,netdev=hostnet0,id=net0"
     -netdev "tap,id=hostnet1,ifname=${mobile_tap_name:-${default_mobile_tap_name}},script=no,downscript=no"
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index a3b9082..300b1a1 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -53,6 +53,13 @@
 
 const std::string CrosvmManager::name() { return "crosvm"; }
 
+void CrosvmManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
+  // PCI domain 0, bus 0, device 5, function 0
+  // TODO There is no way to control this assignment with crosvm (yet)
+  config->add_kernel_cmdline(
+    "androidboot.boot_devices=pci0000:00/0000:00:05.0");
+}
+
 CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
     : VmManager(config) {}
 
@@ -75,12 +82,18 @@
   command.AddParameter("--mem=", config_->memory_mb());
   command.AddParameter("--cpus=", config_->cpus());
   command.AddParameter("--params=", config_->kernel_cmdline_as_string());
-  command.AddParameter("--rwdisk=", config_->system_image_path());
+  if (config_->super_image_path().empty()) {
+    command.AddParameter("--rwdisk=", config_->system_image_path());
+  } else {
+    command.AddParameter("--rwdisk=", config_->super_image_path());
+  }
   command.AddParameter("--rwdisk=", config_->data_image_path());
   command.AddParameter("--rwdisk=", config_->cache_image_path());
   command.AddParameter("--rwdisk=", config_->metadata_image_path());
-  command.AddParameter("--rwdisk=", config_->vendor_image_path());
-  command.AddParameter("--rwdisk=", config_->product_image_path());
+  if (config_->super_image_path().empty()) {
+    command.AddParameter("--rwdisk=", config_->vendor_image_path());
+    command.AddParameter("--rwdisk=", config_->product_image_path());
+  }
   command.AddParameter("--socket=", GetControlSocketPath(config_));
   if (!config_->gsi_fstab_path().empty()) {
     command.AddParameter("--android-fstab=", config_->gsi_fstab_path());
diff --git a/host/libs/vm_manager/crosvm_manager.h b/host/libs/vm_manager/crosvm_manager.h
index 7574e51..112d781 100644
--- a/host/libs/vm_manager/crosvm_manager.h
+++ b/host/libs/vm_manager/crosvm_manager.h
@@ -28,6 +28,7 @@
  public:
   static const std::string name();
   static bool EnsureInstanceDirExists(const std::string& instance_dir);
+  static void ConfigureBootDevices(vsoc::CuttlefishConfig* config);
 
   CrosvmManager(const vsoc::CuttlefishConfig* config);
   virtual ~CrosvmManager() = default;
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index bb8e0af..df78fc7 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -55,6 +55,13 @@
 
 const std::string QemuManager::name() { return "qemu_cli"; }
 
+void QemuManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
+  // PCI domain 0, bus 0, device 3, function 0
+  // This is controlled with 'addr=0x3' in cf_qemu.sh
+  config->add_kernel_cmdline(
+    "androidboot.boot_devices=pci0000:00/0000:00:03.0");
+}
+
 QemuManager::QemuManager(const vsoc::CuttlefishConfig* config)
   : VmManager(config) {}
 
@@ -77,6 +84,7 @@
   LogAndSetEnv("vendor_image_path", config_->vendor_image_path());
   LogAndSetEnv("metadata_image_path", config_->metadata_image_path());
   LogAndSetEnv("product_image_path", config_->product_image_path());
+  LogAndSetEnv("super_image_path", config_->super_image_path());
   LogAndSetEnv("wifi_tap_name", config_->wifi_tap_name());
   LogAndSetEnv("mobile_tap_name", config_->mobile_tap_name());
   LogAndSetEnv("kernel_log_socket_name",
diff --git a/host/libs/vm_manager/qemu_manager.h b/host/libs/vm_manager/qemu_manager.h
index a0c6540..4bcfe5a 100644
--- a/host/libs/vm_manager/qemu_manager.h
+++ b/host/libs/vm_manager/qemu_manager.h
@@ -26,6 +26,7 @@
 class QemuManager : public VmManager {
  public:
   static const std::string name();
+  static void ConfigureBootDevices(vsoc::CuttlefishConfig* config);
 
   QemuManager(const vsoc::CuttlefishConfig* config);
   virtual ~QemuManager() = default;
diff --git a/host/libs/vm_manager/vm_manager.cpp b/host/libs/vm_manager/vm_manager.cpp
index 5433d6d..b3aef11 100644
--- a/host/libs/vm_manager/vm_manager.cpp
+++ b/host/libs/vm_manager/vm_manager.cpp
@@ -40,17 +40,32 @@
 
 std::map<std::string, VmManager::VmManagerHelper>
     VmManager::vm_manager_helpers_ = {
-        {QemuManager::name(),
-         {[](const vsoc::CuttlefishConfig* config) {
-            return GetManagerSingleton<QemuManager>(config);
+        {
+          QemuManager::name(),
+          {
+            [](const vsoc::CuttlefishConfig* config) {
+              return GetManagerSingleton<QemuManager>(config);
+            },
+            []() { return vsoc::HostSupportsQemuCli(); },
+            [](vsoc::CuttlefishConfig* c) {
+              return QemuManager::ConfigureBootDevices(c);
+            }
           },
-          []() { return vsoc::HostSupportsQemuCli(); }}},
-        {CrosvmManager::name(),
-         {[](const vsoc::CuttlefishConfig* config) {
-            return GetManagerSingleton<CrosvmManager>(config);
-          },
-        // Same as Qemu for the time being
-          []() { return vsoc::HostSupportsQemuCli(); }}}};
+        },
+        {
+          CrosvmManager::name(),
+          {
+            [](const vsoc::CuttlefishConfig* config) {
+              return GetManagerSingleton<CrosvmManager>(config);
+            },
+            // Same as Qemu for the time being
+            []() { return vsoc::HostSupportsQemuCli(); },
+            [](vsoc::CuttlefishConfig* c) {
+              return CrosvmManager::ConfigureBootDevices(c);
+            }
+          }
+        }
+    };
 
 VmManager* VmManager::Get(const std::string& vm_manager_name,
                           const vsoc::CuttlefishConfig* config) {
@@ -70,6 +85,14 @@
          vm_manager_helpers_[name].support_checker();
 }
 
+void VmManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
+  auto it = vm_manager_helpers_.find(config->vm_manager());
+  if (it == vm_manager_helpers_.end()) {
+    return;
+  }
+  it->second.configure_boot_devices(config);
+}
+
 std::vector<std::string> VmManager::GetValidNames() {
   std::vector<std::string> ret = {};
   for (const auto& key_val: vm_manager_helpers_) {
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 84bf77c..3073ab6 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -35,6 +35,7 @@
   static VmManager* Get(const std::string& vm_manager_name,
                         const vsoc::CuttlefishConfig* config);
   static bool IsValidName(const std::string& name);
+  static void ConfigureBootDevices(vsoc::CuttlefishConfig* config);
   static bool IsVmManagerSupported(const std::string& name);
   static std::vector<std::string> GetValidNames();
 
@@ -58,6 +59,7 @@
     std::function<VmManager*(const vsoc::CuttlefishConfig*)> builder;
     // Whether the host packages support this vm manager
     std::function<bool()> support_checker;
+    std::function<void(vsoc::CuttlefishConfig*)> configure_boot_devices;
   };
   // Asociates a vm manager helper to every valid vm manager name
   static std::map<std::string, VmManagerHelper> vm_manager_helpers_;