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
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d89cdf..49651ed 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29976,6 +29976,7 @@
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 e6925cb..df1d272 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -361,6 +361,8 @@
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,11 +689,26 @@
/**
* 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 @@
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<Object> {
+ /**
+ * | 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 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 boolean hasFileDescriptors() {
Parcel source = mSource;
return (source != null)
- ? getValueParcel(source).hasFileDescriptors()
+ ? source.hasFileDescriptors(mPosition, mLength)
: Parcel.hasFileDescriptors(mObject);
}
@@ -3621,10 +3649,7 @@
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 ac32038..ee7f78d 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -655,6 +655,22 @@
return ret;
}
+static jboolean android_os_Parcel_hasFileDescriptorsInRange(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint offset,
+ jint length) {
+ Parcel* parcel = reinterpret_cast<Parcel*>(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 <size_t StackReserve>
@@ -847,6 +863,7 @@
{"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},