use crate::binder::Stability;
use crate::binder::StabilityType;
use crate::binder_impl::Mutex;
use crate::binder_impl::panic_if_poisoned;
use crate::error::StatusCode;
use crate::parcel::{
BorrowedParcel, Deserialize, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG, Parcel,
Parcelable, Serialize,
};
use alloc::string::String;
use alloc::sync::Arc;
use core::any::Any;
use core::fmt::Debug;
use core::marker::PhantomData;
use downcast_rs::{DowncastSync, impl_downcast};
pub trait ParcelableMetadata {
fn get_descriptor() -> &'static str;
fn get_stability(&self) -> Stability {
Stability::Local
}
}
trait AnyParcelable: DowncastSync + Parcelable + Debug {}
impl_downcast!(sync AnyParcelable);
impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + Debug {}
#[derive(Debug, Clone)]
enum ParcelableHolderData {
Empty,
Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
Parcel(Parcel),
}
#[derive(Debug)]
pub struct ParcelableHolder<STABILITY: StabilityType> {
data: Mutex<ParcelableHolderData>,
_stability_phantom: PhantomData<STABILITY>,
}
impl<STABILITY: StabilityType> ParcelableHolder<STABILITY> {
pub fn new() -> Self {
Self {
data: Mutex::new(ParcelableHolderData::Empty),
_stability_phantom: Default::default(),
}
}
pub fn reset(&mut self) {
*panic_if_poisoned!(self.data.get_mut()) = ParcelableHolderData::Empty;
}
pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<(), StatusCode>
where
T: Any + Parcelable + ParcelableMetadata + Debug + Send + Sync,
{
if STABILITY::VALUE > p.get_stability() {
return Err(StatusCode::BAD_VALUE);
}
*panic_if_poisoned!(self.data.get_mut()) =
ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
Ok(())
}
pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>, StatusCode>
where
T: Any + Parcelable + ParcelableMetadata + Default + Debug + Send + Sync,
{
let parcelable_desc = T::get_descriptor();
let mut data = panic_if_poisoned!(self.data.lock());
match *data {
ParcelableHolderData::Empty => Ok(None),
ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
if name != parcelable_desc {
return Err(StatusCode::BAD_VALUE);
}
match Arc::clone(parcelable).downcast_arc::<T>() {
Err(_) => Err(StatusCode::BAD_VALUE),
Ok(x) => Ok(Some(x)),
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
unsafe {
parcel.set_data_position(0)?;
}
let name: String = parcel.read()?;
if name != parcelable_desc {
return Ok(None);
}
let mut parcelable = T::default();
parcelable.read_from_parcel(parcel.borrowed_ref())?;
let parcelable = Arc::new(parcelable);
let result = Arc::clone(&parcelable);
*data = ParcelableHolderData::Parcelable { parcelable, name };
Ok(Some(result))
}
}
}
pub fn get_stability(&self) -> Stability {
STABILITY::VALUE
}
}
impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> {
fn default() -> Self {
Self::new()
}
}
impl<STABILITY: StabilityType> Clone for ParcelableHolder<STABILITY> {
fn clone(&self) -> Self {
ParcelableHolder {
data: Mutex::new(panic_if_poisoned!(self.data.lock()).clone()),
_stability_phantom: Default::default(),
}
}
}
impl<STABILITY: StabilityType> Serialize for ParcelableHolder<STABILITY> {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
impl<STABILITY: StabilityType> Deserialize for ParcelableHolder<STABILITY> {
type UninitType = Self;
fn uninit() -> Self::UninitType {
Self::new()
}
fn from_init(value: Self) -> Self::UninitType {
value
}
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self, StatusCode> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
Err(StatusCode::UNEXPECTED_NULL)
} else {
let mut parcelable = Self::new();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
}
}
}
impl<STABILITY: StabilityType> Parcelable for ParcelableHolder<STABILITY> {
fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
parcel.write(&STABILITY::VALUE)?;
let mut data = panic_if_poisoned!(self.data.lock());
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
let length_start = parcel.get_data_position();
parcel.write(&0i32)?;
let data_start = parcel.get_data_position();
parcel.write(name)?;
parcelable.write_to_parcel(parcel)?;
let end = parcel.get_data_position();
unsafe {
parcel.set_data_position(length_start)?;
}
assert!(end >= data_start);
parcel.write(&(end - data_start))?;
unsafe {
parcel.set_data_position(end)?;
}
Ok(())
}
ParcelableHolderData::Parcel(ref mut p) => {
parcel.write(&p.get_data_size())?;
parcel.append_all_from(&*p)
}
}
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
if self.get_stability() != parcel.read()? {
return Err(StatusCode::BAD_VALUE);
}
let data_size: i32 = parcel.read()?;
if data_size < 0 {
return Err(StatusCode::BAD_VALUE);
}
if data_size == 0 {
*panic_if_poisoned!(self.data.get_mut()) = ParcelableHolderData::Empty;
return Ok(());
}
let data_start = parcel.get_data_position();
let data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
let mut new_parcel = Parcel::new();
new_parcel.append_from(parcel, data_start, data_size)?;
*panic_if_poisoned!(self.data.get_mut()) = ParcelableHolderData::Parcel(new_parcel);
unsafe {
parcel.set_data_position(data_end)?;
}
Ok(())
}
}