diff options
author | 2024-05-13 18:39:27 +0000 | |
---|---|---|
committer | 2024-05-13 18:39:27 +0000 | |
commit | 61d93fc23f1d3d7a34b7b94ada7e77c9133cfba8 (patch) | |
tree | b8c67a2ca0844b1358dd1de35f49892152a1998c | |
parent | ad42babc098dcb50c4a0599e1f18c4deca519cdf (diff) | |
parent | 68f34bf241ec316ff92a3195aa3fa67faa1b1b1b (diff) |
Merge "deprecate binder::get_service, add binder::check_service" into main
-rw-r--r-- | libs/binder/rust/binder_tokio/lib.rs | 27 | ||||
-rw-r--r-- | libs/binder/rust/src/lib.rs | 6 | ||||
-rw-r--r-- | libs/binder/rust/src/service.rs | 17 | ||||
-rw-r--r-- | libs/binder/rust/tests/integration.rs | 60 |
4 files changed, 105 insertions, 5 deletions
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs index 1dc0b2471d..71bb95bc0e 100644 --- a/libs/binder/rust/binder_tokio/lib.rs +++ b/libs/binder/rust/binder_tokio/lib.rs @@ -34,6 +34,7 @@ use std::future::Future; /// Retrieve an existing service for a particular interface, sleeping for a few /// seconds if it doesn't yet exist. +#[deprecated = "this polls 5s, use wait_for_interface or check_interface"] pub async fn get_interface<T: FromIBinder + ?Sized + 'static>( name: &str, ) -> Result<Strong<T>, StatusCode> { @@ -56,6 +57,32 @@ pub async fn get_interface<T: FromIBinder + ?Sized + 'static>( } } +/// Retrieve an existing service for a particular interface. Returns +/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available. +/// +/// NOTE: "immediately" above does not mean the future will complete the first time it is polled. +pub async fn check_interface<T: FromIBinder + ?Sized + 'static>( + name: &str, +) -> Result<Strong<T>, StatusCode> { + if binder::is_handling_transaction() { + // See comment in the BinderAsyncPool impl. + return binder::check_interface::<T>(name); + } + + let name = name.to_string(); + let res = tokio::task::spawn_blocking(move || binder::check_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>( diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 0f9c58c0a2..e70f4f0232 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -114,9 +114,9 @@ pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder}; pub use proxy::{DeathRecipient, SpIBinder, WpIBinder}; #[cfg(not(trusty))] pub use service::{ - add_service, force_lazy_services_persist, get_declared_instances, get_interface, get_service, - is_declared, is_handling_transaction, register_lazy_service, wait_for_interface, - wait_for_service, LazyServiceGuard, + add_service, check_interface, check_service, force_lazy_services_persist, + get_declared_instances, get_interface, get_service, is_declared, is_handling_transaction, + register_lazy_service, wait_for_interface, wait_for_service, LazyServiceGuard, }; #[cfg(not(trusty))] pub use state::{ProcessState, ThreadState}; diff --git a/libs/binder/rust/src/service.rs b/libs/binder/rust/src/service.rs index 3ca3b540c4..29dd8e1f58 100644 --- a/libs/binder/rust/src/service.rs +++ b/libs/binder/rust/src/service.rs @@ -144,6 +144,7 @@ fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result /// Retrieve an existing service, blocking for a few seconds if it doesn't yet /// exist. +#[deprecated = "this polls 5s, use wait_for_service or check_service"] pub fn get_service(name: &str) -> Option<SpIBinder> { let name = CString::new(name).ok()?; // Safety: `AServiceManager_getService` returns either a null pointer or a @@ -152,6 +153,15 @@ pub fn get_service(name: &str) -> Option<SpIBinder> { unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) } } +/// Retrieve an existing service. Returns `None` immediately if the service is not available. +pub fn check_service(name: &str) -> Option<SpIBinder> { + let name = CString::new(name).ok()?; + // Safety: `AServiceManager_checkService` returns either a null pointer or + // a valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::AServiceManager_checkService(name.as_ptr())) } +} + /// Retrieve an existing service, or start it if it is configured as a dynamic /// service and isn't yet started. pub fn wait_for_service(name: &str) -> Option<SpIBinder> { @@ -164,10 +174,17 @@ pub fn wait_for_service(name: &str) -> Option<SpIBinder> { /// Retrieve an existing service for a particular interface, blocking for a few /// seconds if it doesn't yet exist. +#[deprecated = "this polls 5s, use wait_for_interface or check_interface"] pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> { interface_cast(get_service(name)) } +/// Retrieve an existing service for a particular interface. Returns +/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available. +pub fn check_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> { + interface_cast(check_service(name)) +} + /// 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 fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> { diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index c87fa89756..15ae56fdd7 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -421,7 +421,7 @@ mod tests { } #[test] - fn check_services() { + fn check_get_service() { 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()); @@ -445,7 +445,7 @@ mod tests { } #[tokio::test] - async fn check_services_async() { + async fn check_get_service_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()); @@ -474,6 +474,62 @@ mod tests { } #[test] + fn check_check_service() { + let mut sm = binder::check_service("manager").expect("Did not find manager binder service"); + assert!(sm.is_binder_alive()); + assert!(sm.ping_binder().is_ok()); + + assert!(binder::check_service("this_service_does_not_exist").is_none()); + assert_eq!( + binder::check_interface::<dyn ITest>("this_service_does_not_exist").err(), + Some(StatusCode::NAME_NOT_FOUND) + ); + assert_eq!( + binder::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(), + Some(StatusCode::NAME_NOT_FOUND) + ); + + // The service manager service isn't an ITest, so this must fail. + assert_eq!( + binder::check_interface::<dyn ITest>("manager").err(), + Some(StatusCode::BAD_TYPE) + ); + assert_eq!( + binder::check_interface::<dyn IATest<Tokio>>("manager").err(), + Some(StatusCode::BAD_TYPE) + ); + } + + #[tokio::test] + async fn check_check_service_async() { + let mut sm = binder::check_service("manager").expect("Did not find manager binder service"); + assert!(sm.is_binder_alive()); + assert!(sm.ping_binder().is_ok()); + + assert!(binder::check_service("this_service_does_not_exist").is_none()); + assert_eq!( + binder_tokio::check_interface::<dyn ITest>("this_service_does_not_exist").await.err(), + Some(StatusCode::NAME_NOT_FOUND) + ); + assert_eq!( + binder_tokio::check_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::check_interface::<dyn ITest>("manager").await.err(), + Some(StatusCode::BAD_TYPE) + ); + assert_eq!( + binder_tokio::check_interface::<dyn IATest<Tokio>>("manager").await.err(), + Some(StatusCode::BAD_TYPE) + ); + } + + #[test] fn check_wait_for_service() { let mut sm = binder::wait_for_service("manager").expect("Did not get manager binder service"); |