Retry connecting to /default KeyMint
Make the cfg-controlled retry behaviour universal. This allows for
slower-starting /default KeyMint instances, at a cost of slower boot
time. It will also still eventually fail, making incorrect
configurations visible.
Bug: 406623055
Test: boot, logcat
Change-Id: Id973ca678b57753456d4260628f31c27f02d52ae
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 92a4bed..abd0f63 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -31,10 +31,6 @@
"keystore2_use_latest_aidl_rust",
"structured_log_rust_defaults",
],
- cfgs: select(release_flag("RELEASE_AVF_ENABLE_EARLY_VM"), {
- true: ["early_vm"],
- default: [],
- }),
rustlibs: [
"android.hardware.security.rkp-V3-rust",
"android.hardware.security.secureclock-V1-rust",
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index a9d4fbc..28e3b7f 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -235,13 +235,13 @@
.context(ks_err!("Get service name from binder service"))?;
let (keymint, hal_version) = if let Some(service_name) = service_name {
+ // Allow a few retries for retrieving the /default KeyMint instance, as it is needed at
+ // startup and may also be starting up. (However, note that a slow-starting /default
+ // KeyMint will result in extended boot times.)
+ let retry_count = if *security_level == SecurityLevel::TRUSTED_ENVIRONMENT { 6 } else { 1 };
let km: Strong<dyn IKeyMintDevice> =
- 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_binder_status_code(retry_get_interface(&service_name, retry_count))
+ .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 183bc0b..deb3e18 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -48,7 +48,7 @@
APC_COMPAT_ERROR_SYSTEM_ERROR,
};
use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt, ZVec};
-use log::{debug, info, warn};
+use log::{debug, error, info, warn};
use std::iter::IntoIterator;
use std::thread::sleep;
use std::time::Duration;
@@ -665,24 +665,32 @@
}
}
+/// Get the Binder interface identified by `name`, retrying any failures up to the given
+/// `retry_count`.
pub(crate) fn retry_get_interface<T: FromIBinder + ?Sized>(
name: &str,
+ retry_count: usize,
) -> 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;
+ let mut attempts = 0;
+ let mut wait_time = Duration::from_secs(1);
+ loop {
+ let err = match binder::get_interface(name) {
+ Ok(res) => {
+ if attempts > 1 {
+ info!("Success on get_interface({name}) after {attempts} failures!");
+ }
+ return Ok(res);
}
+ Err(e) => e,
+ };
+ attempts += 1;
+ error!("Failed (attempt {attempts} of {retry_count}) to get_interface {name}: {err:?}");
+ if attempts >= retry_count {
+ error!("Give up retrying after {attempts} failures, return final error: {err:?}");
+ return Err(err);
}
+ info!("Blocking wait {wait_time:?} before retry of get_interface({name})");
+ sleep(wait_time);
+ wait_time *= 2;
}
- if retry_count > 1 {
- info!("{retry_count}-th (last) retry to get interface: {name}");
- }
- binder::get_interface(name)
}