From 7c296d7514fe9d9f237c43b3554a2b5646035428 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Tue, 2 Nov 2021 10:41:12 +0000 Subject: [PATCH] Refactor Bundle for thread-safety of Bundle.hasFileDescriptors() After aosp/1878338, I realized Bundle.hasFileDescriptors() was accessing mParcelledData and mMap without a lock. So, to avoid locking there, I made mParcelledData volatile (since after mParcelledData is null, it can never be non-null again and mMap is guaranteed to be non-null). So, moved assignments to mParcelledData to be last wrt mMap and mParcelledByNative to ensure visibility of those fields. While refactoring copyInternal(), realized that method was always used after constructing an uninitialized Bundle, so to avoid mistakes with objects not properly initialized, I created a constructor in Bundle, PersistableBundle & BaseBundle that does that copyInternal() did. Bug: 195622897 Test: atest -d android.os.cts.ParcelTest android.os.cts.BundleTest android.os.BundleTest android.os.ParcelTest Change-Id: I5c9337496da7ecf87f10370726099dcb247a6789 --- core/java/android/os/BaseBundle.java | 100 +++++++++++--------- core/java/android/os/Bundle.java | 23 +++-- core/java/android/os/PersistableBundle.java | 15 +-- 3 files changed, 75 insertions(+), 63 deletions(-) diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 2a344f6c2b6ba..ad3de25fecc23 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -103,7 +103,7 @@ public class BaseBundle { * are unparcelled, mParcelledData willbe set to null. */ @UnsupportedAppUsage - Parcel mParcelledData = null; + volatile Parcel mParcelledData = null; /** * Whether {@link #mParcelledData} was generated by native code or not. @@ -182,13 +182,56 @@ public class BaseBundle { * @param b a Bundle to be copied. */ BaseBundle(BaseBundle b) { - copyInternal(b, false); + this(b, /* deep */ false); } /** - * Special constructor that does not initialize the bundle. + * Constructs a {@link BaseBundle} containing a copy of {@code from}. + * + * @param from The bundle to be copied. + * @param deep Whether is a deep or shallow copy. + * + * @hide */ - BaseBundle(boolean doInit) { + BaseBundle(BaseBundle from, boolean deep) { + synchronized (from) { + mClassLoader = from.mClassLoader; + + if (from.mMap != null) { + if (!deep) { + mMap = new ArrayMap<>(from.mMap); + } else { + final ArrayMap fromMap = from.mMap; + final int n = fromMap.size(); + mMap = new ArrayMap<>(n); + for (int i = 0; i < n; i++) { + mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); + } + } + } else { + mMap = null; + } + + final Parcel parcelledData; + if (from.mParcelledData != null) { + if (from.isEmptyParcel()) { + parcelledData = NoImagePreloadHolder.EMPTY_PARCEL; + mParcelledByNative = false; + } else { + parcelledData = Parcel.obtain(); + parcelledData.appendFrom(from.mParcelledData, 0, + from.mParcelledData.dataSize()); + parcelledData.setDataPosition(0); + mParcelledByNative = from.mParcelledByNative; + } + } else { + parcelledData = null; + mParcelledByNative = false; + } + + // Keep as last statement to ensure visibility of other fields + mParcelledData = parcelledData; + } } /** @@ -323,8 +366,8 @@ public class BaseBundle { } else { mMap.erase(); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; return; } @@ -358,8 +401,8 @@ public class BaseBundle { if (recycleParcel) { recycleParcel(parcelledData); } - mParcelledData = null; mParcelledByNative = false; + mParcelledData = null; } if (DEBUG) { Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this)) @@ -501,44 +544,7 @@ public class BaseBundle { mMap.clear(); } - void copyInternal(BaseBundle from, boolean deep) { - synchronized (from) { - if (from.mParcelledData != null) { - if (from.isEmptyParcel()) { - mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; - mParcelledByNative = false; - } else { - mParcelledData = Parcel.obtain(); - mParcelledData.appendFrom(from.mParcelledData, 0, - from.mParcelledData.dataSize()); - mParcelledData.setDataPosition(0); - mParcelledByNative = from.mParcelledByNative; - } - } else { - mParcelledData = null; - mParcelledByNative = false; - } - - if (from.mMap != null) { - if (!deep) { - mMap = new ArrayMap<>(from.mMap); - } else { - final ArrayMap fromMap = from.mMap; - final int N = fromMap.size(); - mMap = new ArrayMap<>(N); - for (int i = 0; i < N; i++) { - mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); - } - } - } else { - mMap = null; - } - - mClassLoader = from.mClassLoader; - } - } - - Object deepCopyValue(Object value) { + private Object deepCopyValue(Object value) { if (value == null) { return null; } @@ -570,7 +576,7 @@ public class BaseBundle { return value; } - ArrayList deepcopyArrayList(ArrayList from) { + private ArrayList deepcopyArrayList(ArrayList from) { final int N = from.size(); ArrayList out = new ArrayList(N); for (int i=0; i