Skip to content

Commit 91088b9

Browse files
devinmoore-googGerrit Code Review
authored andcommitted
Merge "Add AccessorProvider to libbinder_rs" into main
2 parents 5f55630 + 7860d40 commit 91088b9

3 files changed

Lines changed: 228 additions & 12 deletions

File tree

libs/binder/rust/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub use service::{get_interface, get_service};
126126
#[cfg(not(any(trusty, android_ndk)))]
127127
pub use state::{ProcessState, ThreadState};
128128
#[cfg(not(any(android_vendor, android_vndk, android_ndk)))]
129-
pub use system_only::{delegate_accessor, Accessor, ConnectionInfo};
129+
pub use system_only::{delegate_accessor, Accessor, AccessorProvider, ConnectionInfo};
130130

131131
/// Binder result containing a [`Status`] on error.
132132
pub type Result<T> = std::result::Result<T, Status>;

libs/binder/rust/src/system_only.rs

Lines changed: 169 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,36 @@ impl Accessor {
100100
unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) }
101101
}
102102

103+
/// Release the underlying ABinderRpc_Accessor pointer for use with the ndk API
104+
/// This gives up ownership of the ABinderRpc_Accessor and it is the responsibility of
105+
/// the caller to delete it with ABinderRpc_Accessor_delete
106+
///
107+
/// # Safety
108+
///
109+
/// - The returned `ABinderRpc_Accessor` pointer is now owned by the caller, who must
110+
/// call `ABinderRpc_Accessor_delete` to delete the object.
111+
/// - This `Accessor` object is now useless after `release` so it can be dropped.
112+
unsafe fn release(mut self) -> *mut sys::ABinderRpc_Accessor {
113+
if self.accessor.is_null() {
114+
log::error!("Attempting to release an Accessor that was already released");
115+
return ptr::null_mut();
116+
}
117+
let ptr = self.accessor;
118+
self.accessor = ptr::null_mut();
119+
ptr
120+
}
121+
103122
/// Callback invoked from C++ when the connection info is needed.
104123
///
105124
/// # Safety
106125
///
107-
/// The `instance` parameter must be a non-null pointer to a valid C string for
108-
/// CStr::from_ptr. The memory must contain a valid null terminator at the end of
109-
/// the string within isize::MAX from the pointer. The memory must not be mutated for
110-
/// the duration of this function call and must be valid for reads from the pointer
111-
/// to the null terminator.
112-
/// The `cookie` parameter must be the cookie for an `Arc<F>` and
113-
/// the caller must hold a ref-count to it.
126+
/// - The `instance` parameter must be a non-null pointer to a valid C string for
127+
/// CStr::from_ptr. The memory must contain a valid null terminator at the end of
128+
/// the string within isize::MAX from the pointer. The memory must not be mutated for
129+
/// the duration of this function call and must be valid for reads from the pointer
130+
/// to the null terminator.
131+
/// - The `cookie` parameter must be the cookie for an `Arc<F>` and
132+
/// the caller must hold a ref-count to it.
114133
unsafe extern "C" fn connection_info<F>(
115134
instance: *const c_char,
116135
cookie: *mut c_void,
@@ -172,8 +191,8 @@ impl Accessor {
172191
///
173192
/// # Safety
174193
///
175-
/// The `cookie` parameter must be the cookie for an `Arc<F>` and
176-
/// the owner must give up a ref-count to it.
194+
/// - The `cookie` parameter must be the cookie for an `Arc<F>` and
195+
/// the owner must give up a ref-count to it.
177196
unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
178197
where
179198
F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
@@ -185,6 +204,10 @@ impl Accessor {
185204

186205
impl Drop for Accessor {
187206
fn drop(&mut self) {
207+
if self.accessor.is_null() {
208+
// This Accessor was already released.
209+
return;
210+
}
188211
// Safety: `self.accessor` is always a valid, owned
189212
// `ABinderRpc_Accessor` pointer returned by
190213
// `ABinderRpc_Accessor_new` when `self` was created. This delete
@@ -218,3 +241,140 @@ pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder>
218241
// point, so can be safely passed to `SpIBinder::from_raw`.
219242
Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") })
220243
}
244+
245+
/// Rust wrapper around ABinderRpc_AccessorProvider objects for RPC binder service management.
246+
///
247+
/// Dropping the `AccessorProvider` will drop/unregister the underlying object.
248+
#[derive(Debug)]
249+
pub struct AccessorProvider {
250+
accessor_provider: *mut sys::ABinderRpc_AccessorProvider,
251+
}
252+
253+
/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
254+
/// `Sync` and `Send`. As
255+
/// `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
256+
/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
257+
unsafe impl Send for AccessorProvider {}
258+
259+
/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
260+
/// `Sync` and `Send`. As `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
261+
/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
262+
unsafe impl Sync for AccessorProvider {}
263+
264+
impl AccessorProvider {
265+
/// Create a new `AccessorProvider` that will give libbinder `Accessors` in order to
266+
/// connect to binder services over sockets.
267+
///
268+
/// `instances` is a list of all instances that this `AccessorProvider` is responsible for.
269+
/// It is declaring these instances as available to this process and will return
270+
/// `Accessor` objects for them when libbinder calls the `provider` callback.
271+
/// `provider` is the callback that libbinder will call when a service is being requested.
272+
/// The callback takes a `&str` argument representing the service that is being requested.
273+
/// See the `ABinderRpc_AccessorProvider_getAccessorCallback` for the C++ equivalent.
274+
pub fn new<F>(instances: &[String], provider: F) -> Option<AccessorProvider>
275+
where
276+
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
277+
{
278+
let callback: *mut c_void = Arc::into_raw(Arc::new(provider)) as *mut c_void;
279+
let c_str_instances: Vec<CString> =
280+
instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
281+
let mut c_instances: Vec<*const c_char> =
282+
c_str_instances.iter().map(|s| s.as_ptr()).collect();
283+
let num_instances: usize = c_instances.len();
284+
// Safety:
285+
// - The function pointer for the first argument is a valid `get_accessor` callback.
286+
// - This call returns an owned `ABinderRpc_AccessorProvider` pointer which
287+
// must be destroyed via `ABinderRpc_unregisterAccessorProvider` when no longer
288+
// needed.
289+
// - When the underlying ABinderRpc_AccessorProvider is deleted, it will call
290+
// the `cookie_decr_refcount` callback on the `callback` pointer to release its
291+
// strong ref.
292+
// - The `c_instances` vector is not modified by the function
293+
let accessor_provider = unsafe {
294+
sys::ABinderRpc_registerAccessorProvider(
295+
Some(Self::get_accessor::<F>),
296+
c_instances.as_mut_ptr(),
297+
num_instances,
298+
callback,
299+
Some(Self::accessor_cookie_decr_refcount::<F>),
300+
)
301+
};
302+
303+
if accessor_provider.is_null() {
304+
return None;
305+
}
306+
Some(AccessorProvider { accessor_provider })
307+
}
308+
309+
/// Callback invoked from C++ when an Accessor is needed.
310+
///
311+
/// # Safety
312+
///
313+
/// - libbinder guarantees the `instance` argument is a valid C string if it's not null.
314+
/// - The `cookie` pointer is same pointer that we pass to ABinderRpc_registerAccessorProvider
315+
/// in AccessorProvider.new() which is the closure that we will delete with
316+
/// self.accessor_cookie_decr_refcount when unregistering the AccessorProvider.
317+
unsafe extern "C" fn get_accessor<F>(
318+
instance: *const c_char,
319+
cookie: *mut c_void,
320+
) -> *mut binder_ndk_sys::ABinderRpc_Accessor
321+
where
322+
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
323+
{
324+
if cookie.is_null() || instance.is_null() {
325+
log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!");
326+
return ptr::null_mut();
327+
}
328+
// Safety: The caller promises that `cookie` is for an Arc<F>.
329+
let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
330+
331+
let inst = {
332+
// Safety: The caller in libbinder_ndk will have already verified this is a valid
333+
// C string
334+
match unsafe { CStr::from_ptr(instance) }.to_str() {
335+
Ok(s) => s,
336+
Err(err) => {
337+
log::error!("Failed to get a valid C string! {err:?}");
338+
return ptr::null_mut();
339+
}
340+
}
341+
};
342+
343+
match callback(inst) {
344+
Some(a) => {
345+
// Safety: This is giving up ownership of this ABinderRpc_Accessor
346+
// to the caller of this function (libbinder) and it is responsible
347+
// for deleting it.
348+
unsafe { a.release() }
349+
}
350+
None => ptr::null_mut(),
351+
}
352+
}
353+
354+
/// Callback that decrements the ref-count.
355+
/// This is invoked from C++ when the provider is unregistered.
356+
///
357+
/// # Safety
358+
///
359+
/// - The `cookie` parameter must be the cookie for an `Arc<F>` and
360+
/// the owner must give up a ref-count to it.
361+
unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void)
362+
where
363+
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
364+
{
365+
// Safety: The caller promises that `cookie` is for an Arc<F>.
366+
unsafe { Arc::decrement_strong_count(cookie as *const F) };
367+
}
368+
}
369+
370+
impl Drop for AccessorProvider {
371+
fn drop(&mut self) {
372+
// Safety: `self.accessor_provider` is always a valid, owned
373+
// `ABinderRpc_AccessorProvider` pointer returned by
374+
// `ABinderRpc_registerAccessorProvider` when `self` was created. This delete
375+
// method can only be called once when `self` is dropped.
376+
unsafe {
377+
sys::ABinderRpc_unregisterAccessorProvider(self.accessor_provider);
378+
}
379+
}
380+
}

libs/binder/rust/tests/integration.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ mod tests {
384384
use std::time::Duration;
385385

386386
use binder::{
387-
Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder,
388-
StatusCode, Strong,
387+
Accessor, AccessorProvider, BinderFeatures, DeathRecipient, FromIBinder, IBinder,
388+
Interface, SpIBinder, StatusCode, Strong,
389389
};
390390
// Import from impl API for testing only, should not be necessary as long as
391391
// you are using AIDL.
@@ -982,6 +982,62 @@ mod tests {
982982
assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND));
983983
}
984984

985+
#[test]
986+
fn test_accessor_provider_simple() {
987+
let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
988+
let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
989+
assert!(accessor.is_some());
990+
}
991+
992+
#[test]
993+
fn test_accessor_provider_no_instance() {
994+
let instances: Vec<String> = vec![];
995+
let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
996+
assert!(accessor.is_none());
997+
}
998+
999+
#[test]
1000+
fn test_accessor_provider_double_register() {
1001+
let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
1002+
let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
1003+
assert!(accessor.is_some());
1004+
let accessor2 = AccessorProvider::new(&instances, move |_inst: &str| None);
1005+
assert!(accessor2.is_none());
1006+
}
1007+
1008+
#[test]
1009+
fn test_accessor_provider_register_drop_register() {
1010+
let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
1011+
{
1012+
let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
1013+
assert!(accessor.is_some());
1014+
// accessor drops and unregisters the provider
1015+
}
1016+
{
1017+
let accessor = AccessorProvider::new(&instances, move |_inst: &str| None);
1018+
assert!(accessor.is_some());
1019+
}
1020+
}
1021+
1022+
#[test]
1023+
fn test_accessor_provider_callback_destruction() {
1024+
let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
1025+
let instances: Vec<String> = vec!["foo.service".to_owned(), "foo.other_service".to_owned()];
1026+
{
1027+
let accessor: Option<AccessorProvider>;
1028+
{
1029+
let helper = ToBeDeleted { deleted: deleted.clone() };
1030+
accessor = AccessorProvider::new(&instances, move |_inst: &str| {
1031+
let _ = &helper;
1032+
None
1033+
});
1034+
}
1035+
assert!(accessor.is_some());
1036+
assert!(!deleted.load(Ordering::Relaxed));
1037+
}
1038+
assert!(deleted.load(Ordering::Relaxed));
1039+
}
1040+
9851041
#[tokio::test]
9861042
async fn reassociate_rust_binder_async() {
9871043
let service_name = "testing_service";

0 commit comments

Comments
 (0)