keystore2: Fix timeout handling
In earlier revisions of the code, RKPD client would wait indefinitely.
This model had an invariant guaranteeing that receiver end of the
oneshot channel is always present when sender is invoked.
With introduction of timeouts, this invariant no longer holds. The
receiver can time out and be cleaned up. This patch makes SafeSender
tolerate this scenario.
Also, attempt to cancelGetKey() if corresponding request for a key times
out.
Bug: 269460851
Test: keystore2_test
Change-Id: I33d80af52b5ab15c2113a140a8bd2beedfe2ff4f
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
index 0754a64..0ea2d39 100644
--- a/keystore2/src/rkpd_client.rs
+++ b/keystore2/src/rkpd_client.rs
@@ -57,8 +57,11 @@
fn send(&self, value: T) {
if let Some(inner) = self.inner.lock().unwrap().take() {
- // assert instead of unwrap, because on failure send returns Err(value)
- assert!(inner.send(value).is_ok(), "thread state is terminally broken");
+ // It's possible for the corresponding receiver to time out and be dropped. In this
+ // case send() will fail. This error is not actionable though, so only log the error.
+ if inner.send(value).is_err() {
+ log::error!("SafeSender::send() failed");
+ }
}
}
}
@@ -202,8 +205,14 @@
.context(ks_err!("Trying to get key."))?;
match timeout(RKPD_TIMEOUT, rx).await {
- Err(e) => Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
- .context(ks_err!("Waiting for RKPD key timed out: {:?}", e)),
+ Err(e) => {
+ // Make a best effort attempt to cancel the timed out request.
+ if let Err(e) = registration.cancelGetKey(&cb) {
+ log::error!("IRegistration::cancelGetKey failed: {:?}", e);
+ }
+ Err(Error::Rc(ResponseCode::OUT_OF_KEYS_TRANSIENT_ERROR))
+ .context(ks_err!("Waiting for RKPD key timed out: {:?}", e))
+ }
Ok(v) => v.unwrap(),
}
}
@@ -375,7 +384,7 @@
}
fn cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
- todo!()
+ Ok(())
}
fn storeUpgradedKeyAsync(