diff options
Diffstat (limited to 'core/java/android/os/BaseBundle.java')
| -rw-r--r-- | core/java/android/os/BaseBundle.java | 103 |
1 files changed, 75 insertions, 28 deletions
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 1692921f4a8f..6da02f5c9ff5 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -31,6 +31,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.Serializable; import java.util.ArrayList; import java.util.Set; +import java.util.function.Supplier; /** * A mapping from String keys to values of various types. In most cases, you @@ -38,7 +39,8 @@ import java.util.Set; * {@link PersistableBundle} subclass. */ public class BaseBundle { - private static final String TAG = "Bundle"; + /** @hide */ + protected static final String TAG = "Bundle"; static final boolean DEBUG = false; // Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp. @@ -95,7 +97,7 @@ public class BaseBundle { Parcel mParcelledData = null; /** - * Whether {@link #mParcelledData} was generated by native coed or not. + * Whether {@link #mParcelledData} was generated by native code or not. */ private boolean mParcelledByNative; @@ -198,7 +200,7 @@ public class BaseBundle { if (size == 0) { return null; } - Object o = mMap.valueAt(0); + Object o = getValueAt(0); try { return (String) o; } catch (ClassCastException e) { @@ -229,7 +231,12 @@ public class BaseBundle { * using the currently assigned class loader. */ @UnsupportedAppUsage - /* package */ void unparcel() { + final void unparcel() { + unparcel(/* itemwise */ false); + } + + /** Deserializes the underlying data and each item if {@code itemwise} is true. */ + final void unparcel(boolean itemwise) { synchronized (this) { final Parcel source = mParcelledData; if (source != null) { @@ -241,7 +248,40 @@ public class BaseBundle { + ": no parcelled data"); } } + if (itemwise) { + for (int i = 0, n = mMap.size(); i < n; i++) { + // Triggers deserialization of i-th item, if needed + getValueAt(i); + } + } + } + } + + /** + * Returns the value for key {@code key}. + * + * @hide + */ + final Object getValue(String key) { + int i = mMap.indexOfKey(key); + return (i >= 0) ? getValueAt(i) : null; + } + + /** + * Returns the value for a certain position in the array map. + * + * @hide + */ + final Object getValueAt(int i) { + Object object = mMap.valueAt(i); + if (object instanceof Supplier<?>) { + Supplier<?> supplier = (Supplier<?>) object; + synchronized (this) { + object = supplier.get(); + } + mMap.setValueAt(i, object); } + return object; } private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel, @@ -282,15 +322,8 @@ public class BaseBundle { map.ensureCapacity(count); } try { - if (parcelledByNative) { - // If it was parcelled by native code, then the array map keys aren't sorted - // by their hash codes, so use the safe (slow) one. - parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader); - } else { - // If parcelled by Java, we know the contents are sorted properly, - // so we can use ArrayMap.append(). - parcelledData.readArrayMapInternal(map, count, mClassLoader); - } + recycleParcel &= parcelledData.readArrayMap(map, count, !parcelledByNative, + /* lazy */ true, mClassLoader); } catch (BadParcelableException e) { if (sShouldDefuse) { Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e); @@ -342,7 +375,7 @@ public class BaseBundle { /** @hide */ ArrayMap<String, Object> getMap() { - unparcel(); + unparcel(/* itemwise */ true); return mMap; } @@ -400,7 +433,12 @@ public class BaseBundle { } /** - * @hide This kind-of does an equality comparison. Kind-of. + * Performs a loose equality check, which means there can be false negatives but if the method + * returns true than both objects are guaranteed to be equal. + * + * The point is that this method is a light-weight check in performance terms. + * + * @hide */ public boolean kindofEquals(BaseBundle other) { if (other == null) { @@ -415,6 +453,12 @@ public class BaseBundle { } else if (isParcelled()) { return mParcelledData.compareData(other.mParcelledData) == 0; } else { + // Following semantic above of failing in case we get a serialized value vs a + // deserialized one, we'll compare the map. If a certain element hasn't been + // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's + // pretend we don't know that here :P), we'll use that element's equality comparison as + // map naturally does. That will takes care of comparing the payload if needed (see + // Parcel.readLazyValue() for details). return mMap.equals(other.mMap); } } @@ -453,7 +497,7 @@ public class BaseBundle { 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))); + mMap.append(fromMap.keyAt(i), deepCopyValue(from.getValueAt(i))); } } } else { @@ -526,7 +570,7 @@ public class BaseBundle { @Nullable public Object get(String key) { unparcel(); - return mMap.get(key); + return getValue(key); } /** @@ -1001,7 +1045,7 @@ public class BaseBundle { */ char getChar(String key, char defaultValue) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return defaultValue; } @@ -1266,7 +1310,7 @@ public class BaseBundle { @Nullable Serializable getSerializable(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1289,7 +1333,7 @@ public class BaseBundle { @Nullable ArrayList<Integer> getIntegerArrayList(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1312,7 +1356,7 @@ public class BaseBundle { @Nullable ArrayList<String> getStringArrayList(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1335,7 +1379,7 @@ public class BaseBundle { @Nullable ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1404,7 +1448,7 @@ public class BaseBundle { @Nullable short[] getShortArray(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1427,7 +1471,7 @@ public class BaseBundle { @Nullable char[] getCharArray(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1496,7 +1540,7 @@ public class BaseBundle { @Nullable float[] getFloatArray(@Nullable String key) { unparcel(); - Object o = mMap.get(key); + Object o = getValue(key); if (o == null) { return null; } @@ -1585,7 +1629,7 @@ public class BaseBundle { void writeToParcelInner(Parcel parcel, int flags) { // If the parcel has a read-write helper, we can't just copy the blob, so unparcel it first. if (parcel.hasReadWriteHelper()) { - unparcel(); + unparcel(/* itemwise */ true); } // Keep implementation in sync with writeToParcel() in // frameworks/native/libs/binder/PersistableBundle.cpp. @@ -1660,10 +1704,13 @@ public class BaseBundle { } if (parcel.hasReadWriteHelper()) { - // If the parcel has a read-write helper, then we can't lazily-unparcel it, so just - // unparcel right away. + // If the parcel has a read-write helper, it's better to deserialize immediately + // otherwise the helper would have to either maintain valid state long after the bundle + // had been constructed with parcel or to make sure they trigger deserialization of the + // bundle immediately; neither of which is obvious. synchronized (this) { initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle); + unparcel(/* itemwise */ true); } return; } |
