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

Commit 3834321f authored by Sandeep Bandaru's avatar Sandeep Bandaru Committed by Android (Google) Code Review
Browse files

Merge changes from topic "parcel-binder" into main

* changes:
  Add hasBinders() to Bundle
  Adding method to check if a Parcel has any Binders marshalled in it.
parents ed1af87f 4949493f
Loading
Loading
Loading
Loading
+99 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.os;

import static java.util.Objects.requireNonNull;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -31,6 +32,8 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;

import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

@@ -53,6 +56,53 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    @VisibleForTesting
    static final int FLAG_ALLOW_FDS = 1 << 10;

    @VisibleForTesting
    static final int FLAG_HAS_BINDERS_KNOWN = 1 << 11;

    @VisibleForTesting
    static final int FLAG_HAS_BINDERS = 1 << 12;


    /**
     * Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain
     * Binder object(s).
     *
     * @hide
     */
    public static final int STATUS_BINDERS_NOT_PRESENT = 0;

    /**
     * Status when the Bundle can <b>assert</b> that there are Binder object(s) in the Parcel.
     *
     * @hide
     */
    public static final int STATUS_BINDERS_PRESENT = 1;

    /**
     * Status when the Bundle cannot be checked for Binders and there is no parcelled data
     * available to check either.
     * <p> This could happen when a Bundle is unparcelled or was never parcelled, and modified such
     * that it is not possible to assert if the Bundle has any Binder objects in the current state.
     *
     * For e.g. calling {@link #putParcelable} or {@link #putBinder} could have added a Binder
     * object to the Bundle but it is not possible to assert this fact unless the Bundle is written
     * to a Parcel.
     * </p>
     *
     * @hide
     */
    public static final int STATUS_BINDERS_UNKNOWN = 2;

    /** @hide */
    @IntDef(flag = true, prefix = {"STATUS_BINDERS_"}, value = {
            STATUS_BINDERS_PRESENT,
            STATUS_BINDERS_UNKNOWN,
            STATUS_BINDERS_NOT_PRESENT
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface HasBinderStatus {
    }

    /** An unmodifiable {@code Bundle} that is always {@link #isEmpty() empty}. */
    public static final Bundle EMPTY;

@@ -75,7 +125,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     */
    public Bundle() {
        super();
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
    }

    /**
@@ -111,7 +161,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     *
     * @param from The bundle to be copied.
     * @param deep Whether is a deep or shallow copy.
     *
     * @hide
     */
    Bundle(Bundle from, boolean deep) {
@@ -143,7 +192,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     */
    public Bundle(ClassLoader loader) {
        super(loader);
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
    }

    /**
@@ -154,7 +203,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     */
    public Bundle(int capacity) {
        super(capacity);
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
    }

    /**
@@ -180,7 +229,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
     */
    public Bundle(PersistableBundle b) {
        super(b);
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
        mFlags = FLAG_HAS_FDS_KNOWN | FLAG_HAS_BINDERS_KNOWN | FLAG_ALLOW_FDS;
    }

    /**
@@ -292,6 +341,9 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        if ((mFlags & FLAG_HAS_FDS) != 0) {
            mFlags &= ~FLAG_HAS_FDS_KNOWN;
        }
        if ((mFlags & FLAG_HAS_BINDERS) != 0) {
            mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
        }
    }

    /**
@@ -306,13 +358,20 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        bundle.mOwnsLazyValues = false;
        mMap.putAll(bundle.mMap);

        // FD state is now known if and only if both bundles already knew
        // FD and Binders state is now known if and only if both bundles already knew
        if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
            mFlags |= FLAG_HAS_FDS;
        }
        if ((bundle.mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
            mFlags &= ~FLAG_HAS_FDS_KNOWN;
        }

        if ((bundle.mFlags & FLAG_HAS_BINDERS) != 0) {
            mFlags |= FLAG_HAS_BINDERS;
        }
        if ((bundle.mFlags & FLAG_HAS_BINDERS_KNOWN) == 0) {
            mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
        }
    }

    /**
@@ -343,6 +402,33 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        return (mFlags & FLAG_HAS_FDS) != 0;
    }

    /**
     * Returns a status indicating whether the bundle contains any parcelled Binder objects.
     * @hide
     */
    public @HasBinderStatus int hasBinders() {
        if ((mFlags & FLAG_HAS_BINDERS_KNOWN) != 0) {
            if ((mFlags & FLAG_HAS_BINDERS) != 0) {
                return STATUS_BINDERS_PRESENT;
            } else {
                return STATUS_BINDERS_NOT_PRESENT;
            }
        }

        final Parcel p = mParcelledData;
        if (p == null) {
            return STATUS_BINDERS_UNKNOWN;
        }
        if (p.hasBinders()) {
            mFlags = mFlags | FLAG_HAS_BINDERS | FLAG_HAS_BINDERS_KNOWN;
            return STATUS_BINDERS_PRESENT;
        } else {
            mFlags = mFlags & ~FLAG_HAS_BINDERS;
            mFlags |= FLAG_HAS_BINDERS_KNOWN;
            return STATUS_BINDERS_NOT_PRESENT;
        }
    }

    /** {@hide} */
    @Override
    public void putObject(@Nullable String key, @Nullable Object value) {
@@ -464,6 +550,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
@@ -502,6 +589,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
@@ -517,6 +605,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /** {@hide} */
@@ -525,6 +614,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
@@ -540,6 +630,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
@@ -680,6 +771,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    public void putBinder(@Nullable String key, @Nullable IBinder value) {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
@@ -697,6 +789,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    public void putIBinder(@Nullable String key, @Nullable IBinder value) {
        unparcel();
        mMap.put(key, value);
        mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
    }

    /**
+32 −0
Original line number Diff line number Diff line
@@ -475,6 +475,10 @@ public final class Parcel {
    private static native boolean nativeHasFileDescriptors(long nativePtr);
    private static native boolean nativeHasFileDescriptorsInRange(
            long nativePtr, int offset, int length);

    private static native boolean nativeHasBinders(long nativePtr);
    private static native boolean nativeHasBindersInRange(
            long nativePtr, int offset, int length);
    @RavenwoodThrow
    private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
    @RavenwoodThrow
@@ -969,6 +973,34 @@ public final class Parcel {
        return false;
    }

    /**
     * Report whether the parcel contains any marshalled IBinder objects.
     *
     * @throws UnsupportedOperationException if binder kernel driver was disabled or if method was
     *                                       invoked in case of Binder RPC protocol.
     * @hide
     */
    public boolean hasBinders() {
        return nativeHasBinders(mNativePtr);
    }

    /**
     * Report whether the parcel contains any marshalled {@link IBinder} objects 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 binders in the range or not.
     * @throws IllegalArgumentException if the parameters are out of the permitted ranges.
     *
     * @hide
     */
    public boolean hasBinders(int offset, int length) {
        return nativeHasBindersInRange(mNativePtr, offset, length);
    }

    /**
     * Store or read an IBinder interface token in the parcel at the current
     * {@link #dataPosition}. This is used to validate that the marshalled
+34 −1
Original line number Diff line number Diff line
@@ -661,6 +661,35 @@ static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNa
    return;
}

static jboolean android_os_Parcel_hasBinders(JNIEnv* env, jclass clazz, jlong nativePtr) {
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        bool result;
        status_t err = parcel->hasBinders(&result);
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
            return JNI_FALSE;
        }
        return result ? JNI_TRUE : JNI_FALSE;
    }
    return JNI_FALSE;
}

static jboolean android_os_Parcel_hasBindersInRange(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->hasBindersInRange(offset, length, &result);
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
            return JNI_FALSE;
        }
        return result ? JNI_TRUE : JNI_FALSE;
    }
    return JNI_FALSE;
}

static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
{
    jboolean ret = JNI_FALSE;
@@ -806,7 +835,7 @@ static jboolean android_os_Parcel_replaceCallingWorkSourceUid(jlong nativePtr, j
}

// ----------------------------------------------------------------------------

// clang-format off
static const JNINativeMethod gParcelMethods[] = {
    // @CriticalNative
    {"nativeMarkSensitive",       "(J)V", (void*)android_os_Parcel_markSensitive},
@@ -886,6 +915,9 @@ static const JNINativeMethod gParcelMethods[] = {
    // @CriticalNative
    {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
    {"nativeHasFileDescriptorsInRange",  "(JII)Z", (void*)android_os_Parcel_hasFileDescriptorsInRange},

    {"nativeHasBinders",  "(J)Z", (void*)android_os_Parcel_hasBinders},
    {"nativeHasBindersInRange",  "(JII)Z", (void*)android_os_Parcel_hasBindersInRange},
    {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
    {"nativeEnforceInterface",    "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},

@@ -900,6 +932,7 @@ static const JNINativeMethod gParcelMethods[] = {
    // @CriticalNative
    {"nativeReplaceCallingWorkSourceUid", "(JI)Z", (void*)android_os_Parcel_replaceCallingWorkSourceUid},
};
// clang-format on

const char* const kParcelPathName = "android/os/Parcel";

+38 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.Presubmit;
import android.platform.test.ravenwood.RavenwoodRule;
@@ -445,6 +446,42 @@ public class BundleTest {
        assertThat(bundle.size()).isEqualTo(0);
    }

    @Test
    @DisabledOnRavenwood(blockedBy = Parcel.class)
    public void parcelledBundleWithBinder_shouldReturnHasBindersTrue() throws Exception {
        Bundle bundle = new Bundle();
        bundle.putParcelable("test", new CustomParcelable(13, "Tiramisu"));
        bundle.putBinder("test_binder",
                new IBinderWorkSourceNestedService.Stub() {

                    public int[] nestedCallWithWorkSourceToSet(int uidToBlame) {
                        return new int[0];
                    }

                    public int[] nestedCall() {
                        return new int[0];
                    }
                });
        Bundle bundle2 = new Bundle(getParcelledBundle(bundle));
        assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_PRESENT);

        bundle2.putParcelable("test2", new CustomParcelable(13, "Tiramisu"));
        assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_UNKNOWN);
    }

    @Test
    @DisabledOnRavenwood(blockedBy = Parcel.class)
    public void parcelledBundleWithoutBinder_shouldReturnHasBindersFalse() throws Exception {
        Bundle bundle = new Bundle();
        bundle.putParcelable("test", new CustomParcelable(13, "Tiramisu"));
        Bundle bundle2 = new Bundle(getParcelledBundle(bundle));
        //Should fail to load with framework classloader.
        assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_NOT_PRESENT);

        bundle2.putParcelable("test2", new CustomParcelable(13, "Tiramisu"));
        assertEquals(bundle2.hasBinders(), Bundle.STATUS_BINDERS_UNKNOWN);
    }

    private Bundle getMalformedBundle() {
        Parcel p = Parcel.obtain();
        p.writeInt(BaseBundle.BUNDLE_MAGIC);
@@ -520,6 +557,7 @@ public class BundleTest {
            public CustomParcelable createFromParcel(Parcel in) {
                return new CustomParcelable(in);
            }

            @Override
            public CustomParcelable[] newArray(int size) {
                return new CustomParcelable[size];
+26 −0
Original line number Diff line number Diff line
@@ -347,4 +347,30 @@ public class ParcelTest {
        p.recycle();
        Binder.setIsDirectlyHandlingTransactionOverride(false);
    }

    @Test
    @IgnoreUnderRavenwood(blockedBy = Parcel.class)
    public void testHasBinders_AfterWritingBinderToParcel() {
        Binder binder = new Binder();
        Parcel pA = Parcel.obtain();
        int iA = pA.dataPosition();
        pA.writeInt(13);
        assertFalse(pA.hasBinders());
        pA.writeStrongBinder(binder);
        assertTrue(pA.hasBinders());
    }


    @Test
    @IgnoreUnderRavenwood(blockedBy = Parcel.class)
    public void testHasBindersInRange_AfterWritingBinderToParcel() {
        Binder binder = new Binder();
        Parcel pA = Parcel.obtain();
        pA.writeInt(13);

        int binderStartPos = pA.dataPosition();
        pA.writeStrongBinder(binder);
        int binderEndPos = pA.dataPosition();
        assertTrue(pA.hasBinders(binderStartPos, binderEndPos - binderStartPos));
    }
}
Loading