Snap for 13264465 from 01c814f2dddf9fa881d6af18e4a77359e60acd7e to 25Q2-release

Change-Id: Ia31e03175d21cb44b37a3052cdcda030c796f9af
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
index 0a1090d..fe92854 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
@@ -18,6 +18,7 @@
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import android.text.method.ScrollingMovementMethod
 import android.view.View
 import android.widget.TextView
 import java.io.IOException
@@ -34,6 +35,7 @@
 
         val button = findViewById<View>(R.id.recovery)
         button.setOnClickListener(View.OnClickListener { _ -> launchRecoveryActivity() })
+        findViewById<TextView>(R.id.cause).setMovementMethod(ScrollingMovementMethod())
     }
 
     override fun onNewIntent(intent: Intent) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index 542265a..14855ac 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -194,7 +194,7 @@
 
     fun closeTab(tab: TabLayout.Tab) {
         if (terminalTabAdapter.tabs.size == 1) {
-            finishAndRemoveTask()
+            finish()
         }
         viewPager.offscreenPageLimit -= 1
         terminalTabAdapter.deleteTab(tab.position)
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 190acc7..161a534 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -117,6 +117,9 @@
 const SECRETKEEPER_IDENTIFIER: &str =
     "android.hardware.security.secretkeeper.ISecretkeeper/default";
 
+const VM_CAPABILITIES_HAL_IDENTIFIER: &str =
+    "android.hardware.virtualization.capabilities.IVmCapabilitiesService/default";
+
 const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
 
 /// crosvm requires all partitions to be a multiple of 4KiB.
@@ -765,10 +768,11 @@
             }
         }
 
-        // TODO(b/391774181): handle vendor tee services (which require talking to HAL) as well.
-        if !vendor_tee_services.is_empty() {
-            return Err(anyhow!("support for vendor tee services is coming soon!"))
-                .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+        if !vendor_tee_services.is_empty() && !is_vm_capabilities_hal_supported() {
+            return Err(anyhow!(
+                "requesting access to tee services requires {VM_CAPABILITIES_HAL_IDENTIFIER}"
+            ))
+            .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
         }
 
         // TODO(b/391774181): remove this check in a follow-up patch.
@@ -1011,6 +1015,7 @@
             enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
             instance_id,
             custom_memory_backing_files,
+            start_suspended: !vendor_tee_services.is_empty(),
         };
         let instance = Arc::new(
             VmInstance::new(
@@ -1019,6 +1024,7 @@
                 requester_uid,
                 requester_debug_pid,
                 vm_context,
+                vendor_tee_services,
             )
             .with_context(|| format!("Failed to create VM with config {:?}", config))
             .with_log()
@@ -1719,6 +1725,16 @@
     fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine::IVirtualMachine> {
         BnVirtualMachine::new_binder(VirtualMachine { instance }, BinderFeatures::default())
     }
+
+    fn handle_vendor_tee_services(&self) -> binder::Result<()> {
+        // TODO(b/360102915): get vm_fd from crosvm
+        // TODO(b/360102915): talk to HAL
+        self.instance
+            .resume_full()
+            .with_context(|| format!("Error resuming VM with CID {}", self.instance.cid))
+            .with_log()
+            .or_service_specific_exception(-1)
+    }
 }
 
 impl Interface for VirtualMachine {}
@@ -1761,7 +1777,12 @@
             .start()
             .with_context(|| format!("Error starting VM with CID {}", self.instance.cid))
             .with_log()
-            .or_service_specific_exception(-1)
+            .or_service_specific_exception(-1)?;
+        if !self.instance.vendor_tee_services.is_empty() {
+            self.handle_vendor_tee_services()
+        } else {
+            Ok(())
+        }
     }
 
     fn stop(&self) -> binder::Result<()> {
@@ -2338,6 +2359,11 @@
         .expect("Could not check for declared Secretkeeper interface")
 }
 
+fn is_vm_capabilities_hal_supported() -> bool {
+    binder::is_declared(VM_CAPABILITIES_HAL_IDENTIFIER)
+        .expect("failed to check if {VM_CAPABILITIES_HAL_IDENTIFIER} is present")
+}
+
 impl VirtualMachineService {
     fn new_binder(state: Arc<Mutex<State>>, cid: Cid) -> Strong<dyn IVirtualMachineService> {
         BnVirtualMachineService::new_binder(
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 15a4199..c264185 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -142,6 +142,7 @@
     pub instance_id: [u8; 64],
     // (memfd, guest address, size)
     pub custom_memory_backing_files: Vec<(OwnedFd, u64, u64)>,
+    pub start_suspended: bool,
 }
 
 #[derive(Debug)]
@@ -419,6 +420,8 @@
     pub vm_metric: Mutex<VmMetric>,
     // Whether virtio-balloon is enabled
     pub balloon_enabled: bool,
+    /// List of vendor tee services this VM might access.
+    pub vendor_tee_services: Vec<String>,
     /// The latest lifecycle state which the payload reported itself to be in.
     payload_state: Mutex<PayloadState>,
     /// Represents the condition that payload_state was updated
@@ -446,6 +449,7 @@
         requester_uid: u32,
         requester_debug_pid: i32,
         vm_context: VmContext,
+        vendor_tee_services: Vec<String>,
     ) -> Result<VmInstance, Error> {
         validate_config(&config)?;
         let cid = config.cid;
@@ -473,6 +477,7 @@
             payload_state_updated: Condvar::new(),
             requester_uid_name,
             balloon_enabled,
+            vendor_tee_services,
         };
         info!("{} created", &instance);
         Ok(instance)
@@ -826,6 +831,18 @@
         }
         Ok(())
     }
+
+    /// Performs full resume of VM.
+    pub fn resume_full(&self) -> Result<(), Error> {
+        let socket_path_cstring = path_to_cstring(&self.crosvm_control_socket_path);
+        // SAFETY: Pointer is valid for the lifetime of the call.
+        let success =
+            unsafe { crosvm_control::crosvm_client_resume_vm_full(socket_path_cstring.as_ptr()) };
+        if !success {
+            bail!("Failed to resume VM");
+        }
+        Ok(())
+    }
 }
 
 impl Rss {
@@ -1431,6 +1448,10 @@
         }
     }
 
+    if config.start_suspended {
+        command.arg("--suspended");
+    }
+
     print_crosvm_args(&command);
 
     let result = SharedChild::spawn(&mut command)?;
diff --git a/android/virtmgr/src/debug_config.rs b/android/virtmgr/src/debug_config.rs
index 6e2bfef..e552cf4 100644
--- a/android/virtmgr/src/debug_config.rs
+++ b/android/virtmgr/src/debug_config.rs
@@ -191,7 +191,7 @@
 impl DebugConfig {
     pub fn new(config: &VirtualMachineConfig) -> Self {
         let debug_level = get_debug_level(config).unwrap_or(DebugLevel::NONE);
-        let debug_policy = Self::get_debug_policy().unwrap_or_else(|| {
+        let debug_policy = Self::get_debug_policy(config).unwrap_or_else(|| {
             info!("Debug policy is disabled");
             Default::default()
         });
@@ -204,7 +204,11 @@
         Self { debug_level, debug_policy, dump_device_tree }
     }
 
-    fn get_debug_policy() -> Option<DebugPolicy> {
+    fn get_debug_policy(config: &VirtualMachineConfig) -> Option<DebugPolicy> {
+        if matches!(config, VirtualMachineConfig::RawConfig(_)) {
+            info!("Debug policy ignored for non-Microdroid VM");
+            return None;
+        }
         let dp_sysprop = system_properties::read(CUSTOM_DEBUG_POLICY_OVERLAY_SYSPROP);
         let custom_dp = dp_sysprop.unwrap_or_else(|e| {
             warn!("Failed to read sysprop {CUSTOM_DEBUG_POLICY_OVERLAY_SYSPROP}: {e}");
diff --git a/build/microdroid/Android.bp b/build/microdroid/Android.bp
index 9152091..fac212a 100644
--- a/build/microdroid/Android.bp
+++ b/build/microdroid/Android.bp
@@ -476,19 +476,6 @@
     src: ":microdroid_16k_initrd_debuggable",
 }
 
-soong_config_module_type {
-    name: "flag_aware_avb_add_hash_footer_defaults",
-    module_type: "avb_add_hash_footer_defaults",
-    config_namespace: "ANDROID",
-    bool_variables: [
-        "release_avf_enable_llpvm_changes",
-    ],
-    properties: [
-        "rollback_index",
-        "props",
-    ],
-}
-
 avb_add_hash_footer_defaults {
     name: "microdroid_kernel_signed_defaults",
     src: ":empty_file",
@@ -508,44 +495,27 @@
 
 MICRODROID_GKI_ROLLBACK_INDEX = 2
 
-flag_aware_avb_add_hash_footer_defaults {
+avb_add_hash_footer_defaults {
     name: "microdroid_kernel_cap_defaults",
     // Below are properties that are conditionally set depending on value of build flags.
-    soong_config_variables: {
-        release_avf_enable_llpvm_changes: {
-            rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
-            props: [
-                {
-                    name: "com.android.virt.cap",
-                    value: "secretkeeper_protection",
-                },
-            ],
+    props: [
+        {
+            name: "com.android.virt.cap",
+            value: "secretkeeper_protection",
         },
-    },
+    ],
+    rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
 }
 
-flag_aware_avb_add_hash_footer_defaults {
+avb_add_hash_footer_defaults {
     name: "microdroid_kernel_cap_with_uefi_defaults",
-    // Below are properties that are conditionally set depending on value of build flags.
-    soong_config_variables: {
-        release_avf_enable_llpvm_changes: {
-            rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
-            props: [
-                {
-                    name: "com.android.virt.cap",
-                    value: "secretkeeper_protection|supports_uefi_boot",
-                },
-            ],
-            conditions_default: {
-                props: [
-                    {
-                        name: "com.android.virt.cap",
-                        value: "supports_uefi_boot",
-                    },
-                ],
-            },
+    rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
+    props: [
+        {
+            name: "com.android.virt.cap",
+            value: "secretkeeper_protection|supports_uefi_boot",
         },
-    },
+    ],
 }
 
 avb_add_hash_footer {
diff --git a/libs/apexutil/src/lib.rs b/libs/apexutil/src/lib.rs
index 639135f..9ae5f2b 100644
--- a/libs/apexutil/src/lib.rs
+++ b/libs/apexutil/src/lib.rs
@@ -179,7 +179,7 @@
         // The expected hex values were generated when we ran the method the first time.
         assert_eq!(
             hex::encode(res.root_digest),
-            "54265da77ae1fd619e39809ad99fedc576bb20c0c7a8002190fa64438436299f"
+            "0cdeee606f2c9b468900e07d306384605684e6ca0b8bc6c51592808de9fd1c44"
         );
         assert_eq!(
             hex::encode(res.public_key),
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index 2d0294e..c02466e 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -83,6 +83,7 @@
         "liblibfdt_nostd",
         "liblog_rust_nostd",
         "libonce_cell_nostd",
+        "libsafe_mmio",
         "libspin_nostd",
         "libstatic_assertions",
         "libthiserror_nostd",
diff --git a/libs/libvmbase/src/arch.rs b/libs/libvmbase/src/arch.rs
index cc42939..29d3a32 100644
--- a/libs/libvmbase/src/arch.rs
+++ b/libs/libvmbase/src/arch.rs
@@ -38,25 +38,6 @@
 #[cfg(target_arch = "aarch64")]
 pub use aarch64_paging::paging::VirtualAddress;
 
-/// Write with well-defined compiled behavior.
-///
-/// See https://github.com/rust-lang/rust/issues/131894
-///
-/// # Safety
-///
-/// `dst` must be valid for writes.
-#[inline]
-pub unsafe fn write_volatile_u8(dst: *mut u8, src: u8) {
-    cfg_if::cfg_if! {
-        if #[cfg(target_arch = "aarch64")] {
-            // SAFETY: `dst` is valid for writes.
-            unsafe { aarch64::strb(dst, src) }
-        } else {
-            compile_error!("Unsupported target_arch")
-        }
-    }
-}
-
 /// Flush `size` bytes of data cache by virtual address.
 #[inline]
 pub(crate) fn flush_region(start: usize, size: usize) {
diff --git a/libs/libvmbase/src/arch/aarch64.rs b/libs/libvmbase/src/arch/aarch64.rs
index 9c4d256..de3bfa8 100644
--- a/libs/libvmbase/src/arch/aarch64.rs
+++ b/libs/libvmbase/src/arch/aarch64.rs
@@ -119,26 +119,6 @@
     }};
 }
 
-/// STRB intrinsics.
-///
-/// See https://github.com/rust-lang/rust/issues/131894
-///
-/// # Safety
-///
-/// `dst` must be valid for writes.
-#[inline]
-pub unsafe fn strb(dst: *mut u8, src: u8) {
-    // SAFETY: strb only modifies *dst, which must be valid for writes.
-    unsafe {
-        core::arch::asm!(
-            "strb {value:w}, [{ptr}]",
-            value = in(reg) src,
-            ptr = in(reg) dst,
-            options(preserves_flags),
-        );
-    }
-}
-
 /// Reads the number of words in the smallest cache line of all the data caches and unified caches.
 #[inline]
 pub fn min_dcache_line_size() -> usize {
diff --git a/libs/libvmbase/src/arch/aarch64/uart.rs b/libs/libvmbase/src/arch/aarch64/uart.rs
index 2ef7d7e..0e94fc6 100644
--- a/libs/libvmbase/src/arch/aarch64/uart.rs
+++ b/libs/libvmbase/src/arch/aarch64/uart.rs
@@ -14,36 +14,29 @@
 
 //! Uart driver with backend for aarch64 using MMIO
 
-use crate::arch::write_volatile_u8;
 use crate::uart::UartBackend;
+use core::ptr::NonNull;
+use safe_mmio::{fields::ReadWrite, UniqueMmioPointer};
 
 /// Alias for default Uart for aarch64 backend with [`MmioBackend`]
-pub type Uart = crate::uart::Uart<MmioBackend>;
+pub type Uart = crate::uart::Uart<MmioBackend<'static>>;
 
-/// Backend for [`crate::uart::Uart`] that uses [`crate::arch::write_volatile_u8`] for writing to
-/// hardware registers.
-pub struct MmioBackend {
-    base_address: *mut u8,
+/// Backend for [`crate::uart::Uart`] that uses `safe-mmio` for writing to hardware registers.
+pub struct MmioBackend<'a> {
+    registers: UniqueMmioPointer<'a, [ReadWrite<u8>; 8]>,
 }
 
-impl MmioBackend {
-    /// Constructs a new instance of the UART driver backend for a device at the given base address.
-    ///
-    /// # Safety
-    ///
-    /// The given base address must point to the 8 MMIO control registers of an appropriate UART
-    /// device, which must be mapped into the address space of the process as device memory and not
-    /// have any other aliases.
-    pub unsafe fn new(base_address: usize) -> Self {
-        Self { base_address: base_address as *mut u8 }
+impl<'a> MmioBackend<'a> {
+    /// Constructs a new instance of the UART driver backend for a device with the given data
+    /// register.
+    pub fn new(registers: UniqueMmioPointer<'a, [ReadWrite<u8>; 8]>) -> Self {
+        Self { registers }
     }
 }
 
-impl UartBackend for MmioBackend {
-    fn write_register_u8(&self, offset: usize, byte: u8) {
-        // SAFETY: We know that the base address points to the control registers of a UART device
-        // which is appropriately mapped.
-        unsafe { write_volatile_u8(self.base_address.add(offset), byte) }
+impl UartBackend for MmioBackend<'_> {
+    fn write_register_u8(&mut self, offset: usize, byte: u8) {
+        self.registers.get(offset).expect("Register offset out of bounds").write(byte);
     }
 }
 
@@ -52,15 +45,15 @@
     ///
     /// # Safety
     ///
-    /// The given base address must point to the 8 MMIO control registers of an appropriate UART
-    /// device, which must be mapped into the address space of the process as device memory and not
-    /// have any other aliases.
+    /// The given base address must point to the 8 MMIO control registers of an appropriate 8250
+    /// UART device, which must be mapped into the address space of the process as device memory and
+    /// not have any other aliases.
     pub unsafe fn new(base_address: usize) -> Self {
-        // SAFETY: Delegated to caller
-        unsafe { Self::create(MmioBackend::new(base_address)) }
+        // SAFETY: The caller promises that base_address points to a mapped 8250 UART's registers
+        // with no aliases. That implies that there are 8 single-byte registers we can safely
+        // access, as required by `UniqueMmioPointer`.
+        let data_register =
+            unsafe { UniqueMmioPointer::new(NonNull::new(base_address as _).unwrap()) };
+        Self::create(MmioBackend::new(data_register))
     }
 }
-
-// SAFETY: `MmioBackend` just contains a pointer to device memory, which can be accessed from any
-// context.
-unsafe impl Send for MmioBackend {}
diff --git a/libs/libvmbase/src/uart.rs b/libs/libvmbase/src/uart.rs
index 857a22e..6a256ea 100644
--- a/libs/libvmbase/src/uart.rs
+++ b/libs/libvmbase/src/uart.rs
@@ -20,7 +20,7 @@
 /// The backend for [`Uart`] that abstracts the access to 8250 register map
 pub trait UartBackend {
     /// Writes a byte value on the offset to the hardware registers.
-    fn write_register_u8(&self, offset: usize, byte: u8);
+    fn write_register_u8(&mut self, offset: usize, byte: u8);
 }
 
 /// Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
@@ -36,7 +36,7 @@
     }
 
     /// Writes a single byte to the UART.
-    pub fn write_byte(&self, byte: u8) {
+    pub fn write_byte(&mut self, byte: u8) {
         self.backend.write_register_u8(0, byte)
     }
 }
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
index 7eb7748..7c1091d 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
@@ -230,8 +230,12 @@
 
     public boolean isFeatureEnabled(String feature) throws Exception {
         CommandRunner android = new CommandRunner(getDevice());
-        String result = android.run(VIRT_APEX + "bin/vm", "check-feature-enabled", feature);
-        return result.contains("enabled");
+        String cmd = VIRT_APEX + "bin/vm check-feature-enabled " + feature;
+        CommandResult result = android.runForResult(cmd);
+        assumeTrue(
+                "Failed to run" + cmd + " " + result,
+                result.getStatus() == CommandStatus.SUCCESS && result.getExitCode() == 0);
+        return result.getStdout().trim().contains("Feature " + feature + " is enabled");
     }
 
     public List<AssignableDevice> getAssignableDevices() throws Exception {