Loading libs/binder/rust/src/lib.rs +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ pub use service::{get_interface, get_service}; #[cfg(not(any(trusty, android_ndk)))] pub use state::{ProcessState, ThreadState}; #[cfg(not(any(android_vendor, android_vndk, android_ndk)))] pub use system_only::{delegate_accessor, Accessor, ConnectionInfo}; pub use system_only::{delegate_accessor, Accessor, AccessorProvider, ConnectionInfo}; /// Binder result containing a [`Status`] on error. pub type Result<T> = std::result::Result<T, Status>; Loading libs/binder/rust/src/system_only.rs +169 −9 Original line number Diff line number Diff line Loading @@ -100,16 +100,35 @@ impl Accessor { unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) } } /// Release the underlying ABinderRpc_Accessor pointer for use with the ndk API /// This gives up ownership of the ABinderRpc_Accessor and it is the responsibility of /// the caller to delete it with ABinderRpc_Accessor_delete /// /// # Safety /// /// - The returned `ABinderRpc_Accessor` pointer is now owned by the caller, who must /// call `ABinderRpc_Accessor_delete` to delete the object. /// - This `Accessor` object is now useless after `release` so it can be dropped. unsafe fn release(mut self) -> *mut sys::ABinderRpc_Accessor { if self.accessor.is_null() { log::error!("Attempting to release an Accessor that was already released"); return ptr::null_mut(); } let ptr = self.accessor; self.accessor = ptr::null_mut(); ptr } /// Callback invoked from C++ when the connection info is needed. /// /// # Safety /// /// The `instance` parameter must be a non-null pointer to a valid C string for /// - The `instance` parameter must be a non-null pointer to a valid C string for /// CStr::from_ptr. The memory must contain a valid null terminator at the end of /// the string within isize::MAX from the pointer. The memory must not be mutated for /// the duration of this function call and must be valid for reads from the pointer /// to the null terminator. /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the caller must hold a ref-count to it. unsafe extern "C" fn connection_info<F>( instance: *const c_char, Loading Loading @@ -172,7 +191,7 @@ impl Accessor { /// /// # Safety /// /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void) where Loading @@ -185,6 +204,10 @@ impl Accessor { impl Drop for Accessor { fn drop(&mut self) { if self.accessor.is_null() { // This Accessor was already released. return; } // Safety: `self.accessor` is always a valid, owned // `ABinderRpc_Accessor` pointer returned by // `ABinderRpc_Accessor_new` when `self` was created. This delete Loading Loading @@ -218,3 +241,140 @@ pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> // point, so can be safely passed to `SpIBinder::from_raw`. Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") }) } /// Rust wrapper around ABinderRpc_AccessorProvider objects for RPC binder service management. /// /// Dropping the `AccessorProvider` will drop/unregister the underlying object. #[derive(Debug)] pub struct AccessorProvider { accessor_provider: *mut sys::ABinderRpc_AccessorProvider, } /// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is /// `Sync` and `Send`. As /// `ABinderRpc_AccessorProvider` is threadsafe, this structure is too. /// The Fn owned the AccessorProvider has `Sync` and `Send` properties unsafe impl Send for AccessorProvider {} /// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is /// `Sync` and `Send`. As `ABinderRpc_AccessorProvider` is threadsafe, this structure is too. /// The Fn owned the AccessorProvider has `Sync` and `Send` properties unsafe impl Sync for AccessorProvider {} impl AccessorProvider { /// Create a new `AccessorProvider` that will give libbinder `Accessors` in order to /// connect to binder services over sockets. /// /// `instances` is a list of all instances that this `AccessorProvider` is responsible for. /// It is declaring these instances as available to this process and will return /// `Accessor` objects for them when libbinder calls the `provider` callback. /// `provider` is the callback that libbinder will call when a service is being requested. /// The callback takes a `&str` argument representing the service that is being requested. /// See the `ABinderRpc_AccessorProvider_getAccessorCallback` for the C++ equivalent. pub fn new<F>(instances: &[String], provider: F) -> Option<AccessorProvider> where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { let callback: *mut c_void = Arc::into_raw(Arc::new(provider)) as *mut c_void; let c_str_instances: Vec<CString> = instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect(); let mut c_instances: Vec<*const c_char> = c_str_instances.iter().map(|s| s.as_ptr()).collect(); let num_instances: usize = c_instances.len(); // Safety: // - The function pointer for the first argument is a valid `get_accessor` callback. // - This call returns an owned `ABinderRpc_AccessorProvider` pointer which // must be destroyed via `ABinderRpc_unregisterAccessorProvider` when no longer // needed. // - When the underlying ABinderRpc_AccessorProvider is deleted, it will call // the `cookie_decr_refcount` callback on the `callback` pointer to release its // strong ref. // - The `c_instances` vector is not modified by the function let accessor_provider = unsafe { sys::ABinderRpc_registerAccessorProvider( Some(Self::get_accessor::<F>), c_instances.as_mut_ptr(), num_instances, callback, Some(Self::accessor_cookie_decr_refcount::<F>), ) }; if accessor_provider.is_null() { return None; } Some(AccessorProvider { accessor_provider }) } /// Callback invoked from C++ when an Accessor is needed. /// /// # Safety /// /// - libbinder guarantees the `instance` argument is a valid C string if it's not null. /// - The `cookie` pointer is same pointer that we pass to ABinderRpc_registerAccessorProvider /// in AccessorProvider.new() which is the closure that we will delete with /// self.accessor_cookie_decr_refcount when unregistering the AccessorProvider. unsafe extern "C" fn get_accessor<F>( instance: *const c_char, cookie: *mut c_void, ) -> *mut binder_ndk_sys::ABinderRpc_Accessor where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { if cookie.is_null() || instance.is_null() { log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!"); return ptr::null_mut(); } // Safety: The caller promises that `cookie` is for an Arc<F>. let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; let inst = { // Safety: The caller in libbinder_ndk will have already verified this is a valid // C string match unsafe { CStr::from_ptr(instance) }.to_str() { Ok(s) => s, Err(err) => { log::error!("Failed to get a valid C string! {err:?}"); return ptr::null_mut(); } } }; match callback(inst) { Some(a) => { // Safety: This is giving up ownership of this ABinderRpc_Accessor // to the caller of this function (libbinder) and it is responsible // for deleting it. unsafe { a.release() } } None => ptr::null_mut(), } } /// Callback that decrements the ref-count. /// This is invoked from C++ when the provider is unregistered. /// /// # Safety /// /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void) where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { // Safety: The caller promises that `cookie` is for an Arc<F>. unsafe { Arc::decrement_strong_count(cookie as *const F) }; } } impl Drop for AccessorProvider { fn drop(&mut self) { // Safety: `self.accessor_provider` is always a valid, owned // `ABinderRpc_AccessorProvider` pointer returned by // `ABinderRpc_registerAccessorProvider` when `self` was created. This delete // method can only be called once when `self` is dropped. unsafe { sys::ABinderRpc_unregisterAccessorProvider(self.accessor_provider); } } } libs/binder/rust/tests/integration.rs +58 −2 Original line number Diff line number Diff line Loading @@ -384,8 +384,8 @@ mod tests { use std::time::Duration; use binder::{ Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong, Accessor, AccessorProvider, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong, }; // Import from impl API for testing only, should not be necessary as long as // you are using AIDL. Loading Loading @@ -982,6 +982,62 @@ mod tests { assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND)); } #[test] fn test_accessor_provider_simple() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); } #[test] fn test_accessor_provider_no_instance() { let instances: Vec<String> = vec![]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_none()); } #[test] fn test_accessor_provider_double_register() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); let accessor2 = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor2.is_none()); } #[test] fn test_accessor_provider_register_drop_register() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; { let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); // accessor drops and unregisters the provider } { let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); } } #[test] fn test_accessor_provider_callback_destruction() { let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false)); let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; { let accessor: Option<AccessorProvider>; { let helper = ToBeDeleted { deleted: deleted.clone() }; accessor = AccessorProvider::new(&instances, move |_inst: &str| { let _ = &helper; None }); } assert!(accessor.is_some()); assert!(!deleted.load(Ordering::Relaxed)); } assert!(deleted.load(Ordering::Relaxed)); } #[tokio::test] async fn reassociate_rust_binder_async() { let service_name = "testing_service"; Loading Loading
libs/binder/rust/src/lib.rs +1 −1 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ pub use service::{get_interface, get_service}; #[cfg(not(any(trusty, android_ndk)))] pub use state::{ProcessState, ThreadState}; #[cfg(not(any(android_vendor, android_vndk, android_ndk)))] pub use system_only::{delegate_accessor, Accessor, ConnectionInfo}; pub use system_only::{delegate_accessor, Accessor, AccessorProvider, ConnectionInfo}; /// Binder result containing a [`Status`] on error. pub type Result<T> = std::result::Result<T, Status>; Loading
libs/binder/rust/src/system_only.rs +169 −9 Original line number Diff line number Diff line Loading @@ -100,16 +100,35 @@ impl Accessor { unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) } } /// Release the underlying ABinderRpc_Accessor pointer for use with the ndk API /// This gives up ownership of the ABinderRpc_Accessor and it is the responsibility of /// the caller to delete it with ABinderRpc_Accessor_delete /// /// # Safety /// /// - The returned `ABinderRpc_Accessor` pointer is now owned by the caller, who must /// call `ABinderRpc_Accessor_delete` to delete the object. /// - This `Accessor` object is now useless after `release` so it can be dropped. unsafe fn release(mut self) -> *mut sys::ABinderRpc_Accessor { if self.accessor.is_null() { log::error!("Attempting to release an Accessor that was already released"); return ptr::null_mut(); } let ptr = self.accessor; self.accessor = ptr::null_mut(); ptr } /// Callback invoked from C++ when the connection info is needed. /// /// # Safety /// /// The `instance` parameter must be a non-null pointer to a valid C string for /// - The `instance` parameter must be a non-null pointer to a valid C string for /// CStr::from_ptr. The memory must contain a valid null terminator at the end of /// the string within isize::MAX from the pointer. The memory must not be mutated for /// the duration of this function call and must be valid for reads from the pointer /// to the null terminator. /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the caller must hold a ref-count to it. unsafe extern "C" fn connection_info<F>( instance: *const c_char, Loading Loading @@ -172,7 +191,7 @@ impl Accessor { /// /// # Safety /// /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void) where Loading @@ -185,6 +204,10 @@ impl Accessor { impl Drop for Accessor { fn drop(&mut self) { if self.accessor.is_null() { // This Accessor was already released. return; } // Safety: `self.accessor` is always a valid, owned // `ABinderRpc_Accessor` pointer returned by // `ABinderRpc_Accessor_new` when `self` was created. This delete Loading Loading @@ -218,3 +241,140 @@ pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> // point, so can be safely passed to `SpIBinder::from_raw`. Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") }) } /// Rust wrapper around ABinderRpc_AccessorProvider objects for RPC binder service management. /// /// Dropping the `AccessorProvider` will drop/unregister the underlying object. #[derive(Debug)] pub struct AccessorProvider { accessor_provider: *mut sys::ABinderRpc_AccessorProvider, } /// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is /// `Sync` and `Send`. As /// `ABinderRpc_AccessorProvider` is threadsafe, this structure is too. /// The Fn owned the AccessorProvider has `Sync` and `Send` properties unsafe impl Send for AccessorProvider {} /// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is /// `Sync` and `Send`. As `ABinderRpc_AccessorProvider` is threadsafe, this structure is too. /// The Fn owned the AccessorProvider has `Sync` and `Send` properties unsafe impl Sync for AccessorProvider {} impl AccessorProvider { /// Create a new `AccessorProvider` that will give libbinder `Accessors` in order to /// connect to binder services over sockets. /// /// `instances` is a list of all instances that this `AccessorProvider` is responsible for. /// It is declaring these instances as available to this process and will return /// `Accessor` objects for them when libbinder calls the `provider` callback. /// `provider` is the callback that libbinder will call when a service is being requested. /// The callback takes a `&str` argument representing the service that is being requested. /// See the `ABinderRpc_AccessorProvider_getAccessorCallback` for the C++ equivalent. pub fn new<F>(instances: &[String], provider: F) -> Option<AccessorProvider> where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { let callback: *mut c_void = Arc::into_raw(Arc::new(provider)) as *mut c_void; let c_str_instances: Vec<CString> = instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect(); let mut c_instances: Vec<*const c_char> = c_str_instances.iter().map(|s| s.as_ptr()).collect(); let num_instances: usize = c_instances.len(); // Safety: // - The function pointer for the first argument is a valid `get_accessor` callback. // - This call returns an owned `ABinderRpc_AccessorProvider` pointer which // must be destroyed via `ABinderRpc_unregisterAccessorProvider` when no longer // needed. // - When the underlying ABinderRpc_AccessorProvider is deleted, it will call // the `cookie_decr_refcount` callback on the `callback` pointer to release its // strong ref. // - The `c_instances` vector is not modified by the function let accessor_provider = unsafe { sys::ABinderRpc_registerAccessorProvider( Some(Self::get_accessor::<F>), c_instances.as_mut_ptr(), num_instances, callback, Some(Self::accessor_cookie_decr_refcount::<F>), ) }; if accessor_provider.is_null() { return None; } Some(AccessorProvider { accessor_provider }) } /// Callback invoked from C++ when an Accessor is needed. /// /// # Safety /// /// - libbinder guarantees the `instance` argument is a valid C string if it's not null. /// - The `cookie` pointer is same pointer that we pass to ABinderRpc_registerAccessorProvider /// in AccessorProvider.new() which is the closure that we will delete with /// self.accessor_cookie_decr_refcount when unregistering the AccessorProvider. unsafe extern "C" fn get_accessor<F>( instance: *const c_char, cookie: *mut c_void, ) -> *mut binder_ndk_sys::ABinderRpc_Accessor where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { if cookie.is_null() || instance.is_null() { log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!"); return ptr::null_mut(); } // Safety: The caller promises that `cookie` is for an Arc<F>. let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; let inst = { // Safety: The caller in libbinder_ndk will have already verified this is a valid // C string match unsafe { CStr::from_ptr(instance) }.to_str() { Ok(s) => s, Err(err) => { log::error!("Failed to get a valid C string! {err:?}"); return ptr::null_mut(); } } }; match callback(inst) { Some(a) => { // Safety: This is giving up ownership of this ABinderRpc_Accessor // to the caller of this function (libbinder) and it is responsible // for deleting it. unsafe { a.release() } } None => ptr::null_mut(), } } /// Callback that decrements the ref-count. /// This is invoked from C++ when the provider is unregistered. /// /// # Safety /// /// - The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void) where F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static, { // Safety: The caller promises that `cookie` is for an Arc<F>. unsafe { Arc::decrement_strong_count(cookie as *const F) }; } } impl Drop for AccessorProvider { fn drop(&mut self) { // Safety: `self.accessor_provider` is always a valid, owned // `ABinderRpc_AccessorProvider` pointer returned by // `ABinderRpc_registerAccessorProvider` when `self` was created. This delete // method can only be called once when `self` is dropped. unsafe { sys::ABinderRpc_unregisterAccessorProvider(self.accessor_provider); } } }
libs/binder/rust/tests/integration.rs +58 −2 Original line number Diff line number Diff line Loading @@ -384,8 +384,8 @@ mod tests { use std::time::Duration; use binder::{ Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong, Accessor, AccessorProvider, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong, }; // Import from impl API for testing only, should not be necessary as long as // you are using AIDL. Loading Loading @@ -982,6 +982,62 @@ mod tests { assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND)); } #[test] fn test_accessor_provider_simple() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); } #[test] fn test_accessor_provider_no_instance() { let instances: Vec<String> = vec![]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_none()); } #[test] fn test_accessor_provider_double_register() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); let accessor2 = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor2.is_none()); } #[test] fn test_accessor_provider_register_drop_register() { let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; { let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); // accessor drops and unregisters the provider } { let accessor = AccessorProvider::new(&instances, move |_inst: &str| None); assert!(accessor.is_some()); } } #[test] fn test_accessor_provider_callback_destruction() { let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false)); let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()]; { let accessor: Option<AccessorProvider>; { let helper = ToBeDeleted { deleted: deleted.clone() }; accessor = AccessorProvider::new(&instances, move |_inst: &str| { let _ = &helper; None }); } assert!(accessor.is_some()); assert!(!deleted.load(Ordering::Relaxed)); } assert!(deleted.load(Ordering::Relaxed)); } #[tokio::test] async fn reassociate_rust_binder_async() { let service_name = "testing_service"; Loading