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

Commit 72b799d4 authored by Andrei Homescu's avatar Andrei Homescu
Browse files

binder_rs: Add new methods to Parcel

Add a few new methods and a trait implementation to Parcel:
* Parcel::new() and Parcel::default() which create a new empty Parcel
  by calling AParcel_create
* Parcel::append_from() and Parcel::append_all_from()
  which call AParcel_appendFrom
* Clone trait implementation using append_all_from()

Bug: 169035750
Test: atest binder_rs-internal_test
Change-Id: I89404883e9a115676523a974646d9243ac44903b
parent 5c133845
Loading
Loading
Loading
Loading
+99 −50
Original line number Diff line number Diff line
@@ -69,6 +69,21 @@ unsafe impl AsNative<sys::AParcel> for Parcel {
}

impl Parcel {
    /// Create a new empty `Parcel`.
    ///
    /// Creates a new owned empty parcel that can be written to
    /// using the serialization methods and appended to and
    /// from using `append_from` and `append_from_all`.
    pub fn new() -> Parcel {
        let parcel = unsafe {
            // Safety: If `AParcel_create` succeeds, it always returns
            // a valid pointer. If it fails, the process will crash.
            sys::AParcel_create()
        };
        assert!(!parcel.is_null());
        Self::Owned(parcel)
    }

    /// Create a borrowed reference to a parcel object from a raw pointer.
    ///
    /// # Safety
@@ -107,6 +122,22 @@ impl Parcel {
    }
}

impl Default for Parcel {
    fn default() -> Self {
        Self::new()
    }
}

impl Clone for Parcel {
    fn clone(&self) -> Self {
        let mut new_parcel = Self::new();
        new_parcel
            .append_all_from(self)
            .expect("Failed to append from Parcel");
        new_parcel
    }
}

// Data serialization methods
impl Parcel {
    /// Data written to parcelable is zero'd before being deleted or reallocated.
@@ -214,6 +245,30 @@ impl Parcel {
    pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
        status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
    }

    /// Append a subset of another `Parcel`.
    ///
    /// This appends `size` bytes of data from `other` starting at offset
    /// `start` to the current `Parcel`, or returns an error if not possible.
    pub fn append_from(&mut self, other: &Self, start: i32, size: i32) -> Result<()> {
        let status = unsafe {
            // Safety: `Parcel::appendFrom` from C++ checks that `start`
            // and `size` are in bounds, and returns an error otherwise.
            // Both `self` and `other` always contain valid pointers.
            sys::AParcel_appendFrom(
                other.as_native(),
                self.as_native_mut(),
                start,
                size,
            )
        };
        status_result(status)
    }

    /// Append the contents of another `Parcel`.
    pub fn append_all_from(&mut self, other: &Self) -> Result<()> {
        self.append_from(other, 0, other.get_data_size())
    }
}

/// A segment of a writable parcel, used for [`Parcel::sized_write`].
@@ -428,43 +483,9 @@ impl fmt::Debug for Parcel {
    }
}

#[cfg(test)]
impl Parcel {
    /// Create a new parcel tied to a bogus binder. TESTING ONLY!
    ///
    /// This can only be used for testing! All real parcel operations must be
    /// done in the callback to [`IBinder::transact`] or in
    /// [`Remotable::on_transact`] using the parcels provided to these methods.
    pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> {
        let mut input = ptr::null_mut();
        let status = unsafe {
            // Safety: `SpIBinder` guarantees that `binder` always contains a
            // valid pointer to an `AIBinder`. We pass a valid, mutable out
            // pointer to receive a newly constructed parcel. When successful
            // this function assigns a new pointer to an `AParcel` to `input`
            // and transfers ownership of this pointer to the caller. Thus,
            // after this call, `input` will either be null or point to a valid,
            // owned `AParcel`.
            sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input)
        };
        status_result(status)?;
        unsafe {
            // Safety: `input` is either null or a valid, owned pointer to an
            // `AParcel`, so is valid to safe to
            // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel
            // pointer.
            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
        }
    }
}

#[test]
fn test_read_write() {
    use crate::binder::Interface;
    use crate::native::Binder;

    let mut service = Binder::new(()).as_binder();
    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA));
@@ -494,11 +515,7 @@ fn test_read_write() {
#[test]
#[allow(clippy::float_cmp)]
fn test_read_data() {
    use crate::binder::Interface;
    use crate::native::Binder;

    let mut service = Binder::new(()).as_binder();
    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let str_start = parcel.get_data_position();

    parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
@@ -573,11 +590,7 @@ fn test_read_data() {

#[test]
fn test_utf8_utf16_conversions() {
    use crate::binder::Interface;
    use crate::native::Binder;

    let mut service = Binder::new(()).as_binder();
    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    assert!(parcel.write("Hello, Binder!").is_ok());
@@ -637,11 +650,7 @@ fn test_utf8_utf16_conversions() {

#[test]
fn test_sized_write() {
    use crate::binder::Interface;
    use crate::native::Binder;

    let mut service = Binder::new(()).as_binder();
    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    let arr = [1i32, 2i32, 3i32];
@@ -669,3 +678,43 @@ fn test_sized_write() {
        &arr,
    );
}

#[test]
fn test_append_from() {
    let mut parcel1 = Parcel::new();
    parcel1.write(&42i32).expect("Could not perform write");

    let mut parcel2 = Parcel::new();
    assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
    assert_eq!(4, parcel2.get_data_size());
    assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
    assert_eq!(8, parcel2.get_data_size());
    unsafe {
        parcel2.set_data_position(0).unwrap();
    }
    assert_eq!(Ok(42), parcel2.read::<i32>());
    assert_eq!(Ok(42), parcel2.read::<i32>());

    let mut parcel2 = Parcel::new();
    assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
    assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2));
    assert_eq!(4, parcel2.get_data_size());
    unsafe {
        parcel2.set_data_position(0).unwrap();
    }
    assert_eq!(Ok(42), parcel2.read::<i32>());

    let mut parcel2 = Parcel::new();
    assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
    assert_eq!(2, parcel2.get_data_size());
    unsafe {
        parcel2.set_data_position(0).unwrap();
    }
    assert_eq!(Err(StatusCode::NOT_ENOUGH_DATA), parcel2.read::<i32>());

    let mut parcel2 = Parcel::new();
    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 4, 2));
    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, 4));
    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, -1, 4));
    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, -1));
}
+3 −11
Original line number Diff line number Diff line
@@ -861,10 +861,6 @@ impl<T: DeserializeOption> DeserializeOption for Box<T> {

#[test]
fn test_custom_parcelable() {
    use crate::binder::Interface;
    use crate::native::Binder;
    let mut service = Binder::new(()).as_binder();

    struct Custom(u32, bool, String, Vec<String>);

    impl Serialize for Custom {
@@ -897,7 +893,7 @@ fn test_custom_parcelable() {

    let custom = Custom(123_456_789, true, string8, strs);

    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    assert!(custom.serialize(&mut parcel).is_ok());
@@ -917,13 +913,9 @@ fn test_custom_parcelable() {
#[test]
#[allow(clippy::excessive_precision)]
fn test_slice_parcelables() {
    use crate::binder::Interface;
    use crate::native::Binder;
    let mut service = Binder::new(()).as_binder();

    let bools = [true, false, false, true];

    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    assert!(bools.serialize(&mut parcel).is_ok());
@@ -947,7 +939,7 @@ fn test_slice_parcelables() {

    let u8s = [101u8, 255, 42, 117];

    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
    let mut parcel = Parcel::new();
    let start = parcel.get_data_position();

    assert!(parcel.write(&u8s[..]).is_ok());