binder/parcel/
parcelable_holder.rs

1/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::binder::Stability;
18use crate::binder::StabilityType;
19use crate::error::StatusCode;
20use crate::parcel::{
21    BorrowedParcel, Deserialize, Parcel, Parcelable, Serialize, NON_NULL_PARCELABLE_FLAG,
22    NULL_PARCELABLE_FLAG,
23};
24
25use downcast_rs::{impl_downcast, DowncastSync};
26use std::any::Any;
27use std::sync::{Arc, Mutex};
28
29/// Metadata that `ParcelableHolder` needs for all parcelables.
30///
31/// The compiler auto-generates implementations of this trait
32/// for AIDL parcelables.
33pub trait ParcelableMetadata {
34    /// The Binder parcelable descriptor string.
35    ///
36    /// This string is a unique identifier for a Binder parcelable.
37    fn get_descriptor() -> &'static str;
38
39    /// The Binder parcelable stability.
40    fn get_stability(&self) -> Stability {
41        Stability::Local
42    }
43}
44
45trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
46impl_downcast!(sync AnyParcelable);
47impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
48
49#[derive(Debug, Clone)]
50enum ParcelableHolderData {
51    Empty,
52    Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
53    Parcel(Parcel),
54}
55
56/// A container that can hold any arbitrary `Parcelable`.
57///
58/// This type is currently used for AIDL parcelable fields.
59///
60/// `ParcelableHolder` is currently not thread-safe (neither
61/// `Send` nor `Sync`), mainly because it internally contains
62/// a `Parcel` which in turn is not thread-safe.
63#[derive(Debug)]
64pub struct ParcelableHolder<STABILITY: StabilityType> {
65    // This is a `Mutex` because of `get_parcelable`
66    // which takes `&self` for consistency with C++.
67    // We could make `get_parcelable` take a `&mut self`
68    // and get rid of the `Mutex` here for a performance
69    // improvement, but then callers would require a mutable
70    // `ParcelableHolder` even for that getter method.
71    data: Mutex<ParcelableHolderData>,
72
73    _stability_phantom: std::marker::PhantomData<STABILITY>,
74}
75
76impl<STABILITY: StabilityType> ParcelableHolder<STABILITY> {
77    /// Construct a new `ParcelableHolder` with the given stability.
78    pub fn new() -> Self {
79        Self {
80            data: Mutex::new(ParcelableHolderData::Empty),
81            _stability_phantom: Default::default(),
82        }
83    }
84
85    /// Reset the contents of this `ParcelableHolder`.
86    ///
87    /// Note that this method does not reset the stability,
88    /// only the contents.
89    pub fn reset(&mut self) {
90        *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
91        // We could also clear stability here, but C++ doesn't
92    }
93
94    /// Set the parcelable contained in this `ParcelableHolder`.
95    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<(), StatusCode>
96    where
97        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
98    {
99        if STABILITY::VALUE > p.get_stability() {
100            return Err(StatusCode::BAD_VALUE);
101        }
102
103        *self.data.get_mut().unwrap() =
104            ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
105
106        Ok(())
107    }
108
109    /// Retrieve the parcelable stored in this `ParcelableHolder`.
110    ///
111    /// This method attempts to retrieve the parcelable inside
112    /// the current object as a parcelable of type `T`.
113    /// The object is validated against `T` by checking that
114    /// its parcelable descriptor matches the one returned
115    /// by `T::get_descriptor()`.
116    ///
117    /// Returns one of the following:
118    /// * `Err(_)` in case of error
119    /// * `Ok(None)` if the holder is empty or the descriptor does not match
120    /// * `Ok(Some(_))` if the object holds a parcelable of type `T`
121    ///   with the correct descriptor
122    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>, StatusCode>
123    where
124        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
125    {
126        let parcelable_desc = T::get_descriptor();
127        let mut data = self.data.lock().unwrap();
128        match *data {
129            ParcelableHolderData::Empty => Ok(None),
130            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
131                if name != parcelable_desc {
132                    return Err(StatusCode::BAD_VALUE);
133                }
134
135                match Arc::clone(parcelable).downcast_arc::<T>() {
136                    Err(_) => Err(StatusCode::BAD_VALUE),
137                    Ok(x) => Ok(Some(x)),
138                }
139            }
140            ParcelableHolderData::Parcel(ref mut parcel) => {
141                // Safety: 0 should always be a valid position.
142                unsafe {
143                    parcel.set_data_position(0)?;
144                }
145
146                let name: String = parcel.read()?;
147                if name != parcelable_desc {
148                    return Ok(None);
149                }
150
151                let mut parcelable = T::default();
152                parcelable.read_from_parcel(parcel.borrowed_ref())?;
153
154                let parcelable = Arc::new(parcelable);
155                let result = Arc::clone(&parcelable);
156                *data = ParcelableHolderData::Parcelable { parcelable, name };
157
158                Ok(Some(result))
159            }
160        }
161    }
162
163    /// Return the stability value of this object.
164    pub fn get_stability(&self) -> Stability {
165        STABILITY::VALUE
166    }
167}
168
169impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175impl<STABILITY: StabilityType> Clone for ParcelableHolder<STABILITY> {
176    fn clone(&self) -> Self {
177        ParcelableHolder {
178            data: Mutex::new(self.data.lock().unwrap().clone()),
179            _stability_phantom: Default::default(),
180        }
181    }
182}
183
184impl<STABILITY: StabilityType> Serialize for ParcelableHolder<STABILITY> {
185    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
186        parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
187        self.write_to_parcel(parcel)
188    }
189}
190
191impl<STABILITY: StabilityType> Deserialize for ParcelableHolder<STABILITY> {
192    type UninitType = Self;
193    fn uninit() -> Self::UninitType {
194        Self::new()
195    }
196    fn from_init(value: Self) -> Self::UninitType {
197        value
198    }
199
200    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self, StatusCode> {
201        let status: i32 = parcel.read()?;
202        if status == NULL_PARCELABLE_FLAG {
203            Err(StatusCode::UNEXPECTED_NULL)
204        } else {
205            let mut parcelable = Self::new();
206            parcelable.read_from_parcel(parcel)?;
207            Ok(parcelable)
208        }
209    }
210}
211
212impl<STABILITY: StabilityType> Parcelable for ParcelableHolder<STABILITY> {
213    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
214        parcel.write(&STABILITY::VALUE)?;
215
216        let mut data = self.data.lock().unwrap();
217        match *data {
218            ParcelableHolderData::Empty => parcel.write(&0i32),
219            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
220                let length_start = parcel.get_data_position();
221                parcel.write(&0i32)?;
222
223                let data_start = parcel.get_data_position();
224                parcel.write(name)?;
225                parcelable.write_to_parcel(parcel)?;
226
227                let end = parcel.get_data_position();
228                // Safety: we got the position from `get_data_position`.
229                unsafe {
230                    parcel.set_data_position(length_start)?;
231                }
232
233                assert!(end >= data_start);
234                parcel.write(&(end - data_start))?;
235                // Safety: we got the position from `get_data_position`.
236                unsafe {
237                    parcel.set_data_position(end)?;
238                }
239
240                Ok(())
241            }
242            ParcelableHolderData::Parcel(ref mut p) => {
243                parcel.write(&p.get_data_size())?;
244                parcel.append_all_from(&*p)
245            }
246        }
247    }
248
249    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
250        if self.get_stability() != parcel.read()? {
251            return Err(StatusCode::BAD_VALUE);
252        }
253
254        let data_size: i32 = parcel.read()?;
255        if data_size < 0 {
256            // C++ returns BAD_VALUE here,
257            // while Java returns ILLEGAL_ARGUMENT
258            return Err(StatusCode::BAD_VALUE);
259        }
260        if data_size == 0 {
261            *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
262            return Ok(());
263        }
264
265        // TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
266        // only go up to i32::MAX because that's what our API uses everywhere
267        let data_start = parcel.get_data_position();
268        let data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
269
270        let mut new_parcel = Parcel::new();
271        new_parcel.append_from(parcel, data_start, data_size)?;
272        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
273
274        // Safety: `append_from` checks if `data_size` overflows
275        // `parcel` and returns `BAD_VALUE` if that happens. We also
276        // explicitly check for negative and zero `data_size` above,
277        // so `data_end` is guaranteed to be greater than `data_start`.
278        unsafe {
279            parcel.set_data_position(data_end)?;
280        }
281
282        Ok(())
283    }
284}