diff options
| -rw-r--r-- | libs/binder/rust/src/binder.rs | 16 | ||||
| -rw-r--r-- | libs/binder/rust/src/lib.rs | 2 | ||||
| -rw-r--r-- | libs/binder/rust/src/parcel.rs | 147 | ||||
| -rw-r--r-- | libs/binder/rust/src/proxy.rs | 18 |
4 files changed, 137 insertions, 46 deletions
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 854b1f9d4e..cc5dd06c9b 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -17,7 +17,7 @@ //! Trait definitions for binder objects use crate::error::{status_t, Result, StatusCode}; -use crate::parcel::Parcel; +use crate::parcel::{OwnedParcel, Parcel}; use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder}; use crate::sys; @@ -177,25 +177,25 @@ pub trait IBinderInternal: IBinder { fn get_extension(&mut self) -> Result<Option<SpIBinder>>; /// Create a Parcel that can be used with `submit_transact`. - fn prepare_transact(&self) -> Result<Parcel>; + fn prepare_transact(&self) -> Result<OwnedParcel>; /// Perform a generic operation with the object. /// - /// The provided [`Parcel`] must have been created by a call to + /// The provided [`OwnedParcel`] must have been created by a call to /// `prepare_transact` on the same binder. /// /// # Arguments /// /// * `code` - Transaction code for the operation. - /// * `data` - [`Parcel`] with input data. + /// * `data` - [`OwnedParcel`] with input data. /// * `flags` - Transaction flags, e.g. marking the transaction as /// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)). fn submit_transact( &self, code: TransactionCode, - data: Parcel, + data: OwnedParcel, flags: TransactionFlags, - ) -> Result<Parcel>; + ) -> Result<OwnedParcel>; /// Perform a generic operation with the object. This is a convenience /// method that internally calls `prepare_transact` followed by @@ -213,8 +213,8 @@ pub trait IBinderInternal: IBinder { input_callback: F, ) -> Result<Parcel> { let mut parcel = self.prepare_transact()?; - input_callback(&mut parcel)?; - self.submit_transact(code, parcel, flags) + input_callback(&mut parcel.borrowed())?; + self.submit_transact(code, parcel, flags).map(OwnedParcel::into_parcel) } } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index d1d37d710f..81b620e85f 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -113,7 +113,7 @@ pub use crate::binder::{ }; pub use error::{status_t, ExceptionCode, Result, Status, StatusCode}; pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder}; -pub use parcel::Parcel; +pub use parcel::{OwnedParcel, Parcel}; pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service}; pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder}; pub use state::{ProcessState, ThreadState}; diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 73915610d8..9dba950677 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -23,6 +23,7 @@ use crate::sys; use std::cell::RefCell; use std::convert::TryInto; +use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ptr; use std::fmt; @@ -52,6 +53,106 @@ pub enum Parcel { Borrowed(*mut sys::AParcel), } +/// A variant of Parcel that is known to be owned. +pub struct OwnedParcel { + ptr: *mut sys::AParcel, +} + +/// # Safety +/// +/// This type guarantees that it owns the AParcel and that all access to +/// the AParcel happens through the OwnedParcel, so it is ok to send across +/// threads. +unsafe impl Send for OwnedParcel {} + +/// A variant of Parcel that is known to be borrowed. +pub struct BorrowedParcel<'a> { + inner: Parcel, + _lifetime: PhantomData<&'a mut Parcel>, +} + +impl OwnedParcel { + /// Create a new empty `OwnedParcel`. + pub fn new() -> OwnedParcel { + let ptr = unsafe { + // Safety: If `AParcel_create` succeeds, it always returns + // a valid pointer. If it fails, the process will crash. + sys::AParcel_create() + }; + assert!(!ptr.is_null()); + Self { ptr } + } + + /// Create an owned reference to a parcel object from a raw pointer. + /// + /// # Safety + /// + /// This constructor is safe if the raw pointer parameter is either null + /// (resulting in `None`), or a valid pointer to an `AParcel` object. The + /// parcel object must be owned by the caller prior to this call, as this + /// constructor takes ownership of the parcel and will destroy it on drop. + /// + /// Additionally, the caller must guarantee that it is valid to take + /// ownership of the AParcel object. All future access to the AParcel + /// must happen through this `OwnedParcel`. + /// + /// Because `OwnedParcel` implements `Send`, the pointer must never point + /// to any thread-local data, e.g., a variable on the stack, either directly + /// or indirectly. + pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<OwnedParcel> { + ptr.as_mut().map(|ptr| Self { ptr }) + } + + /// Consume the parcel, transferring ownership to the caller. + pub(crate) fn into_raw(self) -> *mut sys::AParcel { + let ptr = self.ptr; + let _ = ManuallyDrop::new(self); + ptr + } + + /// Convert this `OwnedParcel` into an owned `Parcel`. + pub fn into_parcel(self) -> Parcel { + Parcel::Owned(self.into_raw()) + } + + /// Get a borrowed view into the contents of this `Parcel`. + pub fn borrowed(&mut self) -> BorrowedParcel<'_> { + BorrowedParcel { + inner: Parcel::Borrowed(self.ptr), + _lifetime: PhantomData, + } + } +} + +impl Default for OwnedParcel { + fn default() -> Self { + Self::new() + } +} + +impl Clone for OwnedParcel { + fn clone(&self) -> Self { + let mut new_parcel = Self::new(); + new_parcel + .borrowed() + .append_all_from(&Parcel::Borrowed(self.ptr)) + .expect("Failed to append from Parcel"); + new_parcel + } +} + +impl<'a> std::ops::Deref for BorrowedParcel<'a> { + type Target = Parcel; + fn deref(&self) -> &Parcel { + &self.inner + } +} +impl<'a> std::ops::DerefMut for BorrowedParcel<'a> { + fn deref_mut(&mut self) -> &mut Parcel { + &mut self.inner + } +} + /// # Safety /// /// The `Parcel` constructors guarantee that a `Parcel` object will always @@ -95,33 +196,6 @@ impl Parcel { pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> { ptr.as_mut().map(|ptr| Self::Borrowed(ptr)) } - - /// Create an owned reference to a parcel object from a raw pointer. - /// - /// # Safety - /// - /// This constructor is safe if the raw pointer parameter is either null - /// (resulting in `None`), or a valid pointer to an `AParcel` object. The - /// parcel object must be owned by the caller prior to this call, as this - /// constructor takes ownership of the parcel and will destroy it on drop. - pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> { - ptr.as_mut().map(|ptr| Self::Owned(ptr)) - } - - /// Consume the parcel, transferring ownership to the caller if the parcel - /// was owned. - pub(crate) fn into_raw(mut self) -> *mut sys::AParcel { - let ptr = self.as_native_mut(); - let _ = ManuallyDrop::new(self); - ptr - } - - pub(crate) fn is_owned(&self) -> bool { - match *self { - Self::Owned(_) => true, - Self::Borrowed(_) => false, - } - } } impl Default for Parcel { @@ -478,6 +552,18 @@ impl Drop for Parcel { } } +impl Drop for OwnedParcel { + fn drop(&mut self) { + // Run the C++ Parcel complete object destructor + unsafe { + // Safety: `OwnedParcel` always contains a valid pointer to an + // `AParcel`. Since we own the parcel, we can safely delete it + // here. + sys::AParcel_delete(self.ptr) + } + } +} + impl fmt::Debug for Parcel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Parcel") @@ -485,6 +571,13 @@ impl fmt::Debug for Parcel { } } +impl fmt::Debug for OwnedParcel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedParcel") + .finish() + } +} + #[test] fn test_read_write() { let mut parcel = Parcel::new(); diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 2c5b0a8421..a8d0c33034 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -22,7 +22,7 @@ use crate::binder::{ }; use crate::error::{status_result, Result, StatusCode}; use crate::parcel::{ - Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray, + Deserialize, DeserializeArray, DeserializeOption, OwnedParcel, Parcel, Serialize, SerializeArray, SerializeOption, }; use crate::sys; @@ -235,7 +235,7 @@ impl Drop for SpIBinder { } impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { - fn prepare_transact(&self) -> Result<Parcel> { + fn prepare_transact(&self) -> Result<OwnedParcel> { let mut input = ptr::null_mut(); let status = unsafe { // Safety: `SpIBinder` guarantees that `self` always contains a @@ -253,20 +253,19 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { unsafe { // Safety: At this point, `input` is either a valid, owned `AParcel` - // pointer, or null. `Parcel::owned` safely handles both cases, + // pointer, or null. `OwnedParcel::from_raw` safely handles both cases, // taking ownership of the parcel. - Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL) + OwnedParcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) } } fn submit_transact( &self, code: TransactionCode, - data: Parcel, + data: OwnedParcel, flags: TransactionFlags, - ) -> Result<Parcel> { + ) -> Result<OwnedParcel> { let mut reply = ptr::null_mut(); - assert!(data.is_owned()); let status = unsafe { // Safety: `SpIBinder` guarantees that `self` always contains a // valid pointer to an `AIBinder`. Although `IBinder::transact` is @@ -299,9 +298,8 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { // 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) + // construct an owned variant. + OwnedParcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) } } |