Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70c7c0da authored by Matthew Maurer's avatar Matthew Maurer Committed by Automerger Merge Worker
Browse files

Merge "libbinder_rs: Add Strong<> and Weak<> Binder references" am: 7125b188...

Merge "libbinder_rs: Add Strong<> and Weak<> Binder references" am: 7125b188 am: 20ceb7e7 am: 0e72ca42

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1534139

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I9ebaa587aea162205661b3aec5e918b5a9134948
parents 72ef3f3d 0e72ca42
Loading
Loading
Loading
Loading
+145 −13
Original line number Diff line number Diff line
@@ -16,12 +16,17 @@

//! Trait definitions for binder objects

use crate::error::{status_t, Result};
use crate::error::{status_t, Result, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::{DeathRecipient, SpIBinder};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
@@ -44,7 +49,7 @@ pub type TransactionFlags = u32;
/// interfaces) must implement this trait.
///
/// This is equivalent `IInterface` in C++.
pub trait Interface {
pub trait Interface: Send {
    /// Convert this binder object into a generic [`SpIBinder`] reference.
    fn as_binder(&self) -> SpIBinder {
        panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
@@ -230,6 +235,132 @@ impl From<InterfaceClass> for *const sys::AIBinder_Class {
    }
}

/// Strong reference to a binder object
pub struct Strong<I: FromIBinder + ?Sized>(Box<I>);

impl<I: FromIBinder + ?Sized> Strong<I> {
    /// Create a new strong reference to the provided binder object
    pub fn new(binder: Box<I>) -> Self {
        Self(binder)
    }

    /// Construct a new weak reference to this binder
    pub fn downgrade(this: &Strong<I>) -> Weak<I> {
        Weak::new(this)
    }
}

impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
    fn clone(&self) -> Self {
        // Since we hold a strong reference, we should always be able to create
        // a new strong reference to the same interface type, so try_from()
        // should never fail here.
        FromIBinder::try_from(self.0.as_binder()).unwrap()
    }
}

impl<I: FromIBinder + ?Sized> Borrow<I> for Strong<I> {
    fn borrow(&self) -> &I {
        &self.0
    }
}

impl<I: FromIBinder + ?Sized> AsRef<I> for Strong<I> {
    fn as_ref(&self) -> &I {
        &self.0
    }
}

impl<I: FromIBinder + ?Sized> Deref for Strong<I> {
    type Target = I;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<I: FromIBinder + fmt::Debug + ?Sized> fmt::Debug for Strong<I> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

impl<I: FromIBinder + ?Sized> Ord for Strong<I> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.as_binder().cmp(&other.0.as_binder())
    }
}

impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.as_binder().partial_cmp(&other.0.as_binder())
    }
}

impl<I: FromIBinder + ?Sized> PartialEq for Strong<I> {
    fn eq(&self, other: &Self) -> bool {
        self.0.as_binder().eq(&other.0.as_binder())
    }
}

impl<I: FromIBinder + ?Sized> Eq for Strong<I> {}

/// Weak reference to a binder object
#[derive(Debug)]
pub struct Weak<I: FromIBinder + ?Sized> {
    weak_binder: WpIBinder,
    interface_type: PhantomData<I>,
}

impl<I: FromIBinder + ?Sized> Weak<I> {
    /// Construct a new weak reference from a strong reference
    fn new(binder: &Strong<I>) -> Self {
        let weak_binder = binder.as_binder().downgrade();
        Weak {
            weak_binder,
            interface_type: PhantomData,
        }
    }

    /// Upgrade this weak reference to a strong reference if the binder object
    /// is still alive
    pub fn upgrade(&self) -> Result<Strong<I>> {
        self.weak_binder
            .promote()
            .ok_or(StatusCode::DEAD_OBJECT)
            .and_then(FromIBinder::try_from)
    }
}

impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
    fn clone(&self) -> Self {
        Self {
            weak_binder: self.weak_binder.clone(),
            interface_type: PhantomData,
        }
    }
}

impl<I: FromIBinder + ?Sized> Ord for Weak<I> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.weak_binder.cmp(&other.weak_binder)
    }
}

impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.weak_binder.partial_cmp(&other.weak_binder)
    }
}

impl<I: FromIBinder + ?Sized> PartialEq for Weak<I> {
    fn eq(&self, other: &Self) -> bool {
        self.weak_binder == other.weak_binder
    }
}

impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}

/// Create a function implementing a static getter for an interface class.
///
/// Each binder interface (i.e. local [`Remotable`] service or remote proxy
@@ -354,12 +485,12 @@ pub trait InterfaceClassMethods {
///     }
/// }
/// ```
pub trait FromIBinder {
pub trait FromIBinder: Interface {
    /// Try to interpret a generic Binder object as this interface.
    ///
    /// Returns a trait object for the `Self` interface if this object
    /// implements that interface.
    fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>;
    fn try_from(ibinder: SpIBinder) -> Result<Strong<Self>>;
}

/// Trait for transparent Rust wrappers around android C++ native types.
@@ -534,8 +665,9 @@ macro_rules! declare_binder_interface {

        impl $native {
            /// Create a new binder service.
            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface {
                $crate::Binder::new($native(Box::new(inner)))
            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
                let binder = $crate::Binder::new($native(Box::new(inner)));
                $crate::Strong::new(Box::new(binder))
            }
        }

@@ -577,7 +709,7 @@ macro_rules! declare_binder_interface {
        }

        impl $crate::FromIBinder for dyn $interface {
            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $interface>> {
                use $crate::AssociateClass;

                let existing_class = ibinder.get_class();
@@ -590,7 +722,7 @@ macro_rules! declare_binder_interface {
                        // associated object as remote, because we can't cast it
                        // into a Rust service object without a matching class
                        // pointer.
                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                    }
                }

@@ -600,10 +732,10 @@ macro_rules! declare_binder_interface {
                    if let Ok(service) = service {
                        // We were able to associate with our expected class and
                        // the service is local.
                        return Ok(Box::new(service));
                        return Ok($crate::Strong::new(Box::new(service)));
                    } else {
                        // Service is remote
                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                    }
                }

@@ -633,9 +765,9 @@ macro_rules! declare_binder_interface {
            }
        }

        // Convert a &dyn $interface to Box<dyn $interface>
        /// Convert a &dyn $interface to Strong<dyn $interface>
        impl std::borrow::ToOwned for dyn $interface {
            type Owned = Box<dyn $interface>;
            type Owned = $crate::Strong<dyn $interface>;
            fn to_owned(&self) -> Self::Owned {
                self.as_binder().into_interface()
                    .expect(concat!("Error cloning interface ", stringify!($interface)))
+4 −2
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ use binder_ndk_sys as sys;
pub mod parcel;

pub use crate::binder::{
    FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags,
    FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
    TransactionFlags, Weak,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -122,7 +123,8 @@ pub mod public_api {
    pub use super::parcel::ParcelFileDescriptor;
    pub use super::{add_service, get_interface};
    pub use super::{
        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
        Weak, WpIBinder,
    };

    /// Binder result containing a [`Status`] on error.
+5 −5
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

use crate::binder::{AsNative, FromIBinder};
use crate::binder::{AsNative, FromIBinder, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::SpIBinder;
@@ -628,26 +628,26 @@ impl Deserialize for Status {
    }
}

impl<T: Serialize + ?Sized> Serialize for Box<T> {
impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
        Serialize::serialize(&**self, parcel)
    }
}

impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> {
impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
        SerializeOption::serialize_option(this.map(|b| &**b), parcel)
    }
}

impl<T: FromIBinder + ?Sized> Deserialize for Box<T> {
impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
    fn deserialize(parcel: &Parcel) -> Result<Self> {
        let ibinder: SpIBinder = parcel.read()?;
        FromIBinder::try_from(ibinder)
    }
}

impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> {
impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
        let ibinder: Option<SpIBinder> = parcel.read()?;
        ibinder.map(FromIBinder::try_from).transpose()
+92 −5
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
//! Rust API for interacting with a remote binder service.

use crate::binder::{
    AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags,
    AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
@@ -27,6 +27,7 @@ use crate::parcel::{
use crate::sys;

use std::convert::TryInto;
use std::cmp::Ordering;
use std::ffi::{c_void, CString};
use std::fmt;
use std::os::unix::io::AsRawFd;
@@ -99,7 +100,7 @@ impl SpIBinder {
    ///
    /// If this object does not implement the expected interface, the error
    /// `StatusCode::BAD_TYPE` is returned.
    pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> {
    pub fn into_interface<I: FromIBinder + Interface + ?Sized>(self) -> Result<Strong<I>> {
        FromIBinder::try_from(self)
    }

@@ -148,6 +149,36 @@ impl AssociateClass for SpIBinder {
    }
}

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)
@@ -326,7 +357,7 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
            // 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_DeatRecipient`. Any value is safe to pass as the
            // `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(
@@ -342,7 +373,7 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T {
            // 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_DeatRecipient`. Any value is safe to pass as the
            // `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(
@@ -430,6 +461,62 @@ impl WpIBinder {
    }
}

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 {
@@ -564,7 +651,7 @@ pub fn get_service(name: &str) -> Option<SpIBinder> {

/// 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<Box<T>> {
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),
+57 −6
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ mod tests {
    use std::thread;
    use std::time::Duration;

    use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
    use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};

    use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};

@@ -271,7 +271,7 @@ mod tests {
    fn trivial_client() {
        let service_name = "trivial_client_test";
        let _process = ScopedServiceProcess::new(service_name);
        let test_client: Box<dyn ITest> =
        let test_client: Strong<dyn ITest> =
            binder::get_interface(service_name).expect("Did not get manager binder service");
        assert_eq!(test_client.test().unwrap(), "trivial_client_test");
    }
@@ -280,7 +280,7 @@ mod tests {
    fn get_selinux_context() {
        let service_name = "get_selinux_context";
        let _process = ScopedServiceProcess::new(service_name);
        let test_client: Box<dyn ITest> =
        let test_client: Strong<dyn ITest> =
            binder::get_interface(service_name).expect("Did not get manager binder service");
        let expected_context = unsafe {
            let mut out_ptr = ptr::null_mut();
@@ -453,7 +453,7 @@ mod tests {

            let extension = maybe_extension.expect("Remote binder did not have an extension");

            let extension: Box<dyn ITest> = FromIBinder::try_from(extension)
            let extension: Strong<dyn ITest> = FromIBinder::try_from(extension)
                .expect("Extension could not be converted to the expected interface");

            assert_eq!(extension.test().unwrap(), extension_name);
@@ -479,7 +479,7 @@ mod tests {

        // This should succeed although we will have to treat the service as
        // remote.
        let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
        let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
            .expect("Could not re-interpret service as the ITestSameDescriptor interface");
    }

@@ -490,9 +490,60 @@ mod tests {
        let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
            .as_binder();

        let service: Box<dyn ITest> = service_ibinder.into_interface()
        let service: Strong<dyn ITest> = service_ibinder.into_interface()
            .expect("Could not reassociate the generic ibinder");

        assert_eq!(service.test().unwrap(), service_name);
    }

    #[test]
    fn weak_binder_upgrade() {
        let service_name = "testing_service";
        let service = BnTest::new_binder(TestService { s: service_name.to_string() });

        let weak = Strong::downgrade(&service);

        let upgraded = weak.upgrade().expect("Could not upgrade weak binder");

        assert_eq!(service, upgraded);
    }

    #[test]
    fn weak_binder_upgrade_dead() {
        let service_name = "testing_service";
        let weak = {
            let service = BnTest::new_binder(TestService { s: service_name.to_string() });

            Strong::downgrade(&service)
        };

        assert_eq!(weak.upgrade(), Err(StatusCode::DEAD_OBJECT));
    }

    #[test]
    fn weak_binder_clone() {
        let service_name = "testing_service";
        let service = BnTest::new_binder(TestService { s: service_name.to_string() });

        let weak = Strong::downgrade(&service);
        let cloned = weak.clone();
        assert_eq!(weak, cloned);

        let upgraded = weak.upgrade().expect("Could not upgrade weak binder");
        let clone_upgraded = cloned.upgrade().expect("Could not upgrade weak binder");

        assert_eq!(service, upgraded);
        assert_eq!(service, clone_upgraded);
    }

    #[test]
    #[allow(clippy::eq_op)]
    fn binder_ord() {
        let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
        let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });

        assert!(!(service1 < service1));
        assert!(!(service1 > service1));
        assert_eq!(service1 < service2, !(service2 < service1));
    }
}
Loading