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

Commit 68a3e7a0 authored by Gyumin Sim's avatar Gyumin Sim
Browse files

Limit size of initial Parcel for async binder call

It limits the size of the initial Parcel of ParceledListSlice for async
binder call in MediaSessionRecord and MediaBrowserService. The binder
buffer might be full if multiple large Parcels are sent through async
transaction. ParceledListSlice sends the first part of the list via the
initial Parcel and the rest of the list via another synchronous
transaction in the other direction.

The added CTS tests are supposed to be flaky before this change, but
are stable after this change. It was hard to reproduce failures for the
test added in MediaSessionTest because MediaSession#setQueue is
synchronous binder call to system_server so series of setQueue runs
too slowly to overflow the buffer on the process who is listening
onQueueChanged, while the test added in MediaBrowserServiceTest was
very flaky.

Bug: 37493677
Test: atest CtsMediaTestCases:android.media.cts.MediaSessionTest \
  CtsMediaTestCases:android.media.cts.MediaBrowserServiceTest
Change-Id: I24268637792015dac604550a333d4829d1f0e0a0
parent 31bb4ab9
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -684,8 +684,15 @@ public abstract class MediaBrowserService extends Service {
                List<MediaBrowser.MediaItem> filteredList =
                        (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
                                ? applyOptions(list, options) : list;
                final ParceledListSlice<MediaBrowser.MediaItem> pls =
                        filteredList == null ? null : new ParceledListSlice<>(filteredList);
                final ParceledListSlice<MediaBrowser.MediaItem> pls;
                if (filteredList == null) {
                    pls = null;
                } else {
                    pls = new ParceledListSlice<>(filteredList);
                    // Limit the size of initial Parcel to prevent binder buffer overflow
                    // as onLoadChildren is an async binder call.
                    pls.setInlineCountLimit(1);
                }
                try {
                    connection.callbacks.onLoadChildren(parentId, pls, options);
                } catch (RemoteException ex) {
+10 −2
Original line number Diff line number Diff line
@@ -589,11 +589,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
            if (mDestroyed) {
                return;
            }
            ParceledListSlice<QueueItem> parcelableQueue;
            if (mQueue == null) {
                parcelableQueue = null;
            } else {
                parcelableQueue = new ParceledListSlice<>(mQueue);
                // Limit the size of initial Parcel to prevent binder buffer overflow
                // as onQueueChanged is an async binder call.
                parcelableQueue.setInlineCountLimit(1);
            }
            for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
                ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i);
                try {
                    holder.mCallback.onQueueChanged(mQueue == null ? null :
                            new ParceledListSlice<>(mQueue));
                    holder.mCallback.onQueueChanged(parcelableQueue);
                } catch (DeadObjectException e) {
                    mControllerCallbackHolders.remove(i);
                    logCallbackException("Removing dead callback in pushQueueUpdate", holder, e);