Loading core/java/android/os/Parcel.java +107 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,22 @@ public final class Parcel { // see libbinder's binder/Status.h private static final int EX_TRANSACTION_FAILED = -129; // Allow limit of 1 MB for allocating arrays private static final int ARRAY_ALLOCATION_LIMIT = 1000000; // Following type size are used to determine allocation size while creating arrays private static final int SIZE_BYTE = 1; private static final int SIZE_CHAR = 2; private static final int SIZE_SHORT = 2; private static final int SIZE_BOOLEAN = 4; private static final int SIZE_INT = 4; private static final int SIZE_FLOAT = 4; private static final int SIZE_DOUBLE = 8; private static final int SIZE_LONG = 8; // Assume the least possible size for complex objects private static final int SIZE_COMPLEX_TYPE = 1; @CriticalNative private static native void nativeMarkSensitive(long nativePtr); @FastNative Loading Loading @@ -1502,9 +1518,63 @@ public final class Parcel { } } private static <T> int getItemTypeSize(@NonNull Class<T> arrayClass) { final Class<?> componentType = arrayClass.getComponentType(); // typeSize has been referred from respective create*Array functions if (componentType == boolean.class) { return SIZE_BOOLEAN; } else if (componentType == byte.class) { return SIZE_BYTE; } else if (componentType == char.class) { return SIZE_CHAR; } else if (componentType == int.class) { return SIZE_INT; } else if (componentType == long.class) { return SIZE_LONG; } else if (componentType == float.class) { return SIZE_FLOAT; } else if (componentType == double.class) { return SIZE_DOUBLE; } return SIZE_COMPLEX_TYPE; } private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) { // For Multidimensional arrays, Calculate total object // which will be allocated. int totalObjects = 1; try { for (int dimension : dimensions) { totalObjects = Math.multiplyExact(totalObjects, dimension); } } catch (ArithmeticException e) { Log.e(TAG, "ArithmeticException occurred while multiplying dimensions " + e); } ensureWithinMemoryLimit(typeSize, totalObjects); } private void ensureWithinMemoryLimit(int typeSize, @NonNull int length) { int estimatedAllocationSize = 0; try { estimatedAllocationSize = Math.multiplyExact(typeSize, length); } catch (ArithmeticException e) { Log.e(TAG, "ArithmeticException occurred while multiplying values " + typeSize + " and " + length + " Exception: " + e); } boolean isInBinderTransaction = Binder.isDirectlyHandlingTransaction(); if (isInBinderTransaction && (estimatedAllocationSize > ARRAY_ALLOCATION_LIMIT)) { Log.e(TAG, "Trying to Allocate " + estimatedAllocationSize + " memory, In Binder Transaction : " + isInBinderTransaction); } } @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 // the size of a stored boolean in the stream. Loading Loading @@ -1547,6 +1617,8 @@ 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]; for (int i = 0; i < n; i++) { Loading Loading @@ -1585,6 +1657,8 @@ 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]; for (int i=0; i<N; i++) { Loading Loading @@ -1622,6 +1696,8 @@ 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]; for (int i=0; i<N; i++) { Loading Loading @@ -1659,6 +1735,8 @@ 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)) { long[] val = new long[N]; Loading Loading @@ -1697,6 +1775,8 @@ 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)) { float[] val = new float[N]; Loading Loading @@ -1735,6 +1815,8 @@ 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)) { double[] val = new double[N]; Loading Loading @@ -1788,6 +1870,7 @@ public final class Parcel { @Nullable public final String[] createString8Array() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { String[] val = new String[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1828,6 +1911,7 @@ public final class Parcel { @Nullable public final String[] createString16Array() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { String[] val = new String[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1920,6 +2004,7 @@ public final class Parcel { @Nullable public final IBinder[] createBinderArray() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { IBinder[] val = new IBinder[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1954,6 +2039,7 @@ public final class Parcel { public final <T extends IInterface> T[] createInterfaceArray( @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { T[] val = newArray.apply(N); for (int i=0; i<N; i++) { Loading Loading @@ -3200,6 +3286,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); FileDescriptor[] f = new FileDescriptor[N]; for (int i = 0; i < N; i++) { f[i] = readRawFileDescriptor(); Loading Loading @@ -3666,6 +3753,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<T> l = new ArrayList<T>(N); while (N > 0) { l.add(readTypedObject(c)); Loading Loading @@ -3717,6 +3805,7 @@ public final class Parcel { if (count < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count); final SparseArray<T> array = new SparseArray<>(count); for (int i = 0; i < count; i++) { final int index = readInt(); Loading Loading @@ -3745,6 +3834,7 @@ public final class Parcel { if (count < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count); final ArrayMap<String, T> map = new ArrayMap<>(count); for (int i = 0; i < count; i++) { final String key = readString(); Loading @@ -3771,6 +3861,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<String> l = new ArrayList<String>(N); while (N > 0) { l.add(readString()); Loading @@ -3796,6 +3887,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<IBinder> l = new ArrayList<IBinder>(N); while (N > 0) { l.add(readStrongBinder()); Loading @@ -3822,6 +3914,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<T> l = new ArrayList<T>(N); while (N > 0) { l.add(asInterface.apply(readStrongBinder())); Loading Loading @@ -3981,6 +4074,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); T[] l = c.newArray(N); for (int i=0; i<N; i++) { l[i] = readTypedObject(c); Loading Loading @@ -4209,6 +4303,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i)); Loading Loading @@ -4265,6 +4363,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i), asInterface); Loading Loading @@ -4320,6 +4422,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i), c); Loading Loading @@ -5065,6 +5171,7 @@ public final class Parcel { if (n < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, n); T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n)); for (int i = 0; i < n; i++) { p[i] = readParcelableInternal(loader, clazz); Loading Loading
core/java/android/os/Parcel.java +107 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,22 @@ public final class Parcel { // see libbinder's binder/Status.h private static final int EX_TRANSACTION_FAILED = -129; // Allow limit of 1 MB for allocating arrays private static final int ARRAY_ALLOCATION_LIMIT = 1000000; // Following type size are used to determine allocation size while creating arrays private static final int SIZE_BYTE = 1; private static final int SIZE_CHAR = 2; private static final int SIZE_SHORT = 2; private static final int SIZE_BOOLEAN = 4; private static final int SIZE_INT = 4; private static final int SIZE_FLOAT = 4; private static final int SIZE_DOUBLE = 8; private static final int SIZE_LONG = 8; // Assume the least possible size for complex objects private static final int SIZE_COMPLEX_TYPE = 1; @CriticalNative private static native void nativeMarkSensitive(long nativePtr); @FastNative Loading Loading @@ -1502,9 +1518,63 @@ public final class Parcel { } } private static <T> int getItemTypeSize(@NonNull Class<T> arrayClass) { final Class<?> componentType = arrayClass.getComponentType(); // typeSize has been referred from respective create*Array functions if (componentType == boolean.class) { return SIZE_BOOLEAN; } else if (componentType == byte.class) { return SIZE_BYTE; } else if (componentType == char.class) { return SIZE_CHAR; } else if (componentType == int.class) { return SIZE_INT; } else if (componentType == long.class) { return SIZE_LONG; } else if (componentType == float.class) { return SIZE_FLOAT; } else if (componentType == double.class) { return SIZE_DOUBLE; } return SIZE_COMPLEX_TYPE; } private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) { // For Multidimensional arrays, Calculate total object // which will be allocated. int totalObjects = 1; try { for (int dimension : dimensions) { totalObjects = Math.multiplyExact(totalObjects, dimension); } } catch (ArithmeticException e) { Log.e(TAG, "ArithmeticException occurred while multiplying dimensions " + e); } ensureWithinMemoryLimit(typeSize, totalObjects); } private void ensureWithinMemoryLimit(int typeSize, @NonNull int length) { int estimatedAllocationSize = 0; try { estimatedAllocationSize = Math.multiplyExact(typeSize, length); } catch (ArithmeticException e) { Log.e(TAG, "ArithmeticException occurred while multiplying values " + typeSize + " and " + length + " Exception: " + e); } boolean isInBinderTransaction = Binder.isDirectlyHandlingTransaction(); if (isInBinderTransaction && (estimatedAllocationSize > ARRAY_ALLOCATION_LIMIT)) { Log.e(TAG, "Trying to Allocate " + estimatedAllocationSize + " memory, In Binder Transaction : " + isInBinderTransaction); } } @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 // the size of a stored boolean in the stream. Loading Loading @@ -1547,6 +1617,8 @@ 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]; for (int i = 0; i < n; i++) { Loading Loading @@ -1585,6 +1657,8 @@ 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]; for (int i=0; i<N; i++) { Loading Loading @@ -1622,6 +1696,8 @@ 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]; for (int i=0; i<N; i++) { Loading Loading @@ -1659,6 +1735,8 @@ 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)) { long[] val = new long[N]; Loading Loading @@ -1697,6 +1775,8 @@ 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)) { float[] val = new float[N]; Loading Loading @@ -1735,6 +1815,8 @@ 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)) { double[] val = new double[N]; Loading Loading @@ -1788,6 +1870,7 @@ public final class Parcel { @Nullable public final String[] createString8Array() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { String[] val = new String[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1828,6 +1911,7 @@ public final class Parcel { @Nullable public final String[] createString16Array() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { String[] val = new String[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1920,6 +2004,7 @@ public final class Parcel { @Nullable public final IBinder[] createBinderArray() { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { IBinder[] val = new IBinder[N]; for (int i=0; i<N; i++) { Loading Loading @@ -1954,6 +2039,7 @@ public final class Parcel { public final <T extends IInterface> T[] createInterfaceArray( @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) { int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { T[] val = newArray.apply(N); for (int i=0; i<N; i++) { Loading Loading @@ -3200,6 +3286,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); FileDescriptor[] f = new FileDescriptor[N]; for (int i = 0; i < N; i++) { f[i] = readRawFileDescriptor(); Loading Loading @@ -3666,6 +3753,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<T> l = new ArrayList<T>(N); while (N > 0) { l.add(readTypedObject(c)); Loading Loading @@ -3717,6 +3805,7 @@ public final class Parcel { if (count < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count); final SparseArray<T> array = new SparseArray<>(count); for (int i = 0; i < count; i++) { final int index = readInt(); Loading Loading @@ -3745,6 +3834,7 @@ public final class Parcel { if (count < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, count); final ArrayMap<String, T> map = new ArrayMap<>(count); for (int i = 0; i < count; i++) { final String key = readString(); Loading @@ -3771,6 +3861,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<String> l = new ArrayList<String>(N); while (N > 0) { l.add(readString()); Loading @@ -3796,6 +3887,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<IBinder> l = new ArrayList<IBinder>(N); while (N > 0) { l.add(readStrongBinder()); Loading @@ -3822,6 +3914,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); ArrayList<T> l = new ArrayList<T>(N); while (N > 0) { l.add(asInterface.apply(readStrongBinder())); Loading Loading @@ -3981,6 +4074,7 @@ public final class Parcel { if (N < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); T[] l = c.newArray(N); for (int i=0; i<N; i++) { l[i] = readTypedObject(c); Loading Loading @@ -4209,6 +4303,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i)); Loading Loading @@ -4265,6 +4363,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i), asInterface); Loading Loading @@ -4320,6 +4422,10 @@ public final class Parcel { while (innermost.isArray()) { innermost = innermost.getComponentType(); } int typeSize = getItemTypeSize(innermost); ensureWithinMemoryLimit(typeSize, dimensions); val = (T) Array.newInstance(innermost, dimensions); for (int i = 0; i < length; i++) { readFixedArray(Array.get(val, i), c); Loading Loading @@ -5065,6 +5171,7 @@ public final class Parcel { if (n < 0) { return null; } ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, n); T[] p = (T[]) ((clazz == null) ? new Parcelable[n] : Array.newInstance(clazz, n)); for (int i = 0; i < n; i++) { p[i] = readParcelableInternal(loader, clazz); Loading