Merge "autfs: Replace use of cfg_if with hardened cast" into main
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index a2d5f94..98b2f7b 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -990,6 +990,10 @@
 
         vm_config.devices.clone_from(&custom_config.devices);
         vm_config.networkSupported = custom_config.networkSupported;
+
+        for param in custom_config.extraKernelCmdlineParams.iter() {
+            append_kernel_param(param, &mut vm_config);
+        }
     }
 
     if config.memoryMib > 0 {
@@ -1542,6 +1546,17 @@
     Ok(())
 }
 
+fn check_no_extra_kernel_cmdline_params(config: &VirtualMachineConfig) -> binder::Result<()> {
+    let VirtualMachineConfig::AppConfig(config) = config else { return Ok(()) };
+    if let Some(custom_config) = &config.customConfig {
+        if !custom_config.extraKernelCmdlineParams.is_empty() {
+            return Err(anyhow!("debuggable_vms_improvements feature is disabled"))
+                .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+        }
+    }
+    Ok(())
+}
+
 fn check_protected_vm_is_supported() -> binder::Result<()> {
     let is_pvm_supported =
         hypervisor_props::is_protected_vm_supported().or_service_specific_exception(-1)?;
@@ -1563,6 +1578,9 @@
     if !cfg!(multi_tenant) {
         check_no_extra_apks(config)?;
     }
+    if !cfg!(debuggable_vms_improvements) {
+        check_no_extra_kernel_cmdline_params(config)?;
+    }
     Ok(())
 }
 
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index ee39d75..9123742 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -127,6 +127,9 @@
 
         /** Whether the VM should have network feature. */
         boolean networkSupported;
+
+        /** Additional parameters to pass to the VM's kernel cmdline. */
+        String[] extraKernelCmdlineParams;
     }
 
     /** Configuration parameters guarded by android.permission.USE_CUSTOM_VIRTUAL_MACHINE */
diff --git a/android/vm/Android.bp b/android/vm/Android.bp
index c1d9b6b..ba8b416 100644
--- a/android/vm/Android.bp
+++ b/android/vm/Android.bp
@@ -16,6 +16,7 @@
         "libbinder_rs",
         "libclap",
         "libenv_logger",
+        "libcfg_if",
         "libglob",
         "libhypervisor_props",
         "liblibc",
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 3c0887c..185ac34 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -75,14 +75,14 @@
 }
 
 impl CommonConfig {
-    #[cfg(network)]
     fn network_supported(&self) -> bool {
-        self.network_supported
-    }
-
-    #[cfg(not(network))]
-    fn network_supported(&self) -> bool {
-        false
+        cfg_if::cfg_if! {
+            if #[cfg(network)] {
+                self.network_supported
+            } else {
+                false
+            }
+        }
     }
 }
 
@@ -109,6 +109,23 @@
     /// Note: this is only supported on Android kernels android14-5.15 and higher.
     #[arg(long)]
     gdb: Option<NonZeroU16>,
+
+    /// Whether to enable earlycon. Only supported for debuggable Linux-based VMs.
+    #[cfg(debuggable_vms_improvements)]
+    #[arg(long)]
+    enable_earlycon: bool,
+}
+
+impl DebugConfig {
+    fn enable_earlycon(&self) -> bool {
+        cfg_if::cfg_if! {
+            if #[cfg(debuggable_vms_improvements)] {
+                self.enable_earlycon
+            } else {
+                false
+            }
+        }
+    }
 }
 
 #[derive(Args, Default)]
@@ -141,34 +158,34 @@
 }
 
 impl MicrodroidConfig {
-    #[cfg(vendor_modules)]
-    fn vendor(&self) -> &Option<PathBuf> {
-        &self.vendor
+    fn vendor(&self) -> Option<&PathBuf> {
+        cfg_if::cfg_if! {
+            if #[cfg(vendor_modules)] {
+                self.vendor.as_ref()
+            } else {
+                None
+            }
+        }
     }
 
-    #[cfg(not(vendor_modules))]
-    fn vendor(&self) -> Option<PathBuf> {
-        None
-    }
-
-    #[cfg(vendor_modules)]
     fn gki(&self) -> Option<&str> {
-        self.gki.as_deref()
+        cfg_if::cfg_if! {
+            if #[cfg(vendor_modules)] {
+                self.gki.as_deref()
+            } else {
+                None
+            }
+        }
     }
 
-    #[cfg(not(vendor_modules))]
-    fn gki(&self) -> Option<&str> {
-        None
-    }
-
-    #[cfg(device_assignment)]
-    fn devices(&self) -> &Vec<PathBuf> {
-        &self.devices
-    }
-
-    #[cfg(not(device_assignment))]
-    fn devices(&self) -> Vec<PathBuf> {
-        Vec::new()
+    fn devices(&self) -> &[PathBuf] {
+        cfg_if::cfg_if! {
+            if #[cfg(device_assignment)] {
+                &self.devices
+            } else {
+                &[]
+            }
+        }
     }
 }
 
@@ -219,35 +236,35 @@
 }
 
 impl RunAppConfig {
-    #[cfg(multi_tenant)]
     fn extra_apks(&self) -> &[PathBuf] {
-        &self.extra_apks
+        cfg_if::cfg_if! {
+            if #[cfg(multi_tenant)] {
+                &self.extra_apks
+            } else {
+                &[]
+            }
+        }
     }
 
-    #[cfg(not(multi_tenant))]
-    fn extra_apks(&self) -> &[PathBuf] {
-        &[]
-    }
-
-    #[cfg(llpvm_changes)]
     fn instance_id(&self) -> Result<PathBuf, Error> {
-        Ok(self.instance_id.clone())
+        cfg_if::cfg_if! {
+            if #[cfg(llpvm_changes)] {
+                Ok(self.instance_id.clone())
+            } else {
+                Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+            }
+        }
     }
 
-    #[cfg(not(llpvm_changes))]
-    fn instance_id(&self) -> Result<PathBuf, Error> {
-        Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
-    }
-
-    #[cfg(llpvm_changes)]
     fn set_instance_id(&mut self, instance_id_file: PathBuf) -> Result<(), Error> {
-        self.instance_id = instance_id_file;
-        Ok(())
-    }
-
-    #[cfg(not(llpvm_changes))]
-    fn set_instance_id(&mut self, _: PathBuf) -> Result<(), Error> {
-        Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+        cfg_if::cfg_if! {
+            if #[cfg(llpvm_changes)] {
+                self.instance_id = instance_id_file;
+                Ok(())
+            } else {
+                Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+            }
+        }
     }
 }
 
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index b3743ae..823546f 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -148,7 +148,7 @@
 
     let payload_config_str = format!("{:?}!{:?}", config.apk, payload);
 
-    let custom_config = CustomConfig {
+    let mut custom_config = CustomConfig {
         gdbPort: config.debug.gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
         vendorImage: vendor,
         devices: config
@@ -163,6 +163,21 @@
         ..Default::default()
     };
 
+    if config.debug.enable_earlycon() {
+        if config.debug.debug != DebugLevel::FULL {
+            bail!("earlycon is only supported for debuggable VMs")
+        }
+        if cfg!(target_arch = "aarch64") {
+            custom_config
+                .extraKernelCmdlineParams
+                .push(String::from("earlycon=uart8250,mmio,0x3f8"));
+        } else if cfg!(target_arch = "x86_64") {
+            custom_config.extraKernelCmdlineParams.push(String::from("earlycon=uart8250,io,0x3f8"));
+        } else {
+            bail!("unexpected architecture!");
+        }
+    }
+
     let vm_config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
         name: config.common.name.unwrap_or_else(|| String::from("VmRunApp")),
         apk: apk_fd.into(),
diff --git a/build/Android.bp b/build/Android.bp
index 66cc626..6ab1d89 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -44,6 +44,9 @@
     }) + select(release_flag("RELEASE_AVF_ENABLE_VIRT_CPUFREQ"), {
         true: ["virt_cpufreq"],
         default: [],
+    }) + select(release_flag("RELEASE_AVF_IMPROVE_DEBUGGABLE_VMS"), {
+        true: ["debuggable_vms_improvements"],
+        default: [],
     }) + select(release_flag("RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES"), {
         true: ["paravirtualized_devices"],
         default: [],
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index ce04317..8f9340b 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -276,8 +276,9 @@
     MEMORY.lock().as_mut().unwrap().unshare_all_memory();
 
     if let Some(mmio_guard) = get_mmio_guard() {
-        // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
-        if !debuggable_payload {
+        if cfg!(debuggable_vms_improvements) && debuggable_payload {
+            // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
+        } else {
             mmio_guard.unmap(UART_PAGE_ADDR).map_err(|e| {
                 error!("Failed to unshare the UART: {e}");
                 RebootReason::InternalError
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 85cacf9..644a85a 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -778,6 +778,7 @@
             VirtualMachineAppConfig.CustomConfig customConfig =
                     new VirtualMachineAppConfig.CustomConfig();
             customConfig.devices = EMPTY_STRING_ARRAY;
+            customConfig.extraKernelCmdlineParams = EMPTY_STRING_ARRAY;
             try {
                 customConfig.vendorImage =
                         ParcelFileDescriptor.open(mVendorDiskImage, MODE_READ_ONLY);