Merge "binder_rust: add async variants of get_interface and wait_for_interface" am: 1b07286375 am: 01f68a187c am: c3b612e631
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1878423
Change-Id: Icefdf5bf125158b2abc4382c1e595ff674266dc0
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index a71ddda..64833b6 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,10 +28,48 @@
//!
//! [`Tokio`]: crate::Tokio
-use binder::public_api::{BinderAsyncPool, BoxFuture};
-use binder::StatusCode;
+use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
+use binder::{FromIBinder, StatusCode};
use std::future::Future;
+/// Retrieve an existing service for a particular interface, sleeping for a few
+/// seconds if it doesn't yet exist.
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::public_api::get_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
+/// Retrieve an existing service for a particular interface, or start it if it
+/// is configured as a dynamic service and isn't yet started.
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::public_api::wait_for_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
/// Use the Tokio `spawn_blocking` pool with AIDL.
pub enum Tokio {}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 3c29073..ebfe879 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -377,6 +377,33 @@
);
}
+ #[tokio::test]
+ async fn check_services_async() {
+ let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
+ assert!(sm.is_binder_alive());
+ assert!(sm.ping_binder().is_ok());
+
+ assert!(binder::get_service("this_service_does_not_exist").is_none());
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+
+ // The service manager service isn't an ITest, so this must fail.
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ }
+
#[test]
fn check_wait_for_service() {
let mut sm =
@@ -409,7 +436,7 @@
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn IATest<Tokio>> =
- binder::get_interface(service_name).expect("Did not get manager binder service");
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
}
@@ -427,7 +454,7 @@
let service_name = "wait_for_trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn IATest<Tokio>> =
- binder::wait_for_interface(service_name).expect("Did not get manager binder service");
+ binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
}
@@ -459,7 +486,7 @@
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn IATest<Tokio>> =
- binder::get_interface(service_name).expect("Did not get manager binder service");
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
assert_eq!(
test_client.get_selinux_context().await.unwrap(),
get_expected_selinux_context()