Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1aae7207 authored by Hani Kazmi's avatar Hani Kazmi Committed by Android Build Coastguard Worker
Browse files

Update BaseBundle to not use LazyValues when using ReadWriteHelper

This is a partial backport of ag/19532036. It fixes a bug where a
LazyValue might have been pointing to a parcel which was already
recycled.

Bug: 240138318
Test: atest android.os.cts.ParcelTest android.os.cts.BundleTest
android.os.BundleTest android.os.ParcelTest
android.os.BundleRecylingTest
Test: Running PoC app from linked bug

Change-Id: I3acf7127fdf373ee8b38a55702ae315be499601c
Merged-In: I8a878a6d0055b04b2611909b4b17977ba5677a4f
(cherry picked from commit d2f9cc63)
Merged-In: I3acf7127fdf373ee8b38a55702ae315be499601c
parent 7b9ea7a7
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -438,8 +438,11 @@ public class BaseBundle {
            map.ensureCapacity(count);
        }
        try {
            // recycleParcel being false implies that we do not own the parcel. In this case, do
            // not use lazy values to be safe, as the parcel could be recycled outside of our
            // control.
            recycleParcel &= parcelledData.readArrayMap(map, count, !parcelledByNative,
                    /* lazy */ true, mClassLoader);
                    /* lazy */ recycleParcel, mClassLoader);
        } catch (BadParcelableException e) {
            if (sShouldDefuse) {
                Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
@@ -1845,7 +1848,6 @@ public class BaseBundle {
            // bundle immediately; neither of which is obvious.
            synchronized (this) {
                initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle);
                unparcel(/* itemwise */ true);
            }
            return;
        }
+63 −0
Original line number Diff line number Diff line
@@ -408,6 +408,69 @@ public class BundleTest {
        assertThat(bundle.<Parcelable>getParcelable("key")).isEqualTo(parcelable);
    }

    @Test
    public void readFromParcel_withLazyValues_copiesUnderlyingParcel() {
        Bundle bundle = new Bundle();
        Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
        bundle.putParcelable("key", parcelable);
        bundle.putString("string", "value");
        Parcel parcelledBundle = getParcelledBundle(bundle);

        Bundle testBundle = new Bundle();
        testBundle.setClassLoader(getClass().getClassLoader());
        testBundle.readFromParcel(parcelledBundle);
        // Recycle the parcel as it should have been copied
        parcelledBundle.recycle();
        assertThat(testBundle.getString("string")).isEqualTo("value");
        assertThat(testBundle.<Parcelable>getParcelable("key")).isEqualTo(parcelable);
    }

    @Test
    public void readFromParcelWithRwHelper_whenThrowingAndNotDefusing_throws() {
        Bundle bundle = new Bundle();
        Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
        bundle.putParcelable("key", parcelable);
        bundle.putString("string", "value");
        Parcel parcelledBundle = getParcelledBundle(bundle);
        parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());

        Bundle testBundle = new Bundle();
        assertThrows(BadParcelableException.class,
                () -> testBundle.readFromParcel(parcelledBundle));
    }

    @Test
    public void readFromParcelWithRwHelper_whenThrowingAndDefusing_returnsNull() {
        Bundle bundle = new Bundle();
        Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
        bundle.putParcelable("key", parcelable);
        bundle.putString("string", "value");
        Parcel parcelledBundle = getParcelledBundle(bundle);
        parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());

        Bundle.setShouldDefuse(true);
        Bundle testBundle = new Bundle();
        testBundle.readFromParcel(parcelledBundle);
        // Recycle the parcel as it should not be referenced
        parcelledBundle.recycle();
        assertThat(testBundle.getString("string")).isNull();
        assertThat(testBundle.<Parcelable>getParcelable("key")).isNull();
    }

    @Test
    public void readFromParcelWithRwHelper_withoutLazyObject_returnsValue() {
        Bundle bundle = new Bundle();
        bundle.putString("string", "value");
        Parcel parcelledBundle = getParcelledBundle(bundle);
        parcelledBundle.setReadWriteHelper(new Parcel.ReadWriteHelper());

        Bundle testBundle = new Bundle();
        testBundle.readFromParcel(parcelledBundle);
        // Recycle the parcel as it should not be referenced
        parcelledBundle.recycle();
        assertThat(testBundle.getString("string")).isEqualTo("value");
    }

    @Test
    public void partialDeserialization_whenNotDefusing_throws() throws Exception {
        Bundle.setShouldDefuse(false);