diff options
| author | 2020-09-28 07:15:43 +0000 | |
|---|---|---|
| committer | 2020-09-28 07:15:43 +0000 | |
| commit | 7cbdbffe2b8e5419fbc2d2ac234fd61266a615b4 (patch) | |
| tree | ecb16bbe9468cbf33c86c364b21add860d7f3c6b | |
| parent | c50a31f95cbe7c221726b9ccafaedf8a83033ccd (diff) | |
| parent | 52725163a13561e20a6b922eb456e60cdcd48a9f (diff) | |
Merge "Add MediaParceledListSlice as @SystemApi"
| -rw-r--r-- | apex/media/aidl/Android.bp | 10 | ||||
| -rw-r--r-- | apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl | 19 | ||||
| -rw-r--r-- | apex/media/framework/Android.bp | 12 | ||||
| -rw-r--r-- | apex/media/framework/api/module-lib-current.txt | 14 | ||||
| -rw-r--r-- | apex/media/framework/java/android/media/BaseMediaParceledListSlice.java | 215 | ||||
| -rw-r--r-- | apex/media/framework/java/android/media/MediaParceledListSlice.java | 101 | ||||
| -rw-r--r-- | api/module-lib-current.txt | 10 |
7 files changed, 375 insertions, 6 deletions
diff --git a/apex/media/aidl/Android.bp b/apex/media/aidl/Android.bp index 409a04897f56..c2b00d5849c4 100644 --- a/apex/media/aidl/Android.bp +++ b/apex/media/aidl/Android.bp @@ -15,21 +15,21 @@ // filegroup { - name: "stable-mediasession2-aidl-srcs", + name: "stable-media-aidl-srcs", srcs: ["stable/**/*.aidl"], path: "stable", } filegroup { - name: "private-mediasession2-aidl-srcs", + name: "private-media-aidl-srcs", srcs: ["private/**/I*.aidl"], path: "private", } filegroup { - name: "mediasession2-aidl-srcs", + name: "media-aidl-srcs", srcs: [ - ":private-mediasession2-aidl-srcs", - ":stable-mediasession2-aidl-srcs", + ":private-media-aidl-srcs", + ":stable-media-aidl-srcs", ], } diff --git a/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl b/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl new file mode 100644 index 000000000000..92d673fd25cb --- /dev/null +++ b/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +parcelable MediaParceledListSlice<T>; diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index ce4b030467a7..813631e28a88 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -54,9 +54,10 @@ java_library { filegroup { name: "updatable-media-srcs", srcs: [ + ":media-aidl-srcs", + ":mediaparceledlistslice-java-srcs", ":mediaparser-srcs", ":mediasession2-java-srcs", - ":mediasession2-aidl-srcs", ], } @@ -77,6 +78,15 @@ filegroup { } filegroup { + name: "mediaparceledlistslice-java-srcs", + srcs: [ + "java/android/media/MediaParceledListSlice.java", + "java/android/media/BaseMediaParceledListSlice.java", + ], + path: "java", +} + +filegroup { name: "mediaparser-srcs", srcs: [ "java/android/media/MediaParser.java" diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt index d802177e249b..d2826d01664c 100644 --- a/apex/media/framework/api/module-lib-current.txt +++ b/apex/media/framework/api/module-lib-current.txt @@ -1 +1,15 @@ // Signature format: 2.0 +package android.media { + + public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable { + ctor public MediaParceledListSlice(@NonNull java.util.List<T>); + method public int describeContents(); + method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList(); + method public java.util.List<T> getList(); + method public void setInlineCountLimit(int); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR; + } + +} + diff --git a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java new file mode 100644 index 000000000000..fb666098301a --- /dev/null +++ b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java @@ -0,0 +1,215 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is a copied version of BaseParceledListSlice in framework with hidden API usages + * removed. + * + * Transfer a large list of Parcelable objects across an IPC. Splits into + * multiple transactions if needed. + * + * Caveat: for efficiency and security, all elements must be the same concrete type. + * In order to avoid writing the class name of each object, we must ensure that + * each object is the same type, or else unparceling then reparceling the data may yield + * a different result if the class name encoded in the Parcelable is a Base type. + * See b/17671747. + * + * @hide + */ +abstract class BaseMediaParceledListSlice<T> implements Parcelable { + private static String TAG = "BaseMediaParceledListSlice"; + private static boolean DEBUG = false; + + /* + * TODO get this number from somewhere else. For now set it to a quarter of + * the 1MB limit. + */ + // private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes(); + private static final int MAX_IPC_SIZE = 64 * 1024; + + private final List<T> mList; + + private int mInlineCountLimit = Integer.MAX_VALUE; + + public BaseMediaParceledListSlice(List<T> list) { + mList = list; + } + + @SuppressWarnings("unchecked") + BaseMediaParceledListSlice(Parcel p, ClassLoader loader) { + final int N = p.readInt(); + mList = new ArrayList<T>(N); + if (DEBUG) Log.d(TAG, "Retrieving " + N + " items"); + if (N <= 0) { + return; + } + + Parcelable.Creator<?> creator = readParcelableCreator(p, loader); + Class<?> listElementClass = null; + + int i = 0; + while (i < N) { + if (p.readInt() == 0) { + break; + } + + final T parcelable = readCreator(creator, p, loader); + if (listElementClass == null) { + listElementClass = parcelable.getClass(); + } else { + verifySameType(listElementClass, parcelable.getClass()); + } + + mList.add(parcelable); + + if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1)); + i++; + } + if (i >= N) { + return; + } + final IBinder retriever = p.readStrongBinder(); + while (i < N) { + if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever); + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInt(i); + try { + retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); + } catch (RemoteException e) { + Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e); + return; + } + while (i < N && reply.readInt() != 0) { + final T parcelable = readCreator(creator, reply, loader); + verifySameType(listElementClass, parcelable.getClass()); + + mList.add(parcelable); + + if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1)); + i++; + } + reply.recycle(); + data.recycle(); + } + } + + private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) { + if (creator instanceof Parcelable.ClassLoaderCreator<?>) { + Parcelable.ClassLoaderCreator<?> classLoaderCreator = + (Parcelable.ClassLoaderCreator<?>) creator; + return (T) classLoaderCreator.createFromParcel(p, loader); + } + return (T) creator.createFromParcel(p); + } + + private static void verifySameType(final Class<?> expected, final Class<?> actual) { + if (!actual.equals(expected)) { + throw new IllegalArgumentException("Can't unparcel type " + + (actual == null ? null : actual.getName()) + " in list of type " + + (expected == null ? null : expected.getName())); + } + } + + public List<T> getList() { + return mList; + } + + /** + * Set a limit on the maximum number of entries in the array that will be included + * inline in the initial parcelling of this object. + */ + public void setInlineCountLimit(int maxCount) { + mInlineCountLimit = maxCount; + } + + /** + * Write this to another Parcel. Note that this discards the internal Parcel + * and should not be used anymore. This is so we can pass this to a Binder + * where we won't have a chance to call recycle on this. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + final int N = mList.size(); + final int callFlags = flags; + dest.writeInt(N); + if (DEBUG) Log.d(TAG, "Writing " + N + " items"); + if (N > 0) { + final Class<?> listElementClass = mList.get(0).getClass(); + writeParcelableCreator(mList.get(0), dest); + int i = 0; + while (i < N && i < mInlineCountLimit && dest.dataSize() < MAX_IPC_SIZE) { + dest.writeInt(1); + + final T parcelable = mList.get(i); + verifySameType(listElementClass, parcelable.getClass()); + writeElement(parcelable, dest, callFlags); + + if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i)); + i++; + } + if (i < N) { + dest.writeInt(0); + Binder retriever = new Binder() { + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + if (code != FIRST_CALL_TRANSACTION) { + return super.onTransact(code, data, reply, flags); + } + int i = data.readInt(); + if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N); + while (i < N && reply.dataSize() < MAX_IPC_SIZE) { + reply.writeInt(1); + + final T parcelable = mList.get(i); + verifySameType(listElementClass, parcelable.getClass()); + writeElement(parcelable, reply, callFlags); + + if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i)); + i++; + } + if (i < N) { + if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N); + reply.writeInt(0); + } + return true; + } + }; + if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever); + dest.writeStrongBinder(retriever); + } + } + } + + abstract void writeElement(T parcelable, Parcel reply, int callFlags); + + abstract void writeParcelableCreator(T parcelable, Parcel dest); + + abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader); +} diff --git a/apex/media/framework/java/android/media/MediaParceledListSlice.java b/apex/media/framework/java/android/media/MediaParceledListSlice.java new file mode 100644 index 000000000000..e1223f6a6bed --- /dev/null +++ b/apex/media/framework/java/android/media/MediaParceledListSlice.java @@ -0,0 +1,101 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Collections; +import java.util.List; + +/** + * This is a copied version of MediaParceledListSlice in framework with hidden API usages removed, + * and also with some lint error fixed. + * + * Transfer a large list of Parcelable objects across an IPC. Splits into + * multiple transactions if needed. + * + * @see BaseMediaParceledListSlice + * + * TODO: Remove this from @SystemApi once all the MediaSession related classes are moved + * to apex (or ParceledListSlice moved to apex). This class is temporaily added to system API + * for moving classes step by step. + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class MediaParceledListSlice<T extends Parcelable> + extends BaseMediaParceledListSlice<T> { + public MediaParceledListSlice(@NonNull List<T> list) { + super(list); + } + + private MediaParceledListSlice(Parcel in, ClassLoader loader) { + super(in, loader); + } + + @NonNull + public static <T extends Parcelable> MediaParceledListSlice<T> emptyList() { + return new MediaParceledListSlice<T>(Collections.<T> emptyList()); + } + + @Override + public int describeContents() { + int contents = 0; + final List<T> list = getList(); + for (int i=0; i<list.size(); i++) { + contents |= list.get(i).describeContents(); + } + return contents; + } + + @Override + void writeElement(T parcelable, Parcel dest, int callFlags) { + parcelable.writeToParcel(dest, callFlags); + } + + @Override + void writeParcelableCreator(T parcelable, Parcel dest) { + dest.writeParcelableCreator((Parcelable) parcelable); + } + + @Override + Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) { + return from.readParcelableCreator(loader); + } + + @NonNull + @SuppressWarnings("unchecked") + public static final Parcelable.ClassLoaderCreator<MediaParceledListSlice> CREATOR = + new Parcelable.ClassLoaderCreator<MediaParceledListSlice>() { + public MediaParceledListSlice createFromParcel(Parcel in) { + return new MediaParceledListSlice(in, null); + } + + @Override + public MediaParceledListSlice createFromParcel(Parcel in, ClassLoader loader) { + return new MediaParceledListSlice(in, loader); + } + + @Override + public MediaParceledListSlice[] newArray(int size) { + return new MediaParceledListSlice[size]; + } + }; +} diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index 65b29f1a2d37..eb2f26448a69 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -57,6 +57,16 @@ package android.media { ctor public MediaMetadata.Builder(@NonNull android.media.MediaMetadata, @IntRange(from=1) int); } + public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable { + ctor public MediaParceledListSlice(@NonNull java.util.List<T>); + method public int describeContents(); + method @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList(); + method public java.util.List<T> getList(); + method public void setInlineCountLimit(int); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR; + } + } package android.media.session { |