Merge "Add range-based Parcel.compareData()"

This commit is contained in:
Bernardo Rufino 2021-11-01 11:27:05 +00:00 committed by Gerrit Code Review
commit 98a4a1b8b9
4 changed files with 166 additions and 17 deletions

View File

@ -381,6 +381,8 @@ public final class Parcel {
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
private static native boolean nativeCompareDataInRange(
long ptrA, int offsetA, long ptrB, int offsetB, int length);
private static native void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
@CriticalNative
@ -678,10 +680,15 @@ public final class Parcel {
}
/** @hide */
public final int compareData(Parcel other) {
public int compareData(Parcel other) {
return nativeCompareData(mNativePtr, other.mNativePtr);
}
/** @hide */
public static boolean compareData(Parcel a, int offsetA, Parcel b, int offsetB, int length) {
return nativeCompareDataInRange(a.mNativePtr, offsetA, b.mNativePtr, offsetB, length);
}
/** @hide */
public final void setClassCookie(Class clz, Object cookie) {
if (mClassCookies == null) {
@ -3609,7 +3616,6 @@ public final class Parcel {
private final int mType;
@Nullable private final ClassLoader mLoader;
@Nullable private Object mObject;
@Nullable private volatile Parcel mValueParcel;
/**
* This goes from non-null to null once. Always check the nullability of this object before
@ -3707,7 +3713,7 @@ public final class Parcel {
return false;
}
// Finally we compare the payload.
return getValueParcel(source).compareData(value.getValueParcel(otherSource)) == 0;
return Parcel.compareData(source, mPosition, otherSource, value.mPosition, mLength);
}
@Override
@ -3715,17 +3721,6 @@ public final class Parcel {
// Accessing mSource first to provide memory barrier for mObject
return Objects.hash(mSource == null, mObject, mLoader, mType, mLength);
}
/** This extracts the parcel section responsible for the object and returns it. */
private Parcel getValueParcel(Parcel source) {
Parcel parcel = mValueParcel;
if (parcel == null) {
parcel = Parcel.obtain();
parcel.appendFrom(source, mPosition, mLength);
mValueParcel = parcel;
}
return parcel;
}
}
/**

View File

@ -604,6 +604,25 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN
return thisParcel->compareData(*otherParcel);
}
static jboolean android_os_Parcel_compareDataInRange(JNIEnv* env, jclass clazz, jlong thisNativePtr,
jint thisOffset, jlong otherNativePtr,
jint otherOffset, jint length) {
Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
LOG_ALWAYS_FATAL_IF(thisParcel == nullptr, "Should not be null");
Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
LOG_ALWAYS_FATAL_IF(otherParcel == nullptr, "Should not be null");
int result;
status_t err =
thisParcel->compareDataInRange(thisOffset, *otherParcel, otherOffset, length, &result);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
return JNI_FALSE;
}
return (result == 0) ? JNI_TRUE : JNI_FALSE;
}
static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
jlong otherNativePtr, jint offset, jint length)
{
@ -841,6 +860,7 @@ static const JNINativeMethod gParcelMethods[] = {
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
{"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
{"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData},
{"nativeCompareDataInRange", "(JIJII)Z", (void*)android_os_Parcel_compareDataInRange},
{"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
// @CriticalNative
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},

View File

@ -273,16 +273,21 @@ public class BundleTest {
Parcelable p1 = new CustomParcelable(13, "Tiramisu");
Parcelable p2 = new CustomParcelable(13, "Tiramisu");
Bundle a = new Bundle();
a.putParcelable("key", p1);
a.putParcelable("key1", p1);
a.readFromParcel(getParcelledBundle(a));
a.setClassLoader(getClass().getClassLoader());
Bundle b = new Bundle();
b.putParcelable("key", p2);
// Adding extra element so that the position of the elements of interest in their respective
// source parcels are different so we can cover that case of Parcel.compareData(). We'll
// remove the element later so the map is equal.
b.putString("key0", "string");
b.putParcelable("key1", p2);
b.readFromParcel(getParcelledBundle(b));
b.setClassLoader(getClass().getClassLoader());
// 2 lazy values with identical parcels inside
a.isEmpty();
b.isEmpty();
b.remove("key0");
// 2 lazy values with identical parcels inside
assertTrue(Bundle.kindofEquals(a, b));
}

View File

@ -17,6 +17,9 @@
package android.os;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
@ -110,4 +113,130 @@ public class ParcelTest {
assertEquals(string, p.readString16());
}
}
@Test
public void testCompareDataInRange_whenSameData() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(13);
pA.writeString("Tiramisu");
int length = pA.dataPosition() - iA;
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeString("Tiramisu");
assertTrue(Parcel.compareData(pA, iA, pB, iB, length));
}
@Test
public void testCompareDataInRange_whenSameDataWithBinder() {
Binder binder = new Binder();
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(13);
pA.writeStrongBinder(binder);
pA.writeString("Tiramisu");
int length = pA.dataPosition() - iA;
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeStrongBinder(binder);
pB.writeString("Tiramisu");
assertTrue(Parcel.compareData(pA, iA, pB, iB, length));
}
@Test
public void testCompareDataInRange_whenDifferentData() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(13);
pA.writeString("Tiramisu");
int length = pA.dataPosition() - iA;
Parcel pB = Parcel.obtain();
int iB = pB.dataPosition();
pB.writeString("Prefix");
pB.writeInt(13);
pB.writeString("Tiramisu");
assertFalse(Parcel.compareData(pA, iA, pB, iB, length));
}
@Test
public void testCompareDataInRange_whenLimitOutOfBounds_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(12);
pA.writeString("Tiramisu");
int length = pA.dataPosition() - iA;
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeString("Tiramisu");
pB.writeInt(-1);
assertThrows(IllegalArgumentException.class,
() -> Parcel.compareData(pA, iA + length, pB, iB, 1));
assertThrows(IllegalArgumentException.class,
() -> Parcel.compareData(pA, iA, pB, pB.dataSize(), 1));
assertThrows(IllegalArgumentException.class,
() -> Parcel.compareData(pA, iA, pB, iB, length + 1));
assertThrows(IllegalArgumentException.class,
() -> Parcel.compareData(pA, iA + length + 1, pB, iB, 0));
assertThrows(IllegalArgumentException.class,
() -> Parcel.compareData(pA, iA, pB, iB + pB.dataSize() + 1, 0));
}
@Test
public void testCompareDataInRange_whenLengthZero() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(12);
pA.writeString("Tiramisu");
int length = pA.dataPosition() - iA;
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeString("Tiramisu");
assertTrue(Parcel.compareData(pA, 0, pB, iB, 0));
assertTrue(Parcel.compareData(pA, iA + length, pB, iB, 0));
assertTrue(Parcel.compareData(pA, iA, pB, pB.dataSize(), 0));
}
@Test
public void testCompareDataInRange_whenNegativeLength_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(12);
pA.writeString("Tiramisu");
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeString("Tiramisu");
assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, iA, pB, iB, -1));
}
@Test
public void testCompareDataInRange_whenNegativeOffset_throws() {
Parcel pA = Parcel.obtain();
int iA = pA.dataPosition();
pA.writeInt(12);
pA.writeString("Tiramisu");
Parcel pB = Parcel.obtain();
pB.writeString("Prefix");
int iB = pB.dataPosition();
pB.writeInt(13);
pB.writeString("Tiramisu");
assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0));
assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0));
}
}