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

Commit 13e1cbb3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Revert^2 "[binder] Expose public Rust API at crate top level"" am: 8ed347f6

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

Change-Id: I17b1e26e4d93eb0f37c6bacb2dca6b70c760e786
parents 5d9a8200 8ed347f6
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -28,8 +28,8 @@
//!
//! [`Tokio`]: crate::Tokio

use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
use binder::{FromIBinder, StatusCode, BinderAsyncRuntime};
use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
use binder::binder_impl::BinderAsyncRuntime;
use std::future::Future;

/// Retrieve an existing service for a particular interface, sleeping for a few
@@ -37,12 +37,12 @@ use std::future::Future;
pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
    if binder::is_handling_transaction() {
        // See comment in the BinderAsyncPool impl.
        return binder::public_api::get_interface::<T>(name);
        return binder::get_interface::<T>(name);
    }

    let name = name.to_string();
    let res = tokio::task::spawn_blocking(move || {
        binder::public_api::get_interface::<T>(&name)
        binder::get_interface::<T>(&name)
    }).await;

    // The `is_panic` branch is not actually reachable in Android as we compile
@@ -61,12 +61,12 @@ pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Res
pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
    if binder::is_handling_transaction() {
        // See comment in the BinderAsyncPool impl.
        return binder::public_api::wait_for_interface::<T>(name);
        return binder::wait_for_interface::<T>(name);
    }

    let name = name.to_string();
    let res = tokio::task::spawn_blocking(move || {
        binder::public_api::wait_for_interface::<T>(&name)
        binder::wait_for_interface::<T>(&name)
    }).await;

    // The `is_panic` branch is not actually reachable in Android as we compile
+53 −53
Original line number Diff line number Diff line
@@ -536,13 +536,13 @@ impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}
/// ```
macro_rules! binder_fn_get_class {
    ($class:ty) => {
        binder_fn_get_class!($crate::InterfaceClass::new::<$class>());
        binder_fn_get_class!($crate::binder_impl::InterfaceClass::new::<$class>());
    };

    ($constructor:expr) => {
        fn get_class() -> $crate::InterfaceClass {
        fn get_class() -> $crate::binder_impl::InterfaceClass {
            static CLASS_INIT: std::sync::Once = std::sync::Once::new();
            static mut CLASS: Option<$crate::InterfaceClass> = None;
            static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;

            CLASS_INIT.call_once(|| unsafe {
                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
@@ -772,7 +772,7 @@ macro_rules! declare_binder_interface {
                native: $native($on_transact),
                proxy: $proxy {},
                $(async: $async_interface,)?
                stability: $crate::Stability::default(),
                stability: $crate::binder_impl::Stability::default(),
            }
        }
    };
@@ -811,7 +811,7 @@ macro_rules! declare_binder_interface {
                    $($fname: $fty = $finit),*
                },
                $(async: $async_interface,)?
                stability: $crate::Stability::default(),
                stability: $crate::binder_impl::Stability::default(),
            }
        }
    };
@@ -828,9 +828,9 @@ macro_rules! declare_binder_interface {
    } => {
        $crate::declare_binder_interface! {
            $interface[$descriptor] {
                @doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
                @doc[concat!("A binder [`Remotable`]($crate::binder_impl::Remotable) that holds an [`", stringify!($interface), "`] object.")]
                native: $native($on_transact),
                @doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
                @doc[concat!("A binder [`Proxy`]($crate::binder_impl::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
                proxy: $proxy {
                    $($fname: $fty = $finit),*
                },
@@ -867,7 +867,7 @@ macro_rules! declare_binder_interface {
            }
        }

        impl $crate::Proxy for $proxy
        impl $crate::binder_impl::Proxy for $proxy
        where
            $proxy: $interface,
        {
@@ -875,7 +875,7 @@ macro_rules! declare_binder_interface {
                $descriptor
            }

            fn from_binder(mut binder: $crate::SpIBinder) -> $crate::Result<Self> {
            fn from_binder(mut binder: $crate::SpIBinder) -> std::result::Result<Self, $crate::StatusCode> {
                Ok(Self { binder, $($fname: $finit),* })
            }
        }
@@ -887,19 +887,19 @@ macro_rules! declare_binder_interface {
        impl $native {
            /// Create a new binder service.
            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
                let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
                let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability);
                #[cfg(not(android_vndk))]
                $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
                $crate::binder_impl::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
                $crate::Strong::new(Box::new(binder))
            }
        }

        impl $crate::Remotable for $native {
        impl $crate::binder_impl::Remotable for $native {
            fn get_descriptor() -> &'static str {
                $descriptor
            }

            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::BorrowedParcel<'_>, reply: &mut $crate::BorrowedParcel<'_>) -> $crate::Result<()> {
            fn on_transact(&self, code: $crate::binder_impl::TransactionCode, data: &$crate::binder_impl::BorrowedParcel<'_>, reply: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                match $on_transact(&*self.0, code, data, reply) {
                    // The C++ backend converts UNEXPECTED_NULL into an exception
                    Err($crate::StatusCode::UNEXPECTED_NULL) => {
@@ -913,19 +913,19 @@ macro_rules! declare_binder_interface {
                }
            }

            fn on_dump(&self, file: &std::fs::File, args: &[&std::ffi::CStr]) -> $crate::Result<()> {
            fn on_dump(&self, file: &std::fs::File, args: &[&std::ffi::CStr]) -> std::result::Result<(), $crate::StatusCode> {
                self.0.dump(file, args)
            }

            fn get_class() -> $crate::InterfaceClass {
            fn get_class() -> $crate::binder_impl::InterfaceClass {
                static CLASS_INIT: std::sync::Once = std::sync::Once::new();
                static mut CLASS: Option<$crate::InterfaceClass> = None;
                static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;

                CLASS_INIT.call_once(|| unsafe {
                    // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
                    // variable, and therefore is thread-safe, as it can only occur
                    // once.
                    CLASS = Some($crate::InterfaceClass::new::<$crate::Binder<$native>>());
                    CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
                });
                unsafe {
                    // Safety: The `CLASS` variable can only be mutated once, above,
@@ -936,25 +936,25 @@ macro_rules! declare_binder_interface {
        }

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

                let existing_class = ibinder.get_class();
                if let Some(class) = existing_class {
                    if class != <$native as $crate::Remotable>::get_class() &&
                        class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
                    if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
                        class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
                    {
                        // The binder object's descriptor string matches what we
                        // expect. We still need to treat this local or already
                        // associated object as remote, because we can't cast it
                        // into a Rust service object without a matching class
                        // pointer.
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
                    }
                }

                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
                    let service: $crate::Result<$crate::Binder<$native>> =
                if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
                    let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
                        std::convert::TryFrom::try_from(ibinder.clone());
                    if let Ok(service) = service {
                        // We were able to associate with our expected class and
@@ -962,7 +962,7 @@ macro_rules! declare_binder_interface {
                        return Ok($crate::Strong::new(Box::new(service)));
                    } else {
                        // Service is remote
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
                    }
                }

@@ -970,18 +970,18 @@ macro_rules! declare_binder_interface {
            }
        }

        impl $crate::parcel::Serialize for dyn $interface + '_
        impl $crate::binder_impl::Serialize for dyn $interface + '_
        where
            dyn $interface: $crate::Interface
        {
            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
            fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                let binder = $crate::Interface::as_binder(self);
                parcel.write(&binder)
            }
        }

        impl $crate::parcel::SerializeOption for dyn $interface + '_ {
            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
        impl $crate::binder_impl::SerializeOption for dyn $interface + '_ {
            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                parcel.write(&this.map($crate::Interface::as_binder))
            }
        }
@@ -1004,25 +1004,25 @@ macro_rules! declare_binder_interface {
        $(
        // Async interface trait implementations.
        impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $async_interface<P>>> {
                use $crate::AssociateClass;
            fn try_from(mut ibinder: $crate::SpIBinder) -> std::result::Result<$crate::Strong<dyn $async_interface<P>>, $crate::StatusCode> {
                use $crate::binder_impl::AssociateClass;

                let existing_class = ibinder.get_class();
                if let Some(class) = existing_class {
                    if class != <$native as $crate::Remotable>::get_class() &&
                        class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
                    if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
                        class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
                    {
                        // The binder object's descriptor string matches what we
                        // expect. We still need to treat this local or already
                        // associated object as remote, because we can't cast it
                        // into a Rust service object without a matching class
                        // pointer.
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
                    }
                }

                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
                    let service: $crate::Result<$crate::Binder<$native>> =
                if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
                    let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
                        std::convert::TryFrom::try_from(ibinder.clone());
                    if let Ok(service) = service {
                        // We were able to associate with our expected class and
@@ -1031,7 +1031,7 @@ macro_rules! declare_binder_interface {
                        //return Ok($crate::Strong::new(Box::new(service)));
                    } else {
                        // Service is remote
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
                    }
                }

@@ -1039,15 +1039,15 @@ macro_rules! declare_binder_interface {
            }
        }

        impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
        impl<P: $crate::BinderAsyncPool> $crate::binder_impl::Serialize for dyn $async_interface<P> + '_ {
            fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                let binder = $crate::Interface::as_binder(self);
                parcel.write(&binder)
            }
        }

        impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
        impl<P: $crate::BinderAsyncPool> $crate::binder_impl::SerializeOption for dyn $async_interface<P> + '_ {
            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                parcel.write(&this.map($crate::Interface::as_binder))
            }
        }
@@ -1067,11 +1067,11 @@ macro_rules! declare_binder_interface {
            }
        }

        impl<P: $crate::BinderAsyncPool> $crate::ToAsyncInterface<P> for dyn $interface {
        impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToAsyncInterface<P> for dyn $interface {
            type Target = dyn $async_interface<P>;
        }

        impl<P: $crate::BinderAsyncPool> $crate::ToSyncInterface for dyn $async_interface<P> {
        impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToSyncInterface for dyn $async_interface<P> {
            type Target = dyn $interface;
        }
        )?
@@ -1103,29 +1103,29 @@ macro_rules! declare_binder_enum {
            }
        }

        impl $crate::parcel::Serialize for $enum {
            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
        impl $crate::binder_impl::Serialize for $enum {
            fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                parcel.write(&self.0)
            }
        }

        impl $crate::parcel::SerializeArray for $enum {
            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
        impl $crate::binder_impl::SerializeArray for $enum {
            fn serialize_array(slice: &[Self], parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
                let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
                <$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
                <$backing as $crate::binder_impl::SerializeArray>::serialize_array(&v[..], parcel)
            }
        }

        impl $crate::parcel::Deserialize for $enum {
            fn deserialize(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Self> {
        impl $crate::binder_impl::Deserialize for $enum {
            fn deserialize(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Self, $crate::StatusCode> {
                parcel.read().map(Self)
            }
        }

        impl $crate::parcel::DeserializeArray for $enum {
            fn deserialize_array(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Option<Vec<Self>>> {
        impl $crate::binder_impl::DeserializeArray for $enum {
            fn deserialize_array(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Option<Vec<Self>>, $crate::StatusCode> {
                let v: Option<Vec<$backing>> =
                    <$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
                    <$backing as $crate::binder_impl::DeserializeArray>::deserialize_array(parcel)?;
                Ok(v.map(|v| v.into_iter().map(Self).collect()))
            }
        }
+34 −29
Original line number Diff line number Diff line
@@ -101,45 +101,50 @@ mod binder;
mod binder_async;
mod error;
mod native;
mod parcel;
mod state;

use binder_ndk_sys as sys;

pub mod parcel;
pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
pub use error::{ExceptionCode, Status, StatusCode};
pub use native::{
    add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{
    get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
    WpIBinder,
};
pub use state::{ProcessState, ThreadState};

/// Binder result containing a [`Status`] on error.
pub type Result<T> = std::result::Result<T, Status>;

/// Advanced Binder APIs needed internally by AIDL or when manually using Binder
/// without AIDL.
pub mod binder_impl {
    pub use crate::binder::{
    BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
    Stability, Strong, ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, Weak,
    FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
        IBinderInternal, InterfaceClass, Remotable, Stability, ToAsyncInterface, ToSyncInterface,
        TransactionCode, TransactionFlags, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
        FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
    };
pub use crate::binder_async::{BoxFuture, BinderAsyncPool, BinderAsyncRuntime};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::{add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, Binder};
pub use parcel::{BorrowedParcel, 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};
    pub use crate::binder_async::BinderAsyncRuntime;
    pub use crate::error::status_t;
    pub use crate::native::Binder;
    pub use crate::parcel::{
        BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel,
        ParcelableMetadata, Serialize, SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG,
        NULL_PARCELABLE_FLAG,
    };
    pub use crate::proxy::{AssociateClass, Proxy};
}

/// Unstable, in-development API that only allowlisted clients are allowed to use.
#[doc(hidden)]
pub mod unstable_api {
    pub use crate::binder::AsNative;
    pub use crate::proxy::unstable_api::new_spibinder;
    pub use crate::sys::AIBinder;
}

/// The public API usable outside AIDL-generated interface crates.
pub mod public_api {
    pub use super::parcel::{ParcelFileDescriptor, ParcelableHolder};
    pub use super::{
        add_service, force_lazy_services_persist, get_interface, register_lazy_service,
        wait_for_interface,
    };
    pub use super::{
        BinderAsyncPool, BinderFeatures, BoxFuture, DeathRecipient, ExceptionCode, IBinder,
        Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState, Weak,
        WpIBinder,
    };

    /// Binder result containing a [`Status`] on error.
    pub type Result<T> = std::result::Result<T, Status>;
}
+30 −33

File changed.

Preview size limit exceeded, changes collapsed.

+6 −6
Original line number Diff line number Diff line
@@ -15,8 +15,8 @@
 */

use crate::binder::Stability;
use crate::error::{Result, StatusCode};
use crate::parcel::{Parcel, BorrowedParcel, Parcelable};
use crate::error::StatusCode;
use crate::parcel::{BorrowedParcel, Parcel, Parcelable};
use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};

use downcast_rs::{impl_downcast, DowncastSync};
@@ -97,7 +97,7 @@ impl ParcelableHolder {
    }

    /// Set the parcelable contained in this `ParcelableHolder`.
    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<(), StatusCode>
    where
        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
    {
@@ -126,7 +126,7 @@ impl ParcelableHolder {
    /// * `Ok(None)` if the holder is empty or the descriptor does not match
    /// * `Ok(Some(_))` if the object holds a parcelable of type `T`
    ///   with the correct descriptor
    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>, StatusCode>
    where
        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
    {
@@ -180,7 +180,7 @@ impl_serialize_for_parcelable!(ParcelableHolder);
impl_deserialize_for_parcelable!(ParcelableHolder);

impl Parcelable for ParcelableHolder {
    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
        parcel.write(&self.stability)?;

        let mut data = self.data.lock().unwrap();
@@ -219,7 +219,7 @@ impl Parcelable for ParcelableHolder {
        }
    }

    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
        self.stability = parcel.read()?;

        let data_size: i32 = parcel.read()?;
Loading