Loading media/java/android/media/session/ISession.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading media/java/android/media/session/MediaSession.java +7 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading media/java/android/media/session/ParcelableListBinder.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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(); } } } services/core/java/com/android/server/media/MediaSessionRecord.java +13 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -905,13 +906,23 @@ 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; Loading Loading
media/java/android/media/session/ISession.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
media/java/android/media/session/MediaSession.java +7 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); } Loading
media/java/android/media/session/ParcelableListBinder.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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(); } } }
services/core/java/com/android/server/media/MediaSessionRecord.java +13 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -905,13 +906,23 @@ 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; Loading