summaryrefslogtreecommitdiff
path: root/libs/binder/rust/src/proxy.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libs/binder/rust/src/proxy.rs')
-rw-r--r--libs/binder/rust/src/proxy.rs678
1 files changed, 678 insertions, 0 deletions
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
new file mode 100644
index 0000000000..52036f5312
--- /dev/null
+++ b/libs/binder/rust/src/proxy.rs
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Rust API for interacting with a remote binder service.
+
+use crate::binder::{
+ AsNative, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Strong,
+ TransactionCode, TransactionFlags,
+};
+use crate::error::{status_result, Result, StatusCode};
+use crate::parcel::{
+ Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+ SerializeOption,
+};
+use crate::sys;
+
+use std::cmp::Ordering;
+use std::convert::TryInto;
+use std::ffi::{c_void, CString};
+use std::fmt;
+use std::os::unix::io::AsRawFd;
+use std::ptr;
+
+/// A strong reference to a Binder remote object.
+///
+/// This struct encapsulates the generic C++ `sp<IBinder>` class. This wrapper
+/// is untyped; typed interface access is implemented by the AIDL compiler.
+pub struct SpIBinder(*mut sys::AIBinder);
+
+impl fmt::Debug for SpIBinder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("SpIBinder")
+ }
+}
+
+/// # Safety
+///
+/// An `SpIBinder` is a handle to a C++ IBinder, which is thread-safe
+unsafe impl Send for SpIBinder {}
+
+impl SpIBinder {
+ /// Create an `SpIBinder` wrapper object from a raw `AIBinder` pointer.
+ ///
+ /// # Safety
+ ///
+ /// This constructor is safe iff `ptr` is a null pointer or a valid pointer
+ /// to an `AIBinder`.
+ ///
+ /// In the non-null case, this method conceptually takes ownership of a strong
+ /// reference to the object, so `AIBinder_incStrong` must have been called
+ /// on the pointer before passing it to this constructor. This is generally
+ /// done by Binder NDK methods that return an `AIBinder`, but care should be
+ /// taken to ensure this invariant.
+ ///
+ /// All `SpIBinder` objects that are constructed will hold a valid pointer
+ /// to an `AIBinder`, which will remain valid for the entire lifetime of the
+ /// `SpIBinder` (we keep a strong reference, and only decrement on drop).
+ pub(crate) unsafe fn from_raw(ptr: *mut sys::AIBinder) -> Option<Self> {
+ ptr.as_mut().map(|p| Self(p))
+ }
+
+ /// Extract a raw `AIBinder` pointer from this wrapper.
+ ///
+ /// This method should _only_ be used for testing. Do not try to use the NDK
+ /// interface directly for anything else.
+ ///
+ /// # Safety
+ ///
+ /// The resulting pointer is valid only as long as the SpIBinder is alive.
+ /// The SpIBinder object retains ownership of the AIBinder and the caller
+ /// should not attempt to free the returned pointer.
+ pub unsafe fn as_raw(&self) -> *mut sys::AIBinder {
+ self.0
+ }
+
+ /// Return true if this binder object is hosted in a different process than
+ /// the current one.
+ pub fn is_remote(&self) -> bool {
+ unsafe {
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer.
+ sys::AIBinder_isRemote(self.as_native())
+ }
+ }
+
+ /// Try to convert this Binder object into a trait object for the given
+ /// Binder interface.
+ ///
+ /// If this object does not implement the expected interface, the error
+ /// `StatusCode::BAD_TYPE` is returned.
+ pub fn into_interface<I: FromIBinder + Interface + ?Sized>(self) -> Result<Strong<I>> {
+ FromIBinder::try_from(self)
+ }
+
+ /// Return the interface class of this binder object, if associated with
+ /// one.
+ pub fn get_class(&mut self) -> Option<InterfaceClass> {
+ unsafe {
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer. `AIBinder_getClass` returns either a null
+ // pointer or a valid pointer to an `AIBinder_Class`. After mapping
+ // null to None, we can safely construct an `InterfaceClass` if the
+ // pointer was non-null.
+ let class = sys::AIBinder_getClass(self.as_native_mut());
+ class.as_ref().map(|p| InterfaceClass::from_ptr(p))
+ }
+ }
+
+ /// Creates a new weak reference to this binder object.
+ pub fn downgrade(&mut self) -> WpIBinder {
+ WpIBinder::new(self)
+ }
+}
+
+/// An object that can be associate with an [`InterfaceClass`].
+pub trait AssociateClass {
+ /// Check if this object is a valid object for the given interface class
+ /// `I`.
+ ///
+ /// Returns `Some(self)` if this is a valid instance of the interface, and
+ /// `None` otherwise.
+ ///
+ /// Classes constructed by `InterfaceClass` are unique per type, so
+ /// repeatedly calling this method for the same `InterfaceClass` is allowed.
+ fn associate_class(&mut self, class: InterfaceClass) -> bool;
+}
+
+impl AssociateClass for SpIBinder {
+ fn associate_class(&mut self, class: InterfaceClass) -> bool {
+ unsafe {
+ // Safety: `SpIBinder` guarantees that it always contains a valid
+ // `AIBinder` pointer. An `InterfaceClass` can always be converted
+ // into a valid `AIBinder_Class` pointer, so these parameters are
+ // always safe.
+ sys::AIBinder_associateClass(self.as_native_mut(), class.into())
+ }
+ }
+}
+
+impl Ord for SpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
+ // this pointer is always safe to pass to `AIBinder_lt` (null is
+ // also safe to pass to this function, but we should never do that).
+ sys::AIBinder_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for SpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for SpIBinder {
+ fn eq(&self, other: &Self) -> bool {
+ ptr::eq(self.0, other.0)
+ }
+}
+
+impl Eq for SpIBinder {}
+
+impl Clone for SpIBinder {
+ fn clone(&self) -> Self {
+ unsafe {
+ // Safety: Cloning a strong reference must increment the reference
+ // count. We are guaranteed by the `SpIBinder` constructor
+ // invariants that `self.0` is always a valid `AIBinder` pointer.
+ sys::AIBinder_incStrong(self.0);
+ }
+ Self(self.0)
+ }
+}
+
+impl Drop for SpIBinder {
+ // We hold a strong reference to the IBinder in SpIBinder and need to give up
+ // this reference on drop.
+ fn drop(&mut self) {
+ unsafe {
+ // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
+ // know this pointer is safe to pass to `AIBinder_decStrong` here.
+ sys::AIBinder_decStrong(self.as_native_mut());
+ }
+ }
+}
+
+impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
+ /// Perform a binder transaction
+ fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+ &self,
+ code: TransactionCode,
+ flags: TransactionFlags,
+ input_callback: F,
+ ) -> Result<Parcel> {
+ let mut input = ptr::null_mut();
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. It is safe to cast from an
+ // immutable pointer to a mutable pointer here, because
+ // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
+ // methods but the parameter is unfortunately not marked as const.
+ //
+ // After the call, input will be either a valid, owned `AParcel`
+ // pointer, or null.
+ sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
+ };
+ status_result(status)?;
+ let mut input = unsafe {
+ // Safety: At this point, `input` is either a valid, owned `AParcel`
+ // pointer, or null. `Parcel::owned` safely handles both cases,
+ // taking ownership of the parcel.
+ Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)?
+ };
+ input_callback(&mut input)?;
+ let mut reply = ptr::null_mut();
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. Although `IBinder::transact` is
+ // not a const method, it is still safe to cast our immutable
+ // pointer to mutable for the call. First, `IBinder::transact` is
+ // thread-safe, so concurrency is not an issue. The only way that
+ // `transact` can affect any visible, mutable state in the current
+ // process is by calling `onTransact` for a local service. However,
+ // in order for transactions to be thread-safe, this method must
+ // dynamically lock its data before modifying it. We enforce this
+ // property in Rust by requiring `Sync` for remotable objects and
+ // only providing `on_transact` with an immutable reference to
+ // `self`.
+ //
+ // This call takes ownership of the `input` parcel pointer, and
+ // passes ownership of the `reply` out parameter to its caller. It
+ // does not affect ownership of the `binder` parameter.
+ sys::AIBinder_transact(
+ self.as_native() as *mut sys::AIBinder,
+ code,
+ &mut input.into_raw(),
+ &mut reply,
+ flags,
+ )
+ };
+ status_result(status)?;
+
+ unsafe {
+ // Safety: `reply` is either a valid `AParcel` pointer or null
+ // after the call to `AIBinder_transact` above, so we can
+ // construct a `Parcel` out of it. `AIBinder_transact` passes
+ // ownership of the `reply` parcel to Rust, so we need to
+ // construct an owned variant. `Parcel::owned` takes ownership
+ // of the parcel pointer.
+ Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+ }
+ }
+
+ fn is_binder_alive(&self) -> bool {
+ unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
+ sys::AIBinder_isAlive(self.as_native())
+ }
+ }
+
+ fn ping_binder(&mut self) -> Result<()> {
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
+ sys::AIBinder_ping(self.as_native_mut())
+ };
+ status_result(status)
+ }
+
+ fn set_requesting_sid(&mut self, enable: bool) {
+ unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
+ }
+
+ fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
+ let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
+ let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
+ // file descriptor parameter is always be a valid open file. The
+ // `args` pointer parameter is a valid pointer to an array of C
+ // strings that will outlive the call since `args` lives for the
+ // whole function scope.
+ //
+ // This call does not affect ownership of its binder pointer
+ // parameter and does not take ownership of the file or args array
+ // parameters.
+ sys::AIBinder_dump(
+ self.as_native_mut(),
+ fp.as_raw_fd(),
+ arg_ptrs.as_mut_ptr(),
+ arg_ptrs.len().try_into().unwrap(),
+ )
+ };
+ status_result(status)
+ }
+
+ fn get_extension(&mut self) -> Result<Option<SpIBinder>> {
+ let mut out = ptr::null_mut();
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. After this call, the `out`
+ // parameter will be either null, or a valid pointer to an
+ // `AIBinder`.
+ //
+ // This call passes ownership of the out pointer to its caller
+ // (assuming it is set to a non-null value).
+ sys::AIBinder_getExtension(self.as_native_mut(), &mut out)
+ };
+ let ibinder = unsafe {
+ // Safety: The call above guarantees that `out` is either null or a
+ // valid, owned pointer to an `AIBinder`, both of which are safe to
+ // pass to `SpIBinder::from_raw`.
+ SpIBinder::from_raw(out)
+ };
+
+ status_result(status)?;
+ Ok(ibinder)
+ }
+}
+
+impl<T: AsNative<sys::AIBinder>> IBinder for T {
+ fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+ status_result(unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `recipient` can always be
+ // converted into a valid pointer to an
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
+ // cookie, although we depend on this value being set by
+ // `get_cookie` when the death recipient callback is called.
+ sys::AIBinder_linkToDeath(
+ self.as_native_mut(),
+ recipient.as_native_mut(),
+ recipient.get_cookie(),
+ )
+ })
+ }
+
+ fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+ status_result(unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`. `recipient` can always be
+ // converted into a valid pointer to an
+ // `AIBinder_DeathRecipient`. Any value is safe to pass as the
+ // cookie, although we depend on this value being set by
+ // `get_cookie` when the death recipient callback is called.
+ sys::AIBinder_unlinkToDeath(
+ self.as_native_mut(),
+ recipient.as_native_mut(),
+ recipient.get_cookie(),
+ )
+ })
+ }
+}
+
+impl Serialize for SpIBinder {
+ fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ parcel.write_binder(Some(self))
+ }
+}
+
+impl SerializeOption for SpIBinder {
+ fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ parcel.write_binder(this)
+ }
+}
+
+impl SerializeArray for SpIBinder {}
+impl SerializeArray for Option<&SpIBinder> {}
+
+impl Deserialize for SpIBinder {
+ fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+ parcel
+ .read_binder()
+ .transpose()
+ .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ }
+}
+
+impl DeserializeOption for SpIBinder {
+ fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+ parcel.read_binder()
+ }
+}
+
+impl DeserializeArray for SpIBinder {}
+impl DeserializeArray for Option<SpIBinder> {}
+
+/// A weak reference to a Binder remote object.
+///
+/// This struct encapsulates the generic C++ `wp<IBinder>` class. This wrapper
+/// is untyped; typed interface access is implemented by the AIDL compiler.
+pub struct WpIBinder(*mut sys::AIBinder_Weak);
+
+impl fmt::Debug for WpIBinder {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("WpIBinder")
+ }
+}
+
+/// # Safety
+///
+/// A `WpIBinder` is a handle to a C++ IBinder, which is thread-safe.
+unsafe impl Send for WpIBinder {}
+
+impl WpIBinder {
+ /// Create a new weak reference from an object that can be converted into a
+ /// raw `AIBinder` pointer.
+ fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
+ let ptr = unsafe {
+ // Safety: `SpIBinder` guarantees that `binder` always contains a
+ // valid pointer to an `AIBinder`.
+ sys::AIBinder_Weak_new(binder.as_native_mut())
+ };
+ assert!(!ptr.is_null());
+ Self(ptr)
+ }
+
+ /// Promote this weak reference to a strong reference to the binder object.
+ pub fn promote(&self) -> Option<SpIBinder> {
+ unsafe {
+ // Safety: `WpIBinder` always contains a valid weak reference, so we
+ // can pass this pointer to `AIBinder_Weak_promote`. Returns either
+ // null or an AIBinder owned by the caller, both of which are valid
+ // to pass to `SpIBinder::from_raw`.
+ let ptr = sys::AIBinder_Weak_promote(self.0);
+ SpIBinder::from_raw(ptr)
+ }
+ }
+}
+
+impl Clone for WpIBinder {
+ fn clone(&self) -> Self {
+ let ptr = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_clone`
+ // (although null is also a safe value to pass to this API).
+ //
+ // We get ownership of the returned pointer, so can construct a new
+ // WpIBinder object from it.
+ sys::AIBinder_Weak_clone(self.0)
+ };
+ assert!(
+ !ptr.is_null(),
+ "Unexpected null pointer from AIBinder_Weak_clone"
+ );
+ Self(ptr)
+ }
+}
+
+impl Ord for WpIBinder {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let less_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(self.0, other.0)
+ };
+ let greater_than = unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
+ // so this pointer is always safe to pass to `AIBinder_Weak_lt`
+ // (null is also safe to pass to this function, but we should never
+ // do that).
+ sys::AIBinder_Weak_lt(other.0, self.0)
+ };
+ if !less_than && !greater_than {
+ Ordering::Equal
+ } else if less_than {
+ Ordering::Less
+ } else {
+ Ordering::Greater
+ }
+ }
+}
+
+impl PartialOrd for WpIBinder {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for WpIBinder {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl Eq for WpIBinder {}
+
+impl Drop for WpIBinder {
+ fn drop(&mut self) {
+ unsafe {
+ // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+ // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
+ sys::AIBinder_Weak_delete(self.0);
+ }
+ }
+}
+
+/// Rust wrapper around DeathRecipient objects.
+#[repr(C)]
+pub struct DeathRecipient {
+ recipient: *mut sys::AIBinder_DeathRecipient,
+ callback: Box<dyn Fn() + Send + 'static>,
+}
+
+impl DeathRecipient {
+ /// Create a new death recipient that will call the given callback when its
+ /// associated object dies.
+ pub fn new<F>(callback: F) -> DeathRecipient
+ where
+ F: Fn() + Send + 'static,
+ {
+ let callback = Box::new(callback);
+ let recipient = unsafe {
+ // Safety: The function pointer is a valid death recipient callback.
+ //
+ // This call returns an owned `AIBinder_DeathRecipient` pointer
+ // which must be destroyed via `AIBinder_DeathRecipient_delete` when
+ // no longer needed.
+ sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
+ };
+ DeathRecipient {
+ recipient,
+ callback,
+ }
+ }
+
+ /// Get the opaque cookie that identifies this death recipient.
+ ///
+ /// This cookie will be used to link and unlink this death recipient to a
+ /// binder object and will be passed to the `binder_died` callback as an
+ /// opaque userdata pointer.
+ fn get_cookie(&self) -> *mut c_void {
+ &*self.callback as *const _ as *mut c_void
+ }
+
+ /// Callback invoked from C++ when the binder object dies.
+ ///
+ /// # Safety
+ ///
+ /// The `cookie` parameter must have been created with the `get_cookie`
+ /// method of this object.
+ unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
+ where
+ F: Fn() + Send + 'static,
+ {
+ let callback = (cookie as *mut F).as_ref().unwrap();
+ callback();
+ }
+}
+
+/// # Safety
+///
+/// A `DeathRecipient` is always constructed with a valid raw pointer to an
+/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this
+/// pointer.
+unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
+ fn as_native(&self) -> *const sys::AIBinder_DeathRecipient {
+ self.recipient
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AIBinder_DeathRecipient {
+ self.recipient
+ }
+}
+
+impl Drop for DeathRecipient {
+ fn drop(&mut self) {
+ unsafe {
+ // Safety: `self.recipient` is always a valid, owned
+ // `AIBinder_DeathRecipient` pointer returned by
+ // `AIBinder_DeathRecipient_new` when `self` was created. This
+ // delete method can only be called once when `self` is dropped.
+ sys::AIBinder_DeathRecipient_delete(self.recipient);
+ }
+ }
+}
+
+/// Generic interface to remote binder objects.
+///
+/// Corresponds to the C++ `BpInterface` class.
+pub trait Proxy: Sized + Interface {
+ /// The Binder interface descriptor string.
+ ///
+ /// This string is a unique identifier for a Binder interface, and should be
+ /// the same between all implementations of that interface.
+ fn get_descriptor() -> &'static str;
+
+ /// Create a new interface from the given proxy, if it matches the expected
+ /// type of this interface.
+ fn from_binder(binder: SpIBinder) -> Result<Self>;
+}
+
+/// # Safety
+///
+/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow
+/// invocation of `IBinder` methods directly from `Interface` objects. It shares
+/// the same safety as the implementation for `SpIBinder`.
+unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
+ fn as_native(&self) -> *const sys::AIBinder {
+ self.as_binder().as_native()
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AIBinder {
+ self.as_binder().as_native_mut()
+ }
+}
+
+/// Retrieve an existing service, blocking for a few seconds if it doesn't yet
+/// exist.
+pub fn get_service(name: &str) -> Option<SpIBinder> {
+ let name = CString::new(name).ok()?;
+ unsafe {
+ // Safety: `AServiceManager_getService` 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`.
+ SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr()))
+ }
+}
+
+/// Retrieve an existing service for a particular interface, blocking for a few
+/// seconds if it doesn't yet exist.
+pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
+ let service = get_service(name);
+ match service {
+ Some(service) => FromIBinder::try_from(service),
+ None => Err(StatusCode::NAME_NOT_FOUND),
+ }
+}
+
+/// # Safety
+///
+/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
+/// `AIBinder`, so we can trivially extract this pointer here.
+unsafe impl AsNative<sys::AIBinder> for SpIBinder {
+ fn as_native(&self) -> *const sys::AIBinder {
+ self.0
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AIBinder {
+ self.0
+ }
+}