Fix PersistableBundle C++ -> Java interop
PersistableBundle.java expects items to be sorted by the hash codes
of the keys, but PersistableBundle.cpp isn't compatible to it.
PersistableBundle.java now knowns what was parceled by C++
because it now uses a different magic, and change the unpercel
strategy.
Change-Id: Ia516f80b6d48dcb9f981767e0e64303434f39fb4
Fixes: 65744965
Test: adb shell sm fstrim and check logcat
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index f5a7433..0fef78d 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -40,8 +40,9 @@
private static final String TAG = "Bundle";
static final boolean DEBUG = false;
- // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
- static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ // Keep them in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
+ private static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ private static final int BUNDLE_MAGIC_NATIVE = 0x4C444E44; // 'B' 'N' 'D' 'N'
/**
* Flag indicating that this Bundle is okay to "defuse." That is, it's okay
@@ -91,6 +92,11 @@
Parcel mParcelledData = null;
/**
+ * Whether {@link #mParcelledData} was generated by native coed or not.
+ */
+ private boolean mParcelledByNative;
+
+ /**
* The ClassLoader used when unparcelling data from mParcelledData.
*/
private ClassLoader mClassLoader;
@@ -223,7 +229,7 @@
synchronized (this) {
final Parcel source = mParcelledData;
if (source != null) {
- initializeFromParcelLocked(source, /*recycleParcel=*/ true);
+ initializeFromParcelLocked(source, /*recycleParcel=*/ true, mParcelledByNative);
} else {
if (DEBUG) {
Log.d(TAG, "unparcel "
@@ -234,7 +240,8 @@
}
}
- private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel) {
+ private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
+ boolean parcelledByNative) {
if (LOG_DEFUSABLE && sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
Slog.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+ "clobber all data inside!", new Throwable());
@@ -251,6 +258,7 @@
mMap.erase();
}
mParcelledData = null;
+ mParcelledByNative = false;
return;
}
@@ -270,7 +278,15 @@
map.ensureCapacity(count);
}
try {
- parcelledData.readArrayMapInternal(map, count, mClassLoader);
+ 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);
+ }
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
@@ -284,6 +300,7 @@
recycleParcel(parcelledData);
}
mParcelledData = null;
+ mParcelledByNative = false;
}
if (DEBUG) {
Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
@@ -403,14 +420,17 @@
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) {
@@ -1538,7 +1558,7 @@
} else {
int length = mParcelledData.dataSize();
parcel.writeInt(length);
- parcel.writeInt(BUNDLE_MAGIC);
+ parcel.writeInt(mParcelledByNative ? BUNDLE_MAGIC_NATIVE : BUNDLE_MAGIC);
parcel.appendFrom(mParcelledData, 0, length);
}
return;
@@ -1585,11 +1605,14 @@
} else if (length == 0) {
// Empty Bundle or end of data.
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
+ mParcelledByNative = false;
return;
}
final int magic = parcel.readInt();
- if (magic != BUNDLE_MAGIC) {
+ final boolean isJavaBundle = magic == BUNDLE_MAGIC;
+ final boolean isNativeBundle = magic == BUNDLE_MAGIC_NATIVE;
+ if (!isJavaBundle && !isNativeBundle) {
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
@@ -1598,7 +1621,7 @@
// If the parcel has a read-write helper, then we can't lazily-unparcel it, so just
// unparcel right away.
synchronized (this) {
- initializeFromParcelLocked(parcel, /*recycleParcel=*/ false);
+ initializeFromParcelLocked(parcel, /*recycleParcel=*/ false, isNativeBundle);
}
return;
}
@@ -1616,6 +1639,7 @@
p.setDataPosition(0);
mParcelledData = p;
+ mParcelledByNative = isNativeBundle;
}
/** {@hide} */