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

Commit 983e43a0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I45e4bc66,Ic9b4a118,If4c8a0ed into main

* changes:
  Parcel directly to mapped SharedMemory
  Parcel directly to mapped SharedMemory
  Introduce Parcel.{,un}marshall methods that work with ByteBuffers
parents 4eb5d526 51c00139
Loading
Loading
Loading
Loading
+5 −8
Original line number Diff line number Diff line
@@ -75,7 +75,6 @@ public class MarshalQueryableParcelable<T extends Parcelable>
            }

            Parcel parcel = Parcel.obtain();
            byte[] parcelContents;

            try {
                value.writeToParcel(parcel, /*flags*/0);
@@ -85,17 +84,15 @@ public class MarshalQueryableParcelable<T extends Parcelable>
                            "Parcelable " + value + " must not have file descriptors");
                }

                parcelContents = parcel.marshall();
                final int position = buffer.position();
                parcel.marshall(buffer);
                if (buffer.position() == position) {
                    throw new AssertionError("No data marshaled for " + value);
                }
            }
            finally {
                parcel.recycle();
            }

            if (parcelContents.length == 0) {
                throw new AssertionError("No data marshaled for " + value);
            }

            buffer.put(parcelContents);
        }

        @Override
+78 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ import com.android.internal.util.ArrayUtils;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;

import java.nio.BufferOverflowException;
import java.nio.ReadOnlyBufferException;
import libcore.util.SneakyThrow;

import java.io.ByteArrayInputStream;
@@ -62,6 +64,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Array;
@@ -457,8 +460,15 @@ public final class Parcel {
    private static native void nativeDestroy(long nativePtr);

    private static native byte[] nativeMarshall(long nativePtr);
    private static native int nativeMarshallArray(
            long nativePtr, byte[] data, int offset, int length);
    private static native int nativeMarshallBuffer(
            long nativePtr, ByteBuffer buffer, int offset, int length);
    private static native void nativeUnmarshall(
            long nativePtr, byte[] data, int offset, int length);
    private static native void nativeUnmarshallBuffer(
            long nativePtr, ByteBuffer buffer, int offset, int length);

    private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
    private static native boolean nativeCompareDataInRange(
            long ptrA, int offsetA, long ptrB, int offsetB, int length);
@@ -813,6 +823,47 @@ public final class Parcel {
        return nativeMarshall(mNativePtr);
    }

    /**
     * Writes the raw bytes of the parcel to a buffer.
     *
     * <p class="note">The data you retrieve here <strong>must not</strong>
     * be placed in any kind of persistent storage (on local disk, across
     * a network, etc).  For that, you should use standard serialization
     * or another kind of general serialization mechanism.  The Parcel
     * marshalled representation is highly optimized for local IPC, and as
     * such does not attempt to maintain compatibility with data created
     * in different versions of the platform.
     *
     * @param buffer The ByteBuffer to write the data to.
     * @throws ReadOnlyBufferException if the buffer is read-only.
     * @throws BufferOverflowException if the buffer is too small.
     *
     * @hide
     */
    public final void marshall(@NonNull ByteBuffer buffer) {
        if (buffer == null) {
            throw new NullPointerException();
        }
        if (buffer.isReadOnly()) {
            throw new ReadOnlyBufferException();
        }

        final int position = buffer.position();
        final int remaining = buffer.remaining();

        int marshalledSize = 0;
        if (buffer.isDirect()) {
            marshalledSize = nativeMarshallBuffer(mNativePtr, buffer, position, remaining);
        } else if (buffer.hasArray()) {
            marshalledSize = nativeMarshallArray(
                    mNativePtr, buffer.array(), buffer.arrayOffset() + position, remaining);
        } else {
            throw new IllegalArgumentException();
        }

        buffer.position(position + marshalledSize);
    }

    /**
     * Fills the raw bytes of this Parcel with the supplied data.
     */
@@ -820,6 +871,33 @@ public final class Parcel {
        nativeUnmarshall(mNativePtr, data, offset, length);
    }

    /**
     * Fills the raw bytes of this Parcel with data from the supplied buffer.
     *
     * @param buffer will read buffer.remaining() bytes from the buffer.
     *
     * @hide
     */
    public final void unmarshall(@NonNull ByteBuffer buffer) {
        if (buffer == null) {
            throw new NullPointerException();
        }

        final int position = buffer.position();
        final int remaining = buffer.remaining();

        if (buffer.isDirect()) {
            nativeUnmarshallBuffer(mNativePtr, buffer, position, remaining);
        } else if (buffer.hasArray()) {
            nativeUnmarshall(
                    mNativePtr, buffer.array(), buffer.arrayOffset() + position, remaining);
        } else {
            throw new IllegalArgumentException();
        }

        buffer.position(position + remaining);
    }

    public final void appendFrom(Parcel parcel, int offset, int length) {
        nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
    }
+1 −1
Original line number Diff line number Diff line
@@ -219,7 +219,7 @@ public class NotificationRankingUpdate implements Parcelable {
                // Gets a read/write buffer mapping the entire shared memory region.
                buffer = mRankingMapFd.mapReadWrite();
                // Puts the ranking map into the shared memory region buffer.
                buffer.put(mapParcel.marshall(), 0, mapSize);
                mapParcel.marshall(buffer);
                // Protects the region from being written to, by setting it to be read-only.
                mRankingMapFd.setProtect(OsConstants.PROT_READ);
                // Puts the SharedMemory object in the parcel.
+85 −2
Original line number Diff line number Diff line
@@ -558,8 +558,7 @@ static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr
    delete parcel;
}

static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
{
static Parcel* parcel_for_marshall(JNIEnv* env, jlong nativePtr) {
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel == NULL) {
       return NULL;
@@ -577,6 +576,16 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
        return NULL;
    }

    return parcel;
}

static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = parcel_for_marshall(env, nativePtr);
    if (parcel == NULL) {
       return NULL;
    }

    jbyteArray ret = env->NewByteArray(parcel->dataSize());

    if (ret != NULL)
@@ -592,6 +601,58 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
    return ret;
}

static long ensure_capacity(JNIEnv* env, Parcel* parcel, jint remaining) {
    long dataSize = parcel->dataSize();
    if (remaining < dataSize) {
        jniThrowExceptionFmt(env, "java/nio/BufferOverflowException",
                             "Destination buffer remaining capacity %d is less than the Parcel data size %d.",
                             remaining, dataSize);
        return -1;
    }
    return dataSize;
}

static int android_os_Parcel_marshall_array(JNIEnv* env, jclass clazz, jlong nativePtr,
                                            jbyteArray data, jint offset, jint remaining)
{
    Parcel* parcel = parcel_for_marshall(env, nativePtr);
    if (parcel == NULL) {
       return 0;
    }

    long data_size = ensure_capacity(env, parcel, remaining);
    if (data_size < 0) {
        return 0;
    }

    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
    if (array != NULL)
    {
        memcpy(array + offset, parcel->data(), data_size);
        env->ReleasePrimitiveArrayCritical(data, array, 0);
    }
    return data_size;
}

static int android_os_Parcel_marshall_buffer(JNIEnv* env, jclass clazz, jlong nativePtr,
                                             jobject javaBuffer, jint offset, jint remaining) {
    Parcel* parcel = parcel_for_marshall(env, nativePtr);
    if (parcel == NULL) {
       return 0;
    }

    long data_size = ensure_capacity(env, parcel, remaining);
    if (data_size < 0) {
        return 0;
    }

    jbyte* buffer = (jbyte*)env->GetDirectBufferAddress(javaBuffer);
    if (buffer != NULL) {
        memcpy(buffer + offset, parcel->data(), data_size);
    }
    return data_size;
}

static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
                                          jbyteArray data, jint offset, jint length)
{
@@ -613,6 +674,25 @@ static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong native
    }
}

static void android_os_Parcel_unmarshall_buffer(JNIEnv* env, jclass clazz, jlong nativePtr,
                                                jobject javaBuffer, jint offset, jint length)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel == NULL || length < 0) {
       return;
    }

    jbyte* buffer = (jbyte*)env->GetDirectBufferAddress(javaBuffer);
    if (buffer)
    {
        parcel->setDataSize(length);
        parcel->setDataPosition(0);

        void* raw = parcel->writeInplace(length);
        memcpy(raw, (buffer + offset), length);
    }
}

static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisNativePtr,
                                          jlong otherNativePtr)
{
@@ -911,7 +991,10 @@ static const JNINativeMethod gParcelMethods[] = {
    {"nativeDestroy",             "(J)V", (void*)android_os_Parcel_destroy},

    {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
    {"nativeMarshallArray",       "(J[BII)I", (void*)android_os_Parcel_marshall_array},
    {"nativeMarshallBuffer",      "(JLjava/nio/ByteBuffer;II)I", (void*)android_os_Parcel_marshall_buffer},
    {"nativeUnmarshall",          "(J[BII)V", (void*)android_os_Parcel_unmarshall},
    {"nativeUnmarshallBuffer",    "(JLjava/nio/ByteBuffer;II)V", (void*)android_os_Parcel_unmarshall_buffer},
    {"nativeCompareData",         "(JJ)I", (void*)android_os_Parcel_compareData},
    {"nativeCompareDataInRange",  "(JIJII)Z", (void*)android_os_Parcel_compareDataInRange},
    {"nativeAppendFrom",          "(JJII)V", (void*)android_os_Parcel_appendFrom},
+61 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import android.util.Log;

import androidx.test.ext.junit.runners.AndroidJUnit4;

import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -416,4 +418,63 @@ public class ParcelTest {
        int binderEndPos = pA.dataPosition();
        assertTrue(pA.hasBinders(binderStartPos, binderEndPos - binderStartPos));
    }

    private static final byte[] TEST_DATA = new byte[] {4, 8, 15, 16, 23, 42};

    // Allow for some Parcel overhead
    private static final int TEST_DATA_LENGTH = TEST_DATA.length + 100;

    @Test
    public void testMarshall_ByteBuffer_wrapped() {
        ByteBuffer bb = ByteBuffer.allocate(TEST_DATA_LENGTH);
        testMarshall_ByteBuffer(bb);
    }

    @Test
    public void testMarshall_DirectByteBuffer() {
        ByteBuffer bb = ByteBuffer.allocateDirect(TEST_DATA_LENGTH);
        testMarshall_ByteBuffer(bb);
    }

    private void testMarshall_ByteBuffer(ByteBuffer bb) {
        // Ensure that Parcel respects the starting offset by not starting at 0
        bb.position(1);
        bb.mark();

        // Parcel test data, then marshall into the ByteBuffer
        Parcel p1 = Parcel.obtain();
        p1.writeByteArray(TEST_DATA);
        p1.marshall(bb);
        p1.recycle();

        assertTrue(bb.position() > 1);
        bb.reset();

        // Unmarshall test data into a new Parcel
        Parcel p2 = Parcel.obtain();
        bb.reset();
        p2.unmarshall(bb);
        assertTrue(bb.position() > 1);
        p2.setDataPosition(0);
        byte[] marshalled = p2.marshall();

        bb.reset();
        for (int i = 0; i < TEST_DATA.length; i++) {
            assertEquals(bb.get(), marshalled[i]);
        }

        byte[] testDataCopy = new byte[TEST_DATA.length];
        p2.setDataPosition(0);
        p2.readByteArray(testDataCopy);
        for (int i = 0; i < TEST_DATA.length; i++) {
            assertEquals(TEST_DATA[i], testDataCopy[i]);
        }

        // Test that overflowing the buffer throws an exception
        bb.reset();
        // Leave certainly not enough room for the test data
        bb.limit(bb.position() + TEST_DATA.length - 1);
        assertThrows(BufferOverflowException.class, () -> p2.marshall(bb));
        p2.recycle();
    }
}