Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94e184a0 authored by Pawan Wagh's avatar Pawan Wagh
Browse files

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
parent 7b8e729f
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
@@ -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
+0 −7
Original line number Diff line number Diff line
@@ -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)) {
+3 −2
Original line number Diff line number Diff line
@@ -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
+89 −0
Original line number Diff line number Diff line
@@ -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);
    }
}