[getService] Retry get_interface in keystore2

This cl retries to the get_interface function in keystore2 when
it connects to the KeyMint TA.

This is needed because when KeyMint TA runs in VM, it can take
several retries for the host to connect to the Trusty VM.
A timeout longer than the 5-second timeout in getService is
needed to handle this.

Bug: 355194622
Test: CF is gets booted with KeyMint TA in VM
Change-Id: I3b8a2aee77ad2e6111239898f165bc5bfd3ad479
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index a90ba79..bde83fd 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -23,7 +23,7 @@
 use crate::legacy_blob::LegacyBlobLoader;
 use crate::legacy_importer::LegacyImporter;
 use crate::super_key::SuperKeyManager;
-use crate::utils::watchdog as wd;
+use crate::utils::{retry_get_interface, watchdog as wd};
 use crate::{
     database::KeystoreDB,
     database::Uuid,
@@ -225,8 +225,12 @@
 
     let (keymint, hal_version) = if let Some(service_name) = service_name {
         let km: Strong<dyn IKeyMintDevice> =
-            map_binder_status_code(binder::get_interface(&service_name))
-                .context(ks_err!("Trying to connect to genuine KeyMint service."))?;
+            if SecurityLevel::TRUSTED_ENVIRONMENT == *security_level {
+                map_binder_status_code(retry_get_interface(&service_name))
+            } else {
+                map_binder_status_code(binder::get_interface(&service_name))
+            }
+            .context(ks_err!("Trying to connect to genuine KeyMint service."))?;
         // Map the HAL version code for KeyMint to be <AIDL version> * 100, so
         // - V1 is 100
         // - V2 is 200
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 0a545f7..03c0626 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -40,14 +40,17 @@
     Authorization::Authorization, Domain::Domain, KeyDescriptor::KeyDescriptor,
 };
 use anyhow::{Context, Result};
-use binder::{Strong, ThreadState};
+use binder::{FromIBinder, StatusCode, Strong, ThreadState};
 use keystore2_apc_compat::{
     ApcCompatUiOptions, APC_COMPAT_ERROR_ABORTED, APC_COMPAT_ERROR_CANCELLED,
     APC_COMPAT_ERROR_IGNORED, APC_COMPAT_ERROR_OK, APC_COMPAT_ERROR_OPERATION_PENDING,
     APC_COMPAT_ERROR_SYSTEM_ERROR,
 };
 use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt, ZVec};
+use log::{info, warn};
 use std::iter::IntoIterator;
+use std::thread::sleep;
+use std::time::Duration;
 
 #[cfg(test)]
 mod tests;
@@ -634,3 +637,25 @@
         aes_gcm_encrypt(plaintext, self.key()).context(ks_err!("Encryption failed."))
     }
 }
+
+pub(crate) fn retry_get_interface<T: FromIBinder + ?Sized>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
+    let retry_count = if cfg!(early_vm) { 5 } else { 1 };
+
+    let mut wait_time = Duration::from_secs(5);
+    for i in 1..retry_count {
+        match binder::get_interface(name) {
+            Ok(res) => return Ok(res),
+            Err(e) => {
+                warn!("failed to get interface {name}. Retry {i}/{retry_count}: {e:?}");
+                sleep(wait_time);
+                wait_time *= 2;
+            }
+        }
+    }
+    if retry_count > 1 {
+        info!("{retry_count}-th (last) retry to get interface: {name}");
+    }
+    binder::get_interface(name)
+}