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

Commit 69475346 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Fix for race in writeToParcel and unparcel

Don't access the parcelled data while it might be recycled
by another thread.

Also make a local reference of mMap, which could be modified
by another thread.

Bug: 33325384
Test: Hard to repro, so no test
Change-Id: I77f6545ac174236a3da69c0c0f3a01b2eda3f34b
parent e298756b
Loading
Loading
Loading
Loading
+58 −52
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ public class BaseBundle {
     * If the underlying data are stored as a Parcel, unparcel them
     * using the currently assigned class loader.
     */
    /* package */ synchronized void unparcel() {
    /* package */ void unparcel() {
        synchronized (this) {
            final Parcel parcelledData = mParcelledData;
            if (parcelledData == null) {
@@ -319,12 +319,14 @@ public class BaseBundle {
    }

    void copyInternal(BaseBundle from, boolean deep) {
        synchronized (from) {
            if (from.mParcelledData != null) {
                if (from.isEmptyParcel()) {
                    mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
                } else {
                    mParcelledData = Parcel.obtain();
                mParcelledData.appendFrom(from.mParcelledData, 0, from.mParcelledData.dataSize());
                    mParcelledData.appendFrom(from.mParcelledData, 0,
                            from.mParcelledData.dataSize());
                    mParcelledData.setDataPosition(0);
                }
            } else {
@@ -348,6 +350,7 @@ public class BaseBundle {

            mClassLoader = from.mClassLoader;
        }
    }

    Object deepcopyValue(Object value) {
        if (value == null) {
@@ -1441,22 +1444,26 @@ public class BaseBundle {
    void writeToParcelInner(Parcel parcel, int flags) {
        // Keep implementation in sync with writeToParcel() in
        // frameworks/native/libs/binder/PersistableBundle.cpp.
        final Parcel parcelledData;
        final ArrayMap<String, Object> map;
        synchronized (this) {
            parcelledData = mParcelledData;
        }
        if (parcelledData != null) {
            if (isEmptyParcel()) {
            // unparcel() can race with this method and cause the parcel to recycle
            // at the wrong time. So synchronize access the mParcelledData's content.
            if (mParcelledData != null) {
                if (mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL) {
                    parcel.writeInt(0);
                } else {
                int length = parcelledData.dataSize();
                    int length = mParcelledData.dataSize();
                    parcel.writeInt(length);
                    parcel.writeInt(BUNDLE_MAGIC);
                parcel.appendFrom(parcelledData, 0, length);
                    parcel.appendFrom(mParcelledData, 0, length);
                }
        } else {
                return;
            }
            map = mMap;
        }

        // Special case for empty bundles.
            if (mMap == null || mMap.size() <= 0) {
        if (map == null || map.size() <= 0) {
            parcel.writeInt(0);
            return;
        }
@@ -1465,7 +1472,7 @@ public class BaseBundle {
        parcel.writeInt(BUNDLE_MAGIC);

        int startPos = parcel.dataPosition();
            parcel.writeArrayMapInternal(mMap);
        parcel.writeArrayMapInternal(map);
        int endPos = parcel.dataPosition();

        // Backpatch length
@@ -1474,7 +1481,6 @@ public class BaseBundle {
        parcel.writeInt(length);
        parcel.setDataPosition(endPos);
    }
    }

    /**
     * Reads the Parcel contents into this Bundle, typically in order for