summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/session/ISession.aidl3
-rw-r--r--media/java/android/media/session/MediaSession.java9
-rw-r--r--media/java/android/media/session/ParcelableListBinder.java131
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java15
4 files changed, 153 insertions, 5 deletions
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 21378c80fd56..77f7b54368f8 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -41,7 +41,8 @@ interface ISession {
// These commands are for the TransportPerformer
void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
void setPlaybackState(in PlaybackState state);
- void setQueue(in ParceledListSlice queue);
+ void resetQueue();
+ IBinder getBinderForSetQueue();
void setQueueTitle(CharSequence title);
void setExtras(in Bundle extras);
void setRatingType(int type);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 70bd1609ddbd..6c41f7bcd0bc 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -25,7 +25,6 @@ import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
@@ -36,6 +35,7 @@ import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -491,7 +491,12 @@ public final class MediaSession {
*/
public void setQueue(@Nullable List<QueueItem> queue) {
try {
- mBinder.setQueue(queue == null ? null : new ParceledListSlice(queue));
+ if (queue == null) {
+ mBinder.resetQueue();
+ } else {
+ IBinder binder = mBinder.getBinderForSetQueue();
+ ParcelableListBinder.send(binder, queue);
+ }
} catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
diff --git a/media/java/android/media/session/ParcelableListBinder.java b/media/java/android/media/session/ParcelableListBinder.java
new file mode 100644
index 000000000000..a7aacf2d8fca
--- /dev/null
+++ b/media/java/android/media/session/ParcelableListBinder.java
@@ -0,0 +1,131 @@
+/*
+ * 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.session;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Binder to receive a list that has a large number of {@link Parcelable} items.
+ *
+ * It's similar to {@link android.content.pm.ParceledListSlice}, but transactions are performed in
+ * the opposite direction.
+ *
+ * @param <T> the type of {@link Parcelable}
+ * @hide
+ */
+public class ParcelableListBinder<T extends Parcelable> extends Binder {
+
+ private static final int SUGGESTED_MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
+
+ private static final int END_OF_PARCEL = 0;
+ private static final int ITEM_CONTINUED = 1;
+
+ private final Consumer<List<T>> mConsumer;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final List<T> mList = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private int mCount;
+
+ @GuardedBy("mLock")
+ private boolean mConsumed;
+
+ /**
+ * Creates an instance.
+ *
+ * @param consumer a consumer that consumes the list received
+ */
+ public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) {
+ mConsumer = consumer;
+ }
+
+ @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);
+ }
+ List<T> listToBeConsumed;
+ synchronized (mLock) {
+ if (mConsumed) {
+ return false;
+ }
+ int i = mList.size();
+ if (i == 0) {
+ mCount = data.readInt();
+ }
+ while (i < mCount && data.readInt() != END_OF_PARCEL) {
+ mList.add(data.readParcelable(null));
+ i++;
+ }
+ if (i >= mCount) {
+ listToBeConsumed = mList;
+ mConsumed = true;
+ } else {
+ listToBeConsumed = null;
+ }
+ }
+ if (listToBeConsumed != null) {
+ mConsumer.accept(listToBeConsumed);
+ }
+ return true;
+ }
+
+ /**
+ * Sends a list of {@link Parcelable} to a binder.
+ *
+ * @param binder a binder interface backed by {@link ParcelableListBinder}
+ * @param list a list to send
+ */
+ public static <T extends Parcelable> void send(@NonNull IBinder binder, @NonNull List<T> list)
+ throws RemoteException {
+ int count = list.size();
+ int i = 0;
+ while (i < count) {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ if (i == 0) {
+ data.writeInt(count);
+ }
+ while (i < count && data.dataSize() < SUGGESTED_MAX_IPC_SIZE) {
+ data.writeInt(ITEM_CONTINUED);
+ data.writeParcelable(list.get(i), 0);
+ i++;
+ }
+ if (i < count) {
+ data.writeInt(END_OF_PARCEL);
+ }
+ binder.transact(FIRST_CALL_TRANSACTION, data, reply, 0);
+ reply.recycle();
+ data.recycle();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 8777ceacf884..1e02f49c43e4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -36,6 +36,7 @@ import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
+import android.media.session.ParcelableListBinder;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
@@ -905,14 +906,24 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
- public void setQueue(ParceledListSlice queue) throws RemoteException {
+ public void resetQueue() throws RemoteException {
synchronized (mLock) {
- mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
+ mQueue = null;
}
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
}
@Override
+ public IBinder getBinderForSetQueue() throws RemoteException {
+ return new ParcelableListBinder<QueueItem>((list) -> {
+ synchronized (mLock) {
+ mQueue = list;
+ }
+ mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
+ });
+ }
+
+ @Override
public void setQueueTitle(CharSequence title) throws RemoteException {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);