Merge "binder_rust: add async variants of get_interface and wait_for_interface" am: 1b07286375 am: 01f68a187c am: c3b612e631 am: 1a1a5673f8 am: efcf48a6de

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1878423

Change-Id: I1e89d4989f3898599813dfe4c1b1463af3a6d91d
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()