use crate::binder::Stability;
use crate::error::{Result, StatusCode};
use crate::{
Deserialize, Parcel, Parcelable, ParcelableMetadata, Serialize, NON_NULL_PARCELABLE_FLAG,
NULL_PARCELABLE_FLAG,
};
use std::any::Any;
use std::sync::{Arc, Mutex};
trait AnyParcelable: Parcelable + std::fmt::Debug + Send + Sync + 'static {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
impl<T: Parcelable + std::fmt::Debug + Send + Sync + 'static> AnyParcelable for T {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
}
#[derive(Debug)]
enum ParcelableHolderData {
Empty,
Parcelable {
parcelable: Arc<dyn AnyParcelable>,
name: String,
},
Parcel(Parcel),
}
#[derive(Debug)]
pub struct ParcelableHolder {
data: Mutex<ParcelableHolderData>,
stability: Stability,
}
impl Default for ParcelableHolder {
fn default() -> Self {
Self::new(Stability::Local)
}
}
impl ParcelableHolder {
pub fn new(stability: Stability) -> Self {
Self {
data: Mutex::new(ParcelableHolderData::Empty),
stability,
}
}
pub fn reset(&mut self) {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
}
pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
if !p.stability().includes(self.stability) {
log::error!(
"ParcelableHolder::set_parcelable: parcelable stability {:?} does not include holder stability {:?}",
p.stability(),
self.stability
);
return Err(StatusCode::BadValue);
}
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Parcelable {
parcelable: p,
name: T::descriptor().into(),
};
Ok(())
}
pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
where
T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
{
let parcelable_desc = T::descriptor();
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => Ok(None),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
if name != parcelable_desc {
log::error!(
"ParcelableHolder::get_parcelable: parcelable descriptor mismatch: {name:?} != {parcelable_desc:?}");
return Err(StatusCode::BadValue);
}
match Arc::clone(parcelable).into_any_arc().downcast::<T>() {
Err(_) => {
log::error!("ParcelableHolder::get_parcelable: parcelable type mismatch: {parcelable:?} != {parcelable_desc:?}");
Err(StatusCode::BadValue)
}
Ok(x) => Ok(Some(x)),
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
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)?;
let parcelable = Arc::new(parcelable);
let result = Arc::clone(&parcelable);
*data = ParcelableHolderData::Parcelable { parcelable, name };
Ok(Some(result))
}
}
}
pub fn get_stability(&self) -> Stability {
self.stability
}
}
impl Serialize for ParcelableHolder {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
impl Deserialize for ParcelableHolder {
fn deserialize(parcel: &mut Parcel) -> Result<Self> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
log::error!("ParcelableHolder::deserialize: unexpected null");
Err(StatusCode::UnexpectedNull)
} else if status == NON_NULL_PARCELABLE_FLAG {
let mut parcelable = ParcelableHolder::default();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
} else {
Err(StatusCode::UnexpectedNull)
}
}
fn deserialize_from(&mut self, parcel: &mut Parcel) -> Result<()> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
log::error!("ParcelableHolder::deserialize_from: unexpected null");
Err(StatusCode::UnexpectedNull)
} else if status == NON_NULL_PARCELABLE_FLAG {
self.read_from_parcel(parcel)
} else {
Err(StatusCode::UnexpectedNull)
}
}
}
fn parcelable_stability_repr(stability: Stability) -> i32 {
match stability {
Stability::Vintf => 1, _ => 0, }
}
impl Parcelable for ParcelableHolder {
fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
let stability = parcelable_stability_repr(self.stability);
parcel.write(&stability)?;
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
let length_start = parcel.data_position();
parcel.write(&0i32)?;
let data_start = parcel.data_position();
parcel.write(name)?;
parcelable.write_to_parcel(parcel)?;
let end = parcel.data_position();
parcel.set_data_position(length_start);
assert!(end >= data_start);
parcel.write(&((end - data_start) as i32))?;
parcel.set_data_position(end);
Ok(())
}
ParcelableHolderData::Parcel(ref mut p) => {
parcel.write(&(p.data_size() as i32))?;
parcel.append_all_from(p)
}
}
}
fn read_from_parcel(&mut self, parcel: &mut Parcel) -> Result<()> {
let wire_stability: i32 = parcel.read()?;
let local_stability = parcelable_stability_repr(self.stability);
if local_stability != wire_stability {
log::error!(
"ParcelableHolder::read_from_parcel: parcelable stability mismatch: {:?} != {:?}",
self.stability,
wire_stability
);
return Err(StatusCode::BadValue);
}
let data_size: i32 = parcel.read()?;
if data_size < 0 {
return Err(StatusCode::BadValue);
}
if data_size == 0 {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
return Ok(());
}
let data_start: usize = parcel.data_position();
let data_end: usize = data_start
.checked_add(data_size as usize)
.ok_or(StatusCode::BadValue)?;
let mut new_parcel = Parcel::new();
new_parcel.append_from(parcel, data_start, data_size as usize)?;
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Parcel(new_parcel);
parcel.set_data_position(data_end);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn holder_serializes_parcelable_stability_not_binder_level_bitmask() {
let vintf = ParcelableHolder::new(Stability::Vintf);
let mut vp = Parcel::new();
vintf.write_to_parcel(&mut vp).unwrap();
vp.set_data_position(0);
let vintf_wire: i32 = vp.read().unwrap();
assert_eq!(
vintf_wire, 1,
"Vintf holder must serialize as STABILITY_VINTF (1)"
);
let local = ParcelableHolder::default();
let mut lp = Parcel::new();
local.write_to_parcel(&mut lp).unwrap();
lp.set_data_position(0);
let local_wire: i32 = lp.read().unwrap();
assert_eq!(
local_wire, 0,
"Local holder must serialize as STABILITY_LOCAL (0)"
);
vp.set_data_position(0);
let mut dst = ParcelableHolder::new(Stability::Vintf);
dst.read_from_parcel(&mut vp).unwrap();
vp.set_data_position(0);
let mut local_dst = ParcelableHolder::default();
assert!(matches!(
local_dst.read_from_parcel(&mut vp),
Err(StatusCode::BadValue)
));
}
#[test]
fn holder_rejects_null_and_garbage_sentinels() {
for status in [NULL_PARCELABLE_FLAG, 2, -1] {
let mut p = Parcel::new();
p.write(&status).unwrap();
p.set_data_position(0);
assert!(
matches!(
ParcelableHolder::deserialize(&mut p),
Err(StatusCode::UnexpectedNull)
),
"status {status} must be rejected as UnexpectedNull",
);
}
}
}