Lazy bundle
Implement lazy deserialization for custom types in bundle: * Parcelable (VAL_PARCELABLE) * Serializable (VAL_SERIALIZABLE) * Parcelable array (VAL_PARCELABLEARRAY) * Lists (VAL_LIST) * Sparse array (VAL_SPARSEARRAY) * Bundle (VAL_BUNDLE) This enhances security, makes bundles more robust to deserialization errors and avoid deserializing unneeded objects in some cases*, for more details check go/lazy-bundle. To do that, we prefix those types with their length when writing them on the wire. Map serialization and deserialization now happens inside Bundle (instead of calling Parcel's readArrayMapInternal() / writeArrayMapInternal()) and we use an intermediary object - LazyValue - that holds information about the position and length of the value we will deserialize when queried. So, there are basically 3 states: 1. We received the bundle but haven't queried anything about it (not even isEmpty()): in this case the original parcel is held inside and we haven't attempted any deserialization (except for the metadata at the beginning such as the magic, etc) 2. We queried something on it (eg. isEmpty()): Now we deserialize the bundle skipping the custom values above (we're able to do this now with the length written on the wire) and instead placing LazyValue objects for them in the map. 3. We query one of the lazy values: Now, we deserialize the object represented by LazyValue and replace it on the map. Since after (2) LazyValue objects are the only ones holding references to the original Parcel, when all LazyValues are deserialized, the original Parcel is available for GC. Inside bundle now we differentiate between unparcel(itemwise = true) and unparcel(itemwise = false) where the first also deserializes each item (such that there are no LazyValues in the map). This is because some operations such as kindofEquals() need all items deserialized. I had to break a few methods in parcel into multiple methods in parcel to be able to control the format in bundle. They are all @hide. * In quick local experiments, counting the bytes that didn't need to be deserialized after the change. Roughly 10% of bytes from custom-type items in Bundle are not deserialized in the testing scenario (if I haven't messed up the stats :). That's on a sdk_gphone_x86_64_arm64 a few minutes after boot. Check https://screenshot.googleplex.com/53uXrrqDMYahzg3, stats collection is on ag/15403076. Test: atest -d android.os.cts.ParcelTest android.os.cts.BundleTest android.os.BundleTest android.os.ParcelTest Test: Boot device Bug: 195622897 Change-Id: Icfe8880cad00c3cd2afcbe4b92400ad4579e680e
Loading
Please register or sign in to comment