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

Commit bbacfde1 authored by Jooyung Han's avatar Jooyung Han
Browse files

Parcel: add new methods for interface list/array

New methods are to write a list/array of interface objects and to read
them again.

Basically these methods are quite similar to those for IBinder objects.
But when reading IInterface objects, we need to create an array of the
exact type and need a way of converting IBinder into IInterface value.

Two functional interfaces (newArray and asInterface) are just like
while Parcelable.Creator does. We could pass "Stub" class which is
generated by the AIDL compiler and use reflection to create a typed
array instance and call `asInterface` method. But rather than relying on
reflection, passing `IMyInterface[]::new` and
`IMyInterface.Stub::asInterface` would be simple enough to use.

Bug: 205195901
Test: atest -d android.os.cts.ParcelTest
Change-Id: I275db9ebf52d3b9713fa105d81da3a1d289d96a8
parent 8aebd244
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -31427,6 +31427,8 @@ package android.os {
    method @Nullable public double[] createDoubleArray();
    method @Nullable public float[] createFloatArray();
    method @Nullable public int[] createIntArray();
    method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>);
    method @Nullable public <T extends android.os.IInterface> java.util.ArrayList<T> createInterfaceArrayList(@NonNull java.util.function.Function<android.os.IBinder,T>);
    method @Nullable public long[] createLongArray();
    method @Nullable public String[] createStringArray();
    method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList();
@@ -31467,6 +31469,8 @@ package android.os {
    method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
    method public int readInt();
    method public void readIntArray(@NonNull int[]);
    method public <T extends android.os.IInterface> void readInterfaceArray(@NonNull T[], @NonNull java.util.function.Function<android.os.IBinder,T>);
    method public <T extends android.os.IInterface> void readInterfaceList(@NonNull java.util.List<T>, @NonNull java.util.function.Function<android.os.IBinder,T>);
    method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
    method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
    method public long readLong();
@@ -31519,6 +31523,8 @@ package android.os {
    method public void writeFloatArray(@Nullable float[]);
    method public void writeInt(int);
    method public void writeIntArray(@Nullable int[]);
    method public <T extends android.os.IInterface> void writeInterfaceArray(@Nullable T[]);
    method public <T extends android.os.IInterface> void writeInterfaceList(@Nullable java.util.List<T>);
    method public void writeInterfaceToken(@NonNull String);
    method public void writeList(@Nullable java.util.List);
    method public void writeLong(long);
+145 −1
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;

/**
@@ -178,8 +180,12 @@ import java.util.function.Supplier;
 * {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
 * {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
 * {@link #createBinderArray()},
 * {@link #writeInterfaceArray(T[])}, {@link #readInterfaceArray(T[], Function)},
 * {@link #createInterfaceArray(IntFunction, Function)},
 * {@link #writeBinderList(List)}, {@link #readBinderList(List)},
 * {@link #createBinderArrayList()}.</p>
 * {@link #createBinderArrayList()},
 * {@link #writeInterfaceList(List)}, {@link #readInterfaceList(List, Function)},
 * {@link #createInterfaceArrayList(Function)}.</p>
 *
 * <p>FileDescriptor objects, representing raw Linux file descriptor identifiers,
 * can be written and {@link ParcelFileDescriptor} objects returned to operate
@@ -1729,6 +1735,30 @@ public final class Parcel {
        }
    }

    /**
     * Flatten a homogeneous array containing an IInterface type into the parcel,
     * at the current dataPosition() and growing dataCapacity() if needed.  The
     * type of the objects in the array must be one that implements IInterface.
     *
     * @param val The array of objects to be written.
     *
     * @see #createInterfaceArray
     * @see #readInterfaceArray
     * @see IInterface
     */
    public final <T extends IInterface> void writeInterfaceArray(
            @SuppressLint("ArrayReturn") @Nullable T[] val) {
        if (val != null) {
            int N = val.length;
            writeInt(N);
            for (int i=0; i<N; i++) {
                writeStrongInterface(val[i]);
            }
        } else {
            writeInt(-1);
        }
    }

    /**
     * @hide
     */
@@ -1784,6 +1814,50 @@ public final class Parcel {
        }
    }

    /**
     * Read and return a new array of T (IInterface) from the parcel.
     *
     * @return the IInterface array of type T
     * @param newArray a function to create an array of T with a given length
     * @param asInterface a function to convert IBinder object into T (IInterface)
     */
    @SuppressLint({"ArrayReturn", "NullableCollection", "SamShouldBeLast"})
    @Nullable
    public final <T extends IInterface> T[] createInterfaceArray(
            @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
        int N = readInt();
        if (N >= 0) {
            T[] val = newArray.apply(N);
            for (int i=0; i<N; i++) {
                val[i] = asInterface.apply(readStrongBinder());
            }
            return val;
        } else {
            return null;
        }
    }

    /**
     * Read an array of T (IInterface) from a parcel.
     *
     * @param asInterface a function to convert IBinder object into T (IInterface)
     *
     * @throws BadParcelableException Throws BadParcelableException if the length of `val`
     *    mismatches the number of items in the parcel.
     */
    public final <T extends IInterface> void readInterfaceArray(
            @SuppressLint("ArrayReturn") @NonNull T[] val,
            @NonNull Function<IBinder, T> asInterface) {
        int N = readInt();
        if (N == val.length) {
            for (int i=0; i<N; i++) {
                val[i] = asInterface.apply(readStrongBinder());
            }
        } else {
            throw new BadParcelableException("bad array lengths");
        }
    }

    /**
     * Flatten a List containing a particular object type into the parcel, at
     * the current dataPosition() and growing dataCapacity() if needed.  The
@@ -1897,6 +1971,28 @@ public final class Parcel {
        }
    }

    /**
     * Flatten a {@code List} containing T (IInterface) objects into this parcel
     * at the current position. They can later be retrieved with
     * {@link #createInterfaceArrayList} or {@link #readInterfaceList}.
     *
     * @see #createInterfaceArrayList
     * @see #readInterfaceList
     */
    public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) {
        if (val == null) {
            writeInt(-1);
            return;
        }
        int N = val.size();
        int i=0;
        writeInt(N);
        while (i < N) {
            writeStrongInterface(val.get(i));
            i++;
        }
    }

    /**
     * Flatten a {@code List} containing arbitrary {@code Parcelable} objects into this parcel
     * at the current position. They can later be retrieved using
@@ -3379,6 +3475,32 @@ public final class Parcel {
        return l;
    }

    /**
     * Read and return a new ArrayList containing T (IInterface) objects from
     * the parcel that was written with {@link #writeInterfaceList} at the
     * current dataPosition().  Returns null if the
     * previously written list object was null.
     *
     * @return A newly created ArrayList containing T (IInterface)
     *
     * @see #writeInterfaceList
     */
    @SuppressLint({"ConcreteCollection", "NullableCollection"})
    @Nullable
    public final <T extends IInterface> ArrayList<T> createInterfaceArrayList(
            @NonNull Function<IBinder, T> asInterface) {
        int N = readInt();
        if (N < 0) {
            return null;
        }
        ArrayList<T> l = new ArrayList<T>(N);
        while (N > 0) {
            l.add(asInterface.apply(readStrongBinder()));
            N--;
        }
        return l;
    }

    /**
     * Read into the given List items String objects that were written with
     * {@link #writeStringList} at the current dataPosition().
@@ -3421,6 +3543,28 @@ public final class Parcel {
        }
    }

    /**
     * Read into the given List items IInterface objects that were written with
     * {@link #writeInterfaceList} at the current dataPosition().
     *
     * @see #writeInterfaceList
     */
    public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list,
            @NonNull Function<IBinder, T> asInterface) {
        int M = list.size();
        int N = readInt();
        int i = 0;
        for (; i < M && i < N; i++) {
            list.set(i, asInterface.apply(readStrongBinder()));
        }
        for (; i<N; i++) {
            list.add(asInterface.apply(readStrongBinder()));
        }
        for (; i<M; i++) {
            list.remove(N);
        }
    }

    /**
     * Read the list of {@code Parcelable} objects at the current data position into the
     * given {@code list}. The contents of the {@code list} are replaced. If the serialized