Adding tests for OOM fix

Renaming method isDirectlyHandlingTransaction to
isDirectlyHandlingTransactionNative and
adding test which should verify
- Whether large allocations greate than 1MB for
primitive types are failing
- Array length limited to 1M for complex objects
- Allocations within allowed limit are succeeding

Adding a test api in Parcel to mock that binder
transaction is being handled.

Test: atest -c android.os.ParcelTest
Bug: 205282403

Change-Id: I46bc719508c03613646d182571bf773149223bd1
This commit is contained in:
Pawan Wagh
2023-03-21 02:02:52 +00:00
parent 7b8e729f1b
commit 94e184a09d
4 changed files with 110 additions and 10 deletions

View File

@@ -325,7 +325,24 @@ public class Binder implements IBinder {
* @hide
*/
@CriticalNative
public static final native boolean isDirectlyHandlingTransaction();
public static final native boolean isDirectlyHandlingTransactionNative();
private static boolean sIsHandlingBinderTransaction = false;
/**
* @hide
*/
public static final boolean isDirectlyHandlingTransaction() {
return sIsHandlingBinderTransaction || isDirectlyHandlingTransactionNative();
}
/**
* This is Test API which will be used to override output of isDirectlyHandlingTransactionNative
* @hide
*/
public static void setIsDirectlyHandlingTransactionOverride(boolean isInTransaction) {
sIsHandlingBinderTransaction = isInTransaction;
}
/**
* Returns {@code true} if the current thread has had its identity

View File

@@ -1584,7 +1584,6 @@ public final class Parcel {
@Nullable
public final boolean[] createBooleanArray() {
int N = readInt();
// Assuming size of 4 byte for boolean.
ensureWithinMemoryLimit(SIZE_BOOLEAN, N);
// >>2 as a fast divide-by-4 works in the create*Array() functions
// because dataAvail() will never return a negative number. 4 is
@@ -1628,7 +1627,6 @@ public final class Parcel {
@Nullable
public short[] createShortArray() {
int n = readInt();
// Assuming size of 2 byte for short.
ensureWithinMemoryLimit(SIZE_SHORT, n);
if (n >= 0 && n <= (dataAvail() >> 2)) {
short[] val = new short[n];
@@ -1668,7 +1666,6 @@ public final class Parcel {
@Nullable
public final char[] createCharArray() {
int N = readInt();
// Assuming size of 2 byte for char.
ensureWithinMemoryLimit(SIZE_CHAR, N);
if (N >= 0 && N <= (dataAvail() >> 2)) {
char[] val = new char[N];
@@ -1707,7 +1704,6 @@ public final class Parcel {
@Nullable
public final int[] createIntArray() {
int N = readInt();
// Assuming size of 4 byte for int.
ensureWithinMemoryLimit(SIZE_INT, N);
if (N >= 0 && N <= (dataAvail() >> 2)) {
int[] val = new int[N];
@@ -1746,7 +1742,6 @@ public final class Parcel {
@Nullable
public final long[] createLongArray() {
int N = readInt();
// Assuming size of 8 byte for long.
ensureWithinMemoryLimit(SIZE_LONG, N);
// >>3 because stored longs are 64 bits
if (N >= 0 && N <= (dataAvail() >> 3)) {
@@ -1786,7 +1781,6 @@ public final class Parcel {
@Nullable
public final float[] createFloatArray() {
int N = readInt();
// Assuming size of 4 byte for float.
ensureWithinMemoryLimit(SIZE_FLOAT, N);
// >>2 because stored floats are 4 bytes
if (N >= 0 && N <= (dataAvail() >> 2)) {
@@ -1826,7 +1820,6 @@ public final class Parcel {
@Nullable
public final double[] createDoubleArray() {
int N = readInt();
// Assuming size of 8 byte for double.
ensureWithinMemoryLimit(SIZE_DOUBLE, N);
// >>3 because stored doubles are 8 bytes
if (N >= 0 && N <= (dataAvail() >> 3)) {

View File

@@ -974,7 +974,7 @@ static jint android_os_Binder_getCallingUid()
return IPCThreadState::self()->getCallingUid();
}
static jboolean android_os_Binder_isDirectlyHandlingTransaction() {
static jboolean android_os_Binder_isDirectlyHandlingTransactionNative() {
return getCurrentServingCall() == BinderCallType::BINDER;
}
@@ -1082,7 +1082,8 @@ static const JNINativeMethod gBinderMethods[] = {
// @CriticalNative
{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
// @CriticalNative
{ "isDirectlyHandlingTransaction", "()Z", (void*)android_os_Binder_isDirectlyHandlingTransaction },
{ "isDirectlyHandlingTransactionNative", "()Z",
(void*)android_os_Binder_isDirectlyHandlingTransactionNative },
// @CriticalNative
{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
// @CriticalNative

View File

@@ -246,4 +246,93 @@ public class ParcelTest {
assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0));
assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0));
}
/***
* Tests for b/205282403
* This test checks if allocations made over limit of 1MB for primitive types
* and 1M length for complex objects are not allowed.
*/
@Test
public void testAllocationsOverLimit_whenOverLimit_throws() {
Binder.setIsDirectlyHandlingTransactionOverride(true);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.writeInt(Integer.MAX_VALUE);
p.setDataPosition(0);
assertThrows(BadParcelableException.class, () ->p.createBooleanArray());
p.setDataPosition(0);
assertThrows(BadParcelableException.class, () ->p.createCharArray());
p.setDataPosition(0);
assertThrows(BadParcelableException.class, () ->p.createIntArray());
p.setDataPosition(0);
assertThrows(BadParcelableException.class, () ->p.createLongArray());
p.setDataPosition(0);
assertThrows(BadParcelableException.class, () ->p.createBinderArray());
int[] dimensions = new int[]{Integer.MAX_VALUE, 100, 100};
p.setDataPosition(0);
assertThrows(BadParcelableException.class,
() -> p.createFixedArray(int[][][].class, dimensions));
p.setDataPosition(0);
assertThrows(BadParcelableException.class,
() -> p.createFixedArray(String[][][].class, dimensions));
p.setDataPosition(0);
assertThrows(BadParcelableException.class,
() -> p.createFixedArray(IBinder[][][].class, dimensions));
p.recycle();
Binder.setIsDirectlyHandlingTransactionOverride(false);
}
/***
* Tests for b/205282403
* This test checks if allocations made under limit of 1MB for primitive types
* and 1M length for complex objects are allowed.
*/
@Test
public void testAllocations_whenWithinLimit() {
Binder.setIsDirectlyHandlingTransactionOverride(true);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.writeInt(100000);
p.setDataPosition(0);
p.createByteArray();
p.setDataPosition(0);
p.createCharArray();
p.setDataPosition(0);
p.createIntArray();
p.setDataPosition(0);
p.createLongArray();
p.setDataPosition(0);
p.createBinderArray();
int[] dimensions = new int[]{ 100, 100, 100 };
p.setDataPosition(0);
int[][][] data = new int[100][100][100];
p.writeFixedArray(data, 0, dimensions);
p.setDataPosition(0);
p.createFixedArray(int[][][].class, dimensions);
p.setDataPosition(0);
IBinder[][][] parcelables = new IBinder[100][100][100];
p.writeFixedArray(parcelables, 0, dimensions);
p.setDataPosition(0);
p.createFixedArray(IBinder[][][].class, dimensions);
p.recycle();
Binder.setIsDirectlyHandlingTransactionOverride(false);
}
}