From 172c97db77f7cd2f296ca7c506a4a0b16f801e51 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Thu, 7 Oct 2021 14:00:56 +0100 Subject: [PATCH] Add range-based Parcel.hasFileDescriptors(offset, length) To be used by lazy values in bundle. I ended up opening up as public API for apps to use it too because I saw no reason not to, can change if folks prefer it to be @hide though. Test: atest -d android.os.cts.ParcelTest android.os.cts.BundleTest android.os.BundleTest android.os.ParcelTest Bug: 195622897 Change-Id: I7bf580f94313669fe67998b32b2723544c594cde --- core/api/current.txt | 1 + core/java/android/os/Parcel.java | 45 +++++++++++++++++++++++++------- core/jni/android_os_Parcel.cpp | 17 ++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 4d89cdf6affb6..49651ed1a24a4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -29976,6 +29976,7 @@ package android.os { method public int dataSize(); method public void enforceInterface(@NonNull String); method public boolean hasFileDescriptors(); + method public boolean hasFileDescriptors(int, int); method public byte[] marshall(); method @NonNull public static android.os.Parcel obtain(); method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index e6925cbdc065f..df1d272d28956 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -361,6 +361,8 @@ public final class Parcel { long thisNativePtr, long otherNativePtr, int offset, int length); @CriticalNative private static native boolean nativeHasFileDescriptors(long nativePtr); + private static native boolean nativeHasFileDescriptorsInRange( + long nativePtr, int offset, int length); private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName); private static native void nativeEnforceInterface(long nativePtr, String interfaceName); @@ -687,10 +689,25 @@ public final class Parcel { /** * Report whether the parcel contains any marshalled file descriptors. */ - public final boolean hasFileDescriptors() { + public boolean hasFileDescriptors() { return nativeHasFileDescriptors(mNativePtr); } + /** + * Report whether the parcel contains any marshalled file descriptors in the range defined by + * {@code offset} and {@code length}. + * + * @param offset The offset from which the range starts. Should be between 0 and + * {@link #dataSize()}. + * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code + * offset}. + * @return whether there are file descriptors or not. + * @throws IllegalArgumentException if the parameters are out of the permitted ranges. + */ + public boolean hasFileDescriptors(int offset, int length) { + return nativeHasFileDescriptorsInRange(mNativePtr, offset, length); + } + /** * Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)} * has file descriptors. @@ -3495,15 +3512,26 @@ public final class Parcel { int start = dataPosition(); int type = readInt(); if (isLengthPrefixed(type)) { - int length = readInt(); - setDataPosition(MathUtils.addOrThrow(dataPosition(), length)); - return new LazyValue(this, start, length, type, loader); + int objectLength = readInt(); + int end = MathUtils.addOrThrow(dataPosition(), objectLength); + int valueLength = end - start; + setDataPosition(end); + return new LazyValue(this, start, valueLength, type, loader); } else { return readValue(type, loader, /* clazz */ null); } } + private static final class LazyValue implements Supplier { + /** + * | 4B | 4B | + * mSource = Parcel{... | type | length | object | ...} + * a b c d + * length = d - c + * mPosition = a + * mLength = d - a + */ private final int mPosition; private final int mLength; private final int mType; @@ -3551,7 +3579,7 @@ public final class Parcel { public void writeToParcel(Parcel out) { Parcel source = mSource; if (source != null) { - out.appendFrom(source, mPosition, mLength + 8); + out.appendFrom(source, mPosition, mLength); } else { out.writeValue(mObject); } @@ -3560,7 +3588,7 @@ public final class Parcel { public boolean hasFileDescriptors() { Parcel source = mSource; return (source != null) - ? getValueParcel(source).hasFileDescriptors() + ? source.hasFileDescriptors(mPosition, mLength) : Parcel.hasFileDescriptors(mObject); } @@ -3621,10 +3649,7 @@ public final class Parcel { Parcel parcel = mValueParcel; if (parcel == null) { parcel = Parcel.obtain(); - // mLength is the length of object representation, excluding the type and length. - // mPosition is the position of the entire value container, right before the type. - // So, we add 4 bytes for the type + 4 bytes for the length written. - parcel.appendFrom(source, mPosition, mLength + 8); + parcel.appendFrom(source, mPosition, mLength); mValueParcel = parcel; } return parcel; diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index ac320386c3f3a..ee7f78dd5cff3 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -655,6 +655,22 @@ static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr) return ret; } +static jboolean android_os_Parcel_hasFileDescriptorsInRange(JNIEnv* env, jclass clazz, + jlong nativePtr, jint offset, + jint length) { + Parcel* parcel = reinterpret_cast(nativePtr); + if (parcel != NULL) { + bool result; + status_t err = parcel->hasFileDescriptorsInRange(offset, length, result); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return JNI_FALSE; + } + return result ? JNI_TRUE : JNI_FALSE; + } + return JNI_FALSE; +} + // String tries to allocate itself on the stack, within a known size, but will // make a heap allocation if not. template @@ -847,6 +863,7 @@ static const JNINativeMethod gParcelMethods[] = { {"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom}, // @CriticalNative {"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors}, + {"nativeHasFileDescriptorsInRange", "(JII)Z", (void*)android_os_Parcel_hasFileDescriptorsInRange}, {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken}, {"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},