From c1736849971a4ca2f9a855c1840d5ff1fcabcb45 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 23 Nov 2021 12:38:51 +0000 Subject: rust: add conversion between sync and async interfaces Test: add new test Bug: 207463587 Change-Id: Ib01ffb737c15b1e919d9d87e89a1c47e40723b92 --- libs/binder/rust/src/binder.rs | 57 +++++++++++++++++++++++++++++++++++ libs/binder/rust/src/lib.rs | 4 +-- libs/binder/rust/tests/integration.rs | 26 ++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 3d2eddf611..4d6b294000 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -66,6 +66,35 @@ pub trait Interface: Send + Sync { } } +/// Implemented by sync interfaces to specify what the associated async interface is. +/// Generic to handle the fact that async interfaces are generic over a thread pool. +/// +/// The binder in any object implementing this trait should be compatible with the +/// `Target` associated type, and using `FromIBinder` to convert it to the target +/// should not fail. +pub trait ToAsyncInterface

+where + Self: Interface, + Self::Target: FromIBinder, +{ + /// The async interface associated with this sync interface. + type Target: ?Sized; +} + +/// Implemented by async interfaces to specify what the associated sync interface is. +/// +/// The binder in any object implementing this trait should be compatible with the +/// `Target` associated type, and using `FromIBinder` to convert it to the target +/// should not fail. +pub trait ToSyncInterface +where + Self: Interface, + Self::Target: FromIBinder, +{ + /// The sync interface associated with this async interface. + type Target: ?Sized; +} + /// Interface stability promise /// /// An interface can promise to be a stable vendor interface ([`Vintf`]), or @@ -337,6 +366,26 @@ impl Strong { pub fn downgrade(this: &Strong) -> Weak { Weak::new(this) } + + /// Convert this synchronous binder handle into an asynchronous one. + pub fn into_async

(self) -> Strong<>::Target> + where + I: ToAsyncInterface

, + { + // By implementing the ToAsyncInterface trait, it is guaranteed that the binder + // object is also valid for the target type. + FromIBinder::try_from(self.0.as_binder()).unwrap() + } + + /// Convert this asynchronous binder handle into a synchronous one. + pub fn into_sync(self) -> Strong<::Target> + where + I: ToSyncInterface, + { + // By implementing the ToSyncInterface trait, it is guaranteed that the binder + // object is also valid for the target type. + FromIBinder::try_from(self.0.as_binder()).unwrap() + } } impl Clone for Strong { @@ -1017,6 +1066,14 @@ macro_rules! declare_binder_interface { .expect(concat!("Error cloning interface ", stringify!($async_interface))) } } + + impl $crate::ToAsyncInterface

for dyn $interface { + type Target = dyn $async_interface

; + } + + impl $crate::ToSyncInterface for dyn $async_interface

{ + type Target = dyn $interface; + } )? }; } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index b94dfa137e..7c04a7207b 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -109,8 +109,8 @@ pub mod parcel; pub use crate::binder::{ BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, - Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION, - FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION, + Stability, Strong, ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, Weak, + FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION, }; pub use crate::binder_async::{BoxFuture, BinderAsyncPool}; pub use error::{status_t, ExceptionCode, Result, Status, StatusCode}; diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index 40359b4749..f8bc5acd4f 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -510,6 +510,32 @@ mod tests { ); } + #[tokio::test] + async fn get_selinux_context_sync_to_async() { + let service_name = "get_selinux_context"; + let _process = ScopedServiceProcess::new(service_name); + let test_client: Strong = + binder::get_interface(service_name).expect("Did not get manager binder service"); + let test_client = test_client.into_async::(); + assert_eq!( + test_client.get_selinux_context().await.unwrap(), + get_expected_selinux_context() + ); + } + + #[tokio::test] + async fn get_selinux_context_async_to_sync() { + let service_name = "get_selinux_context"; + let _process = ScopedServiceProcess::new(service_name); + let test_client: Strong> = + binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service"); + let test_client = test_client.into_sync(); + assert_eq!( + test_client.get_selinux_context().unwrap(), + get_expected_selinux_context() + ); + } + struct Bools { binder_died: Arc, binder_dealloc: Arc, -- cgit v1.2.3-59-g8ed1b