Merge "Re-implement libcompos_client in Rust"
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 425657f..3665687 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -51,9 +51,9 @@
         "init_second_stage",
         "microdroid_build_prop",
         "microdroid_init_rc",
+        "microdroid_ueventd_rc",
         "microdroid_launcher",
 
-        "ueventd.rc",
         "libbinder",
         "libbinder_ndk",
         "libstdc++",
@@ -136,6 +136,13 @@
     installable: false, // avoid collision with system partition's init.rc
 }
 
+prebuilt_etc {
+    name: "microdroid_ueventd_rc",
+    filename: "ueventd.rc",
+    src: "ueventd.rc",
+    installable: false, // avoid collision with system partition's ueventd.rc
+}
+
 prebuilt_root {
     name: "microdroid_build_prop",
     filename: "build.prop",
@@ -225,7 +232,15 @@
         },
         x86_64: {
             kernel_prebuilt: ":kernel_prebuilts-5.10-x86_64",
-            cmdline: microdroid_boot_cmdline + ["acpi=noirq"],
+            cmdline: microdroid_boot_cmdline + [
+                // console=none is to work around the x86 specific u-boot behavior which when
+                // console= option is not found in the kernel commandline console=ttyS0 is
+                // automatically added. By adding console=none, we can prevent u-boot from doing
+                // that. Note that console is set to hvc0 by bootconfig if the VM is configured as
+                // debuggable.
+                "console=none",
+                "acpi=noirq",
+            ],
         },
     },
 
diff --git a/microdroid/bootconfig.full_debuggable b/microdroid/bootconfig.full_debuggable
index f6afdcf..0d0457c 100644
--- a/microdroid/bootconfig.full_debuggable
+++ b/microdroid/bootconfig.full_debuggable
@@ -3,6 +3,7 @@
 
 # Kernel message is exported.
 kernel.printk.devkmsg=on
+kernel.console=hvc0
 
 # ADB is supported and rooting is possible. Note that
 # ro.adb.secure is still 0 (see build.prop) which means that adbd is started
diff --git a/microdroid/bootconfig.x86_64 b/microdroid/bootconfig.x86_64
index 75e4a80..20d64f7 100644
--- a/microdroid/bootconfig.x86_64
+++ b/microdroid/bootconfig.x86_64
@@ -1 +1 @@
-androidboot.boot_devices = pci0000:00/0000:00:01.0,pci0000:00/0000:00:02.0,pci0000:00/0000:00:03.0
+androidboot.boot_devices = pci0000:00/0000:00:02.0,pci0000:00/0000:00:03.0,pci0000:00/0000:00:04.0
diff --git a/microdroid/ueventd.rc b/microdroid/ueventd.rc
new file mode 100644
index 0000000..271e134
--- /dev/null
+++ b/microdroid/ueventd.rc
@@ -0,0 +1,26 @@
+uevent_socket_rcvbuf_size 16M
+
+subsystem dma_heap
+   devname uevent_devpath
+   dirname /dev/dma_heap
+
+/dev/null                 0666   root       root
+/dev/zero                 0666   root       root
+/dev/full                 0666   root       root
+/dev/ptmx                 0666   root       root
+/dev/tty                  0666   root       root
+/dev/random               0666   root       root
+/dev/urandom              0666   root       root
+/dev/ashmem*              0666   root       root
+/dev/binder               0666   root       root
+/dev/hwbinder             0666   root       root
+/dev/vndbinder            0666   root       root
+
+/dev/pmsg0                         0222   root       log
+/dev/dma_heap/system               0444   system     system
+/dev/dma_heap/system-uncached      0444   system     system
+/dev/dma_heap/system-secure        0444   system     system
+
+# these should not be world writable
+/dev/rtc0                 0640   system     system
+/dev/tty0                 0660   root       system
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index dc72c95..177a0db 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -240,13 +240,13 @@
 /// virtualizationservice in the host side.
 fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<()> {
     info!("executing main task {:?}...", task);
-    let mut child = build_command(task)?.spawn()?;
+    let mut command = build_command(task)?;
 
     let local_cid = get_local_cid()?;
     info!("notifying payload started");
     service.notifyPayloadStarted(local_cid as i32)?;
 
-    let exit_status = child.wait()?;
+    let exit_status = command.spawn()?.wait()?;
     if let Some(code) = exit_status.code() {
         info!("notifying payload finished");
         service.notifyPayloadFinished(local_cid as i32, code)?;
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 38e5bf3..4844657 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -238,12 +238,25 @@
         command.arg("--mem").arg(memory_mib.to_string());
     }
 
-    if let Some(log_fd) = config.log_fd {
+    // Setup the serial devices.
+    // 1. uart device: used as the output device by bootloaders and as early console by linux
+    // 2. virtio-console device: used as the console device
+    //
+    // When log_fd is not specified, the devices are attached to sink, which means what's written
+    // there is discarded.
+    //
+    // Warning: Adding more serial devices requires you to shift the PCI device ID of the boot
+    // disks in bootconfig.x86_64. This is because x86 crosvm puts serial devices and the block
+    // devices in the same PCI bus and serial devices comes before the block devices. Arm crosvm
+    // doesn't have the issue.
+    let backend = if let Some(log_fd) = config.log_fd {
         command.stdout(log_fd);
+        "stdout"
     } else {
-        // Ignore console output.
-        command.arg("--serial=type=sink");
-    }
+        "sink"
+    };
+    command.arg(format!("--serial=type={},hardware=serial", backend));
+    command.arg(format!("--serial=type={},hardware=virtio-console", backend));
 
     // Keep track of what file descriptors should be mapped to the crosvm process.
     let mut preserved_fds = config.indirect_files.iter().map(|file| file.as_raw_fd()).collect();
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 4c71c37..a59afd5 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -21,7 +21,7 @@
 };
 use android_system_virtualizationservice::binder::ParcelFileDescriptor;
 use anyhow::{anyhow, Context, Result};
-use binder::{wait_for_interface, Strong};
+use binder::wait_for_interface;
 use log::{error, info};
 use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
 use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
@@ -108,27 +108,28 @@
 }
 
 struct PackageManager {
-    service: Strong<dyn IPackageManagerNative>,
     // TODO(b/199146189) use IPackageManagerNative
     apex_info_list: &'static ApexInfoList,
 }
 
 impl PackageManager {
     fn new() -> Result<Self> {
-        let service = wait_for_interface(PACKAGE_MANAGER_NATIVE_SERVICE)
-            .context("Failed to find PackageManager")?;
         let apex_info_list = ApexInfoList::load()?;
-        Ok(Self { service, apex_info_list })
+        Ok(Self { apex_info_list })
     }
 
     fn get_apex_list(&self, prefer_staged: bool) -> Result<ApexInfoList> {
+        // get the list of active apexes
         let mut list = self.apex_info_list.clone();
+        // When prefer_staged, we override ApexInfo by consulting "package_native"
         if prefer_staged {
-            // When prefer_staged, we override ApexInfo by consulting "package_native"
-            let staged = self.service.getStagedApexModuleNames()?;
+            let pm =
+                wait_for_interface::<dyn IPackageManagerNative>(PACKAGE_MANAGER_NATIVE_SERVICE)
+                    .context("Failed to get service when prefer_staged is set.")?;
+            let staged = pm.getStagedApexModuleNames()?;
             for apex_info in list.list.iter_mut() {
                 if staged.contains(&apex_info.name) {
-                    let staged_apex_info = self.service.getStagedApexInfo(&apex_info.name)?;
+                    let staged_apex_info = pm.getStagedApexInfo(&apex_info.name)?;
                     if let Some(staged_apex_info) = staged_apex_info {
                         apex_info.path = PathBuf::from(staged_apex_info.diskImagePath);
                         // TODO(b/201788989) copy bootclasspath/systemserverclasspath