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

Commit 2c62f367 authored by Jooyung Han's avatar Jooyung Han Committed by Gerrit Code Review
Browse files

Merge changes from topics "aidl-rust-null-parcelable-flags",...

Merge changes from topics "aidl-rust-null-parcelable-flags", "aidl-rust-parcelable-holder", "aidl-rust-parcelable-trait"

* changes:
  binder_rs: Implement ParcelableHolder
  binder_rs: Add null parcelable flags
  binder_rs: Add new methods to Parcel
  binder_rs: Add Parcelable trait
  binder_rs: Implement traits for Stability
parents 8347ab59 ea406211
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ rust_library {
    rustlibs: [
        "liblibc",
        "libbinder_ndk_sys",
        "libdowncast_rs",
    ],
    host_supported: true,
    target: {
@@ -133,6 +134,7 @@ rust_test {
    rustlibs: [
        "liblibc",
        "libbinder_ndk_sys",
        "libdowncast_rs",
    ],
}

+24 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ use crate::sys;

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::fs::File;
@@ -70,6 +71,7 @@ pub trait Interface: Send + Sync {
/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
/// makes no stability guarantees ([`Local`]). [`Local`] is
/// currently the default stability.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Stability {
    /// Default stability, visible to other modules in the same compilation
    /// context (e.g. modules on system.img)
@@ -85,6 +87,28 @@ impl Default for Stability {
    }
}

impl From<Stability> for i32 {
    fn from(stability: Stability) -> i32 {
        use Stability::*;
        match stability {
            Local => 0,
            Vintf => 1,
        }
    }
}

impl TryFrom<i32> for Stability {
    type Error = StatusCode;
    fn try_from(stability: i32) -> Result<Stability> {
        use Stability::*;
        match stability {
            0 => Ok(Local),
            1 => Ok(Vintf),
            _ => Err(StatusCode::BAD_VALUE)
        }
    }
}

/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ pub mod unstable_api {

/// The public API usable outside AIDL-generated interface crates.
pub mod public_api {
    pub use super::parcel::ParcelFileDescriptor;
    pub use super::parcel::{ParcelFileDescriptor, ParcelableHolder};
    pub use super::{
        add_service, force_lazy_services_persist, get_interface, register_lazy_service,
        wait_for_interface,
+102 −50
Original line number Diff line number Diff line
@@ -29,11 +29,14 @@ use std::fmt;

mod file_descriptor;
mod parcelable;
mod parcelable_holder;

pub use self::file_descriptor::ParcelFileDescriptor;
pub use self::parcelable::{
    Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
    Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
};
pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};

/// Container for a message (data and object references) that can be sent
/// through Binder.
@@ -68,6 +71,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
@@ -106,6 +124,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.
@@ -213,6 +247,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`].
@@ -427,43 +485,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));
@@ -493,11 +517,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();
@@ -572,11 +592,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());
@@ -636,11 +652,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];
@@ -668,3 +680,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));
}
+104 −29
Original line number Diff line number Diff line
@@ -14,19 +14,42 @@
 * limitations under the License.
 */

use crate::binder::{AsNative, FromIBinder, Strong};
use crate::binder::{AsNative, FromIBinder, Stability, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
use crate::parcel::Parcel;
use crate::proxy::SpIBinder;
use crate::sys;

use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
use std::os::raw::{c_char, c_ulong};
use std::mem::{self, MaybeUninit};
use std::ptr;
use std::slice;

/// Super-trait for Binder parcelables.
///
/// This trait is equivalent `android::Parcelable` in C++,
/// and defines a common interface that all parcelables need
/// to implement.
pub trait Parcelable {
    /// Internal serialization function for parcelables.
    ///
    /// This method is mainly for internal use.
    /// `Serialize::serialize` and its variants are generally
    /// preferred over this function, since the former also
    /// prepend a header.
    fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()>;

    /// Internal deserialization function for parcelables.
    ///
    /// This method is mainly for internal use.
    /// `Deserialize::deserialize` and its variants are generally
    /// preferred over this function, since the former also
    /// parse the additional header.
    fn read_from_parcel(&mut self, parcel: &Parcel) -> Result<()>;
}

/// A struct whose instances can be written to a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Serialize {
@@ -162,6 +185,18 @@ unsafe extern "C" fn deserialize_element<T: Deserialize>(
    StatusCode::OK as status_t
}

/// Flag that specifies that the following parcelable is present.
///
/// This is the Rust equivalent of `Parcel::kNonNullParcelableFlag`
/// from `include/binder/Parcel.h` in C++.
pub const NON_NULL_PARCELABLE_FLAG: i32 = 1;

/// Flag that specifies that the following parcelable is absent.
///
/// This is the Rust equivalent of `Parcel::kNullParcelableFlag`
/// from `include/binder/Parcel.h` in C++.
pub const NULL_PARCELABLE_FLAG: i32 = 0;

/// Helper trait for types that can be nullable when serialized.
// We really need this trait instead of implementing `Serialize for Option<T>`
// because of the Rust orphan rule which prevents us from doing
@@ -173,10 +208,10 @@ pub trait SerializeOption: Serialize {
    /// Serialize an Option of this type into the given [`Parcel`].
    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
        if let Some(inner) = this {
            parcel.write(&1i32)?;
            parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
            parcel.write(inner)
        } else {
            parcel.write(&0i32)
            parcel.write(&NULL_PARCELABLE_FLAG)
        }
    }
}
@@ -186,7 +221,7 @@ pub trait DeserializeOption: Deserialize {
    /// Deserialize an Option of this type from the given [`Parcel`].
    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
        let null: i32 = parcel.read()?;
        if null == 0 {
        if null == NULL_PARCELABLE_FLAG {
            Ok(None)
        } else {
            parcel.read().map(Some)
@@ -608,6 +643,18 @@ impl<T: DeserializeArray> DeserializeOption for Vec<T> {
    }
}

impl Serialize for Stability {
    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
        i32::from(*self).serialize(parcel)
    }
}

impl Deserialize for Stability {
    fn deserialize(parcel: &Parcel) -> Result<Self> {
        i32::deserialize(parcel).and_then(Stability::try_from)
    }
}

impl Serialize for Status {
    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
        unsafe {
@@ -699,19 +746,53 @@ impl<T: DeserializeOption> Deserialize for Option<T> {
    }
}

/// Implement `Serialize` trait and friends for a parcelable
///
/// This is an internal macro used by the AIDL compiler to implement
/// `Serialize`, `SerializeArray` and `SerializeOption` for
/// structured parcelables. The target type must implement the
/// `Parcelable` trait.
/// ```
#[macro_export]
macro_rules! impl_serialize_for_parcelable {
    ($parcelable:ident) => {
        impl $crate::parcel::Serialize for $parcelable {
            fn serialize(
                &self,
                parcel: &mut $crate::parcel::Parcel,
            ) -> $crate::Result<()> {
                <Self as $crate::parcel::SerializeOption>::serialize_option(
                    Some(self),
                    parcel,
                )
            }
        }

        impl $crate::parcel::SerializeArray for $parcelable {}

        impl $crate::parcel::SerializeOption for $parcelable {
            fn serialize_option(
                this: Option<&Self>,
                parcel: &mut $crate::parcel::Parcel,
            ) -> $crate::Result<()> {
                if let Some(this) = this {
                    use $crate::parcel::Parcelable;
                    parcel.write(&$crate::parcel::NON_NULL_PARCELABLE_FLAG)?;
                    this.write_to_parcel(parcel)
                } else {
                    parcel.write(&$crate::parcel::NULL_PARCELABLE_FLAG)
                }
            }
        }
    }
}

/// Implement `Deserialize` trait and friends for a parcelable
///
/// This is an internal macro used by the AIDL compiler to implement
/// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
/// structured parcelables. The target type must implement a
/// `deserialize_parcelable` method with the following signature:
/// ```no_run
/// fn deserialize_parcelable(
///     &mut self,
///     parcel: &binder::parcel::Parcelable,
/// ) -> binder::Result<()> {
///     // ...
/// }
/// structured parcelables. The target type must implement the
/// `Parcelable` trait.
/// ```
#[macro_export]
macro_rules! impl_deserialize_for_parcelable {
@@ -729,10 +810,11 @@ macro_rules! impl_deserialize_for_parcelable {
                parcel: &$crate::parcel::Parcel,
            ) -> $crate::Result<()> {
                let status: i32 = parcel.read()?;
                if status == 0 {
                if status == $crate::parcel::NULL_PARCELABLE_FLAG {
                    Err($crate::StatusCode::UNEXPECTED_NULL)
                } else {
                    self.deserialize_parcelable(parcel)
                    use $crate::parcel::Parcelable;
                    self.read_from_parcel(parcel)
                }
            }
        }
@@ -752,12 +834,13 @@ macro_rules! impl_deserialize_for_parcelable {
                parcel: &$crate::parcel::Parcel,
            ) -> $crate::Result<()> {
                let status: i32 = parcel.read()?;
                if status == 0 {
                if status == $crate::parcel::NULL_PARCELABLE_FLAG {
                    *this = None;
                    Ok(())
                } else {
                    use $crate::parcel::Parcelable;
                    this.get_or_insert_with(Self::default)
                        .deserialize_parcelable(parcel)
                        .read_from_parcel(parcel)
                }
            }
        }
@@ -790,10 +873,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 {
@@ -826,7 +905,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());
@@ -846,13 +925,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());
@@ -876,7 +951,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());
Loading