binder_rs: Add sized_read to Parcel

Add a new Parcel::sized_read method that builds
a sized readable sub-parcel with an end position and is
used by the AIDL compiler to deserialize parcelables.

Bug: 186724059
Test: atest aidl_integration_test
Change-Id: Iba064858fe8b434e89732d437ccc304bc6cd172a
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index ef84ade..a3f7620 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -184,11 +184,17 @@
         }
     }
 
+    /// Returns the total size of the parcel.
+    pub fn get_data_size(&self) -> i32 {
+        unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
+            // and this call is otherwise safe.
+            sys::AParcel_getDataSize(self.as_native())
+        }
+    }
+
     /// Move the current read/write position in the parcel.
     ///
-    /// The new position must be a position previously returned by
-    /// `self.get_data_position()`.
-    ///
     /// # Safety
     ///
     /// This method is safe if `pos` is less than the current size of the parcel
@@ -226,6 +232,65 @@
         x.deserialize_from(self)
     }
 
+    /// Safely read a sized parcelable.
+    ///
+    /// Read the size of a parcelable, compute the end position
+    /// of that parcelable, then build a sized readable sub-parcel
+    /// and call a closure with the sub-parcel as its parameter.
+    /// The closure can keep reading data from the sub-parcel
+    /// until it runs out of input data. The closure is responsible
+    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// more data before every read, at least until Rust generators
+    /// are stabilized.
+    /// After the closure returns, skip to the end of the current
+    /// parcelable regardless of how much the closure has read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// let mut parcelable = Default::default();
+    /// parcel.sized_read(|subparcel| {
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.a = subparcel.read()?;
+    ///     }
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.b = subparcel.read()?;
+    ///     }
+    ///     Ok(())
+    /// });
+    /// ```
+    ///
+    pub fn sized_read<F>(&self, mut f: F) -> Result<()>
+    where
+        for<'a> F: FnMut(ReadableSubParcel<'a>) -> Result<()>
+    {
+        let start = self.get_data_position();
+        let parcelable_size: i32 = self.read()?;
+        if parcelable_size < 0 {
+            return Err(StatusCode::BAD_VALUE);
+        }
+
+        let end = start.checked_add(parcelable_size)
+            .ok_or(StatusCode::BAD_VALUE)?;
+        if end > self.get_data_size() {
+            return Err(StatusCode::NOT_ENOUGH_DATA);
+        }
+
+        let subparcel = ReadableSubParcel {
+            parcel: self,
+            end_position: end,
+        };
+        f(subparcel)?;
+
+        // Advance the data position to the actual end,
+        // in case the closure read less data than was available
+        unsafe {
+            self.set_data_position(end)?;
+        }
+
+        Ok(())
+    }
+
     /// Read a vector size from the `Parcel` and resize the given output vector
     /// to be correctly sized for that amount of data.
     ///
@@ -271,6 +336,27 @@
     }
 }
 
+/// A segment of a readable parcel, used for [`Parcel::sized_read`].
+pub struct ReadableSubParcel<'a> {
+    parcel: &'a Parcel,
+    end_position: i32,
+}
+
+impl<'a> ReadableSubParcel<'a> {
+    /// Read a type that implements [`Deserialize`] from the sub-parcel.
+    pub fn read<D: Deserialize>(&self) -> Result<D> {
+        // The caller should have checked this,
+        // but it can't hurt to double-check
+        assert!(self.has_more_data());
+        D::deserialize(self.parcel)
+    }
+
+    /// Check if the sub-parcel has more data to read
+    pub fn has_more_data(&self) -> bool {
+        self.parcel.get_data_position() < self.end_position
+    }
+}
+
 // Internal APIs
 impl Parcel {
     pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {