Merge changes from topic "custom-smcs" into main

* changes:
  Start a VM in suspended state if vendor_tee_services were requested
  custom smcs: check for presence of HAL
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)?;