Merge "Script to upload build artifacts via direct ssh" into cuttlefish-testing
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 71249ba..0201df9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "postsubmit": [
     {
       "name": "circqueue_test",
       "host": true
diff --git a/common/libs/auto_resources/TEST_MAPPING b/common/libs/auto_resources/TEST_MAPPING
index 1e34e75..5771ed3 100644
--- a/common/libs/auto_resources/TEST_MAPPING
+++ b/common/libs/auto_resources/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "postsubmit": [
     {
       "name": "auto_free_buffer_test",
       "host": true
diff --git a/common/libs/net/TEST_MAPPING b/common/libs/net/TEST_MAPPING
index a06d72a..d01ecf9 100644
--- a/common/libs/net/TEST_MAPPING
+++ b/common/libs/net/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "postsubmit": [
     {
       "name": "cuttlefish_net_tests",
       "host": true
diff --git a/common/libs/time/TEST_MAPPING b/common/libs/time/TEST_MAPPING
index 4c95014..af51510 100644
--- a/common/libs/time/TEST_MAPPING
+++ b/common/libs/time/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "postsubmit": [
     {
       "name": "monotonic_time_test",
       "host": true
diff --git a/host/commands/kernel_log_monitor/Android.bp b/host/commands/kernel_log_monitor/Android.bp
index a7197e5..7bc29e0 100644
--- a/host/commands/kernel_log_monitor/Android.bp
+++ b/host/commands/kernel_log_monitor/Android.bp
@@ -24,6 +24,7 @@
     ],
     shared_libs: [
         "libcuttlefish_fs",
+        "libcuttlefish_strings",
         "libcuttlefish_utils",
         "cuttlefish_auto_resources",
         "libbase",
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.cc b/host/commands/kernel_log_monitor/kernel_log_server.cc
index 0ecf5fe..84b2694 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.cc
+++ b/host/commands/kernel_log_monitor/kernel_log_server.cc
@@ -39,6 +39,8 @@
      monitor::BootEvent::MobileNetworkConnected},
     {"VIRTUAL_DEVICE_NETWORK_WIFI_CONNECTED",
      monitor::BootEvent::WifiNetworkConnected},
+    // TODO(b/131864854): Replace this with a string less likely to change
+    {"init: starting service 'adbd'", monitor::BootEvent::AdbdStarted},
 };
 
 void ProcessSubscriptions(
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.h b/host/commands/kernel_log_monitor/kernel_log_server.h
index 80a6cfa..f71ebb7 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.h
+++ b/host/commands/kernel_log_monitor/kernel_log_server.h
@@ -23,7 +23,6 @@
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/fs/shared_select.h"
-//#include "host/libs/monitor/kernel_log_client.h"
 
 namespace monitor {
 
@@ -33,6 +32,7 @@
   BootFailed = 2,
   WifiNetworkConnected = 3,
   MobileNetworkConnected = 4,
+  AdbdStarted = 5,
 };
 
 enum class SubscriptionAction {
diff --git a/host/commands/kernel_log_monitor/main.cc b/host/commands/kernel_log_monitor/main.cc
index f87f0ea..a17b1b8 100644
--- a/host/commands/kernel_log_monitor/main.cc
+++ b/host/commands/kernel_log_monitor/main.cc
@@ -15,12 +15,17 @@
  */
 
 #include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
 
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
 #include <common/libs/fs/shared_fd.h>
 #include <common/libs/fs/shared_select.h>
+#include <common/libs/strings/str_split.h>
 #include <host/libs/config/cuttlefish_config.h>
 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
 
@@ -28,14 +33,38 @@
              "A file descriptor representing a (UNIX) socket from which to "
              "read the logs. If -1 is given the socket is created according to "
              "the instance configuration");
-DEFINE_int32(subscriber_fd, -1,
-             "A file descriptor (a pipe) to write boot events to. If -1 is "
-             "given no events will be sent");
+DEFINE_string(subscriber_fds, "",
+             "A comma separated list of file descriptors (most likely pipes) to"
+             " send boot events to.");
+
+std::vector<cvd::SharedFD> SubscribersFromCmdline() {
+  // Validate the parameter
+  std::string fd_list = FLAGS_subscriber_fds;
+  for (auto c: fd_list) {
+    if (c != ',' && (c < '0' || c > '9')) {
+      LOG(ERROR) << "Invalid file descriptor list: " << fd_list;
+      std::exit(1);
+    }
+  }
+
+  auto fds = cvd::StrSplit(FLAGS_subscriber_fds, ',');
+  std::vector<cvd::SharedFD> shared_fds;
+  for (auto& fd_str: fds) {
+    auto fd = std::stoi(fd_str);
+    auto shared_fd = cvd::SharedFD::Dup(fd);
+    close(fd);
+    shared_fds.push_back(shared_fd);
+  }
+
+  return shared_fds;
+}
 
 int main(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, true);
 
+  auto subscriber_fds = SubscribersFromCmdline();
+
   // Disable default handling of SIGPIPE
   struct sigaction new_action {
   }, old_action{};
@@ -66,24 +95,22 @@
   monitor::KernelLogServer klog{server, config->PerInstancePath("kernel.log"),
                                 config->deprecated_boot_completed()};
 
-  if (FLAGS_subscriber_fd >= 0) {
-    auto pipe_fd = cvd::SharedFD::Dup(FLAGS_subscriber_fd);
-    close(FLAGS_subscriber_fd);
-    if (pipe_fd->IsOpen()) {
-      klog.SubscribeToBootEvents([pipe_fd](monitor::BootEvent evt) {
-        int retval = pipe_fd->Write(&evt, sizeof(evt));
+  for (auto subscriber_fd: subscriber_fds) {
+    if (subscriber_fd->IsOpen()) {
+      klog.SubscribeToBootEvents([subscriber_fd](monitor::BootEvent evt) {
+        int retval = subscriber_fd->Write(&evt, sizeof(evt));
         if (retval < 0) {
-          if (pipe_fd->GetErrno() != EPIPE) {
+          if (subscriber_fd->GetErrno() != EPIPE) {
             LOG(ERROR) << "Error while writing to pipe: "
-                       << pipe_fd->StrError();
+                       << subscriber_fd->StrError();
           }
-          pipe_fd->Close();
+          subscriber_fd->Close();
           return monitor::SubscriptionAction::CancelSubscription;
         }
         return monitor::SubscriptionAction::ContinueSubscription;
       });
     } else {
-      LOG(ERROR) << "Subscriber fd isn't valid: " << pipe_fd->StrError();
+      LOG(ERROR) << "Subscriber fd isn't valid: " << subscriber_fd->StrError();
       // Don't return here, we still need to write the logs to a file
     }
   }
diff --git a/host/commands/launch/flags.cc b/host/commands/launch/flags.cc
index f7f5d63..a761a74 100644
--- a/host/commands/launch/flags.cc
+++ b/host/commands/launch/flags.cc
@@ -97,6 +97,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."
@@ -244,6 +245,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;
 }
@@ -280,6 +284,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);
@@ -318,9 +324,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 {
@@ -332,6 +345,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));
@@ -379,15 +395,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(
@@ -474,7 +501,7 @@
     tmp_config_obj.add_kernel_cmdline("androidboot.tombstone_transmit=1");
     tmp_config_obj.add_kernel_cmdline(concat("androidboot.vsock_tombstone_port="
       ,FLAGS_tombstone_receiver_port));
-    // TODO (b/128842613) populate a cid flag to read the host CID during 
+    // TODO (b/128842613) populate a cid flag to read the host CID during
     // runtime
   } else {
     tmp_config_obj.add_kernel_cmdline("androidboot.tombstone_transmit=0");
@@ -693,10 +720,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/commands/launch/launch.cc b/host/commands/launch/launch.cc
index f247789..3d9a00b 100644
--- a/host/commands/launch/launch.cc
+++ b/host/commands/launch/launch.cc
@@ -136,20 +136,27 @@
 // subscription to boot events from the kernel log monitor will be created and
 // events will appear on *boot_events_pipe
 cvd::Command GetKernelLogMonitorCommand(const vsoc::CuttlefishConfig& config,
-                                        cvd::SharedFD* boot_events_pipe) {
+                                        cvd::SharedFD* boot_events_pipe,
+                                        cvd::SharedFD* adbd_events_pipe) {
   auto log_name = config.kernel_log_socket_name();
   auto server = cvd::SharedFD::SocketLocalServer(log_name.c_str(), false,
                                                  SOCK_STREAM, 0666);
   cvd::Command kernel_log_monitor(config.kernel_log_monitor_binary());
   kernel_log_monitor.AddParameter("-log_server_fd=", server);
-  if (boot_events_pipe) {
-    cvd::SharedFD pipe_write_end;
-    if (!cvd::SharedFD::Pipe(boot_events_pipe, &pipe_write_end)) {
-      LOG(ERROR) << "Unable to create boot events pipe: " << strerror(errno);
-      std::exit(LauncherExitCodes::kPipeIOError);
-    }
-    kernel_log_monitor.AddParameter("-subscriber_fd=", pipe_write_end);
+
+  cvd::SharedFD boot_pipe_write_end;
+  if (!cvd::SharedFD::Pipe(boot_events_pipe, &boot_pipe_write_end)) {
+    LOG(ERROR) << "Unable to create boot events pipe: " << strerror(errno);
+    std::exit(LauncherExitCodes::kPipeIOError);
   }
+  cvd::SharedFD adbd_pipe_write_end;
+  if (!cvd::SharedFD::Pipe(adbd_events_pipe, &adbd_pipe_write_end)) {
+    LOG(ERROR) << "Unable to create adbd events pipe: " << strerror(errno);
+    std::exit(LauncherExitCodes::kPipeIOError);
+  }
+  kernel_log_monitor.AddParameter("-subscriber_fds=", boot_pipe_write_end, ",",
+                                  adbd_pipe_write_end);
+
   return kernel_log_monitor;
 }
 
@@ -298,16 +305,22 @@
 }
 
 void LaunchAdbConnectorIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config) {
+                                 const vsoc::CuttlefishConfig& config,
+                                 cvd::SharedFD adbd_events_pipe) {
+  bool launch = false;
+  cvd::Command adb_connector(config.adb_connector_binary());
+  adb_connector.AddParameter("-adbd_events_fd=", adbd_events_pipe);
+
   if (AdbTcpConnectorEnabled(config)) {
-    cvd::Command adb_connector(config.adb_connector_binary());
+    launch = true;
     adb_connector.AddParameter(GetAdbConnectorTcpArg());
-    process_monitor->StartSubprocess(std::move(adb_connector),
-                                     GetOnSubprocessExitCallback(config));
   }
   if (AdbVsockConnectorEnabled(config)) {
-    cvd::Command adb_connector(config.adb_connector_binary());
+    launch = true;
     adb_connector.AddParameter(GetAdbConnectorVsockArg(config));
+  }
+
+  if (launch) {
     process_monitor->StartSubprocess(std::move(adb_connector),
                                      GetOnSubprocessExitCallback(config));
   }
diff --git a/host/commands/launch/launch.h b/host/commands/launch/launch.h
index 2e23c6f..c614b47 100644
--- a/host/commands/launch/launch.h
+++ b/host/commands/launch/launch.h
@@ -12,7 +12,8 @@
 
 cvd::Command GetIvServerCommand(const vsoc::CuttlefishConfig& config);
 cvd::Command GetKernelLogMonitorCommand(const vsoc::CuttlefishConfig& config,
-                                        cvd::SharedFD* boot_events_pipe);
+                                        cvd::SharedFD* boot_events_pipe,
+                                        cvd::SharedFD* adbd_events_pipe);
 void LaunchLogcatReceiverIfEnabled(const vsoc::CuttlefishConfig& config,
                                    cvd::ProcessMonitor* process_monitor);
 void LaunchConfigServer(const vsoc::CuttlefishConfig& config,
@@ -26,7 +27,8 @@
                                 cvd::ProcessMonitor* process_monitor,
                                 std::function<bool(cvd::MonitorEntry*)> callback);
 void LaunchAdbConnectorIfEnabled(cvd::ProcessMonitor* process_monitor,
-                                 const vsoc::CuttlefishConfig& config);
+                                 const vsoc::CuttlefishConfig& config,
+                                 cvd::SharedFD adbd_events_pipe);
 void LaunchSocketForwardProxyIfEnabled(cvd::ProcessMonitor* process_monitor,
                                  const vsoc::CuttlefishConfig& config);
 void LaunchSocketVsockProxyIfEnabled(cvd::ProcessMonitor* process_monitor,
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index ebede83..f651811 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -413,12 +413,10 @@
   cvd::ProcessMonitor process_monitor;
 
   cvd::SharedFD boot_events_pipe;
+  cvd::SharedFD adbd_events_pipe;
   // Only subscribe to boot events if running as daemon
   process_monitor.StartSubprocess(
-      GetKernelLogMonitorCommand(*config,
-                                 config->run_as_daemon()
-                                   ? &boot_events_pipe
-                                   : nullptr),
+      GetKernelLogMonitorCommand(*config, &boot_events_pipe, &adbd_events_pipe),
       GetOnSubprocessExitCallback(*config));
 
   SetUpHandlingOfBootEvents(&process_monitor, boot_events_pipe,
@@ -447,7 +445,7 @@
                            GetOnSubprocessExitCallback(*config));
   LaunchStreamAudioIfEnabled(*config, &process_monitor,
                              GetOnSubprocessExitCallback(*config));
-  LaunchAdbConnectorIfEnabled(&process_monitor, *config);
+  LaunchAdbConnectorIfEnabled(&process_monitor, *config, adbd_events_pipe);
 
   ServerLoop(launcher_monitor_socket, vm_manager); // Should not return
   LOG(ERROR) << "The server loop returned, it should never happen!!";
diff --git a/host/frontend/adb_connector/main.cpp b/host/frontend/adb_connector/main.cpp
index e046b3d..93a929d 100644
--- a/host/frontend/adb_connector/main.cpp
+++ b/host/frontend/adb_connector/main.cpp
@@ -25,12 +25,18 @@
 #include <gflags/gflags.h>
 
 #include <unistd.h>
+#include <host/commands/kernel_log_monitor/kernel_log_server.h>
 
+#include "common/libs/fs/shared_fd.h"
 #include "common/libs/strings/str_split.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/adb_connection_maintainer/adb_connection_maintainer.h"
 
-DEFINE_string(addresses, "", "Comma-separated list of addresses to 'adb connect' to");
+DEFINE_string(addresses, "", "Comma-separated list of addresses to "
+                             "'adb connect' to");
+DEFINE_int32(adbd_events_fd, -1, "A file descriptor. If set it will wait for "
+                                 "AdbdStarted boot event from the kernel log "
+                                 "monitor before trying to connect adb");
 
 namespace {
 void LaunchConnectionMaintainerThread(const std::string& address) {
@@ -49,12 +55,36 @@
     sleep(std::numeric_limits<unsigned int>::max());
   }
 }
+
+void WaitForAdbdToBeStarted(int events_fd) {
+  auto evt_shared_fd = cvd::SharedFD::Dup(events_fd);
+  close(events_fd);
+  while (evt_shared_fd->IsOpen()) {
+    monitor::BootEvent event;
+    auto bytes_read = evt_shared_fd->Read(&event, sizeof(event));
+    if (bytes_read != sizeof(event)) {
+      LOG(ERROR) << "Fail to read a complete event, read " << bytes_read
+                 << " bytes only instead of the expected " << sizeof(event);
+      // The file descriptor can't be trusted anymore, stop waiting and try to
+      // connect
+      return;
+    }
+    if (event == monitor::BootEvent::AdbdStarted) {
+      LOG(INFO) << "Adbd has started in the guest, connecting adb";
+      return;
+    }
+  }
+}
 }  // namespace
 
 int main(int argc, char* argv[]) {
   gflags::ParseCommandLineFlags(&argc, &argv, true);
   CHECK(!FLAGS_addresses.empty()) << "Must specify --addresses flag";
 
+  if (FLAGS_adbd_events_fd >= 0) {
+    WaitForAdbdToBeStarted(FLAGS_adbd_events_fd);
+  }
+
   for (auto address : ParseAddressList(FLAGS_addresses)) {
     LaunchConnectionMaintainerThread(address);
   }
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 1f4852b..ab723c8 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -96,6 +96,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";
@@ -393,6 +394,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 c52eb94..db28a2a 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -144,6 +144,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 157f7d1..669d43f 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -73,6 +73,13 @@
   return false;
 }
 
+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) {}
 
@@ -99,12 +106,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 646ae75..ac26ee8 100644
--- a/host/libs/vm_manager/crosvm_manager.h
+++ b/host/libs/vm_manager/crosvm_manager.h
@@ -28,7 +28,8 @@
  public:
   static const std::string name();
   static bool EnsureInstanceDirExists(const std::string& instance_dir);
-  static bool ConfigureGpu(vsoc::CuttlefishConfig *config);
+  static bool ConfigureGpu(vsoc::CuttlefishConfig* config);
+  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 ad2a026..f2cde65 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -54,6 +54,7 @@
 }  // namespace
 
 const std::string QemuManager::name() { return "qemu_cli"; }
+
 bool QemuManager::ConfigureGpu(vsoc::CuttlefishConfig *config) {
   if (config->gpu_mode() != vsoc::kGpuModeGuestAshmem) {
     return false;
@@ -68,6 +69,13 @@
   return true;
 }
 
+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) {}
 
@@ -90,6 +98,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 4226c30..ea24644 100644
--- a/host/libs/vm_manager/qemu_manager.h
+++ b/host/libs/vm_manager/qemu_manager.h
@@ -26,7 +26,8 @@
 class QemuManager : public VmManager {
  public:
   static const std::string name();
-  static bool ConfigureGpu(vsoc::CuttlefishConfig *config);
+  static bool ConfigureGpu(vsoc::CuttlefishConfig* config);
+  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 c3646d8..d613a56 100644
--- a/host/libs/vm_manager/vm_manager.cpp
+++ b/host/libs/vm_manager/vm_manager.cpp
@@ -49,6 +49,9 @@
             []() { return vsoc::HostSupportsQemuCli(); },
             [](vsoc::CuttlefishConfig* c) {
               return QemuManager::ConfigureGpu(c);
+            },
+            [](vsoc::CuttlefishConfig* c) {
+              return QemuManager::ConfigureBootDevices(c);
             }
           },
         },
@@ -62,6 +65,9 @@
             []() { return vsoc::HostSupportsQemuCli(); },
             [](vsoc::CuttlefishConfig* c) {
               return CrosvmManager::ConfigureGpu(c);
+            },
+            [](vsoc::CuttlefishConfig* c) {
+              return CrosvmManager::ConfigureBootDevices(c);
             }
           }
         }
@@ -93,6 +99,14 @@
   return it->second.configure_gpu_mode(config);
 }
 
+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 c62c186..ac93e26 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -36,6 +36,7 @@
                         const vsoc::CuttlefishConfig* config);
   static bool IsValidName(const std::string& name);
   static bool ConfigureGpuMode(vsoc::CuttlefishConfig* config);
+  static void ConfigureBootDevices(vsoc::CuttlefishConfig* config);
   static bool IsVmManagerSupported(const std::string& name);
   static std::vector<std::string> GetValidNames();
 
@@ -60,6 +61,7 @@
     // Whether the host packages support this vm manager
     std::function<bool()> support_checker;
     std::function<bool(vsoc::CuttlefishConfig*)> configure_gpu_mode;
+    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_;