public class

ParcelImplListSlice

extends java.lang.Object

 java.lang.Object

↳androidx.media2.common.ParcelImplListSlice

Gradle dependencies

compile group: 'androidx.media2', name: 'media2-common', version: '1.3.0'

  • groupId: androidx.media2
  • artifactId: media2-common
  • version: 1.3.0

Artifact androidx.media2:media2-common:1.3.0 it located at Google repository (https://maven.google.com/)

Overview

Transfer a large list of ParcelImpl objects across an IPC. Splits into multiple transactions if needed. Note: Using this class causes synchronous binder calls in the opposite direction regardless of "oneway" property.

Summary

Fields
public static final <any>CREATOR

Constructors
publicParcelImplListSlice(java.util.List<ParcelImpl> list)

Methods
public intdescribeContents()

public java.util.List<ParcelImpl>getList()

public voidwriteToParcel(Parcel dest, int flags)

Write this to another Parcel.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final <any> CREATOR

Constructors

public ParcelImplListSlice(java.util.List<ParcelImpl> list)

Methods

public java.util.List<ParcelImpl> getList()

public void writeToParcel(Parcel dest, int flags)

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.

public int describeContents()

Source

/*
 * Copyright 2019 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 androidx.media2.common;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import android.annotation.SuppressLint;
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 androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.versionedparcelable.ParcelImpl;

import java.util.ArrayList;
import java.util.List;

/**
 * Transfer a large list of {@link ParcelImpl} objects across an IPC. Splits into
 * multiple transactions if needed.
 *
 * Note: Using this class causes synchronous binder calls in the opposite direction regardless of
 * "oneway" property.
 *
 */
@RestrictTo(LIBRARY_GROUP)
@SuppressLint("BanParcelableUsage")
public class ParcelImplListSlice implements Parcelable {
    private static final String TAG = "ParcelImplListSlice";
    private static final boolean DEBUG = false;

    private static final int MAX_IPC_SIZE = 64 * 1024; // IBinder.MAX_IPC_SIZE
    private static final int INLINE_COUNT_LIMIT = 1;

    final List<ParcelImpl> mList;

    public ParcelImplListSlice(@NonNull List<ParcelImpl> list) {
        if (list == null) {
            throw new NullPointerException("list shouldn't be null");
        }
        mList = list;
    }

    @SuppressWarnings("deprecation")
    ParcelImplListSlice(Parcel p) {
        final int itemCount = p.readInt();
        mList = new ArrayList<>(itemCount);
        if (DEBUG) {
            Log.d(TAG, "Retrieving " + itemCount + " items");
        }
        if (itemCount <= 0) {
            return;
        }

        int i = 0;
        while (i < itemCount) {
            if (p.readInt() == 0) {
                break;
            }

            final ParcelImpl parcelImpl = p.readParcelable(ParcelImpl.class.getClassLoader());
            mList.add(parcelImpl);

            if (DEBUG) {
                Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
            }
            i++;
        }
        if (i >= itemCount) {
            return;
        }
        final IBinder retriever = p.readStrongBinder();
        while (i < itemCount) {
            if (DEBUG) {
                Log.d(TAG, "Reading more @" + i + " of " + itemCount + ": retriever=" + retriever);
            }
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            try {
                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 " + itemCount,
                            e);
                    return;
                }
                while (i < itemCount && reply.readInt() != 0) {
                    final ParcelImpl parcelImpl = reply.readParcelable(
                            ParcelImpl.class.getClassLoader());
                    mList.add(parcelImpl);

                    if (DEBUG) {
                        Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
                    }
                    i++;
                }
            } finally {
                reply.recycle();
                data.recycle();
            }
        }
    }

    public @NonNull List<ParcelImpl> getList() {
        return mList;
    }

    /**
     * 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 itemCount = mList.size();
        dest.writeInt(itemCount);
        if (DEBUG) {
            Log.d(TAG, "Writing " + itemCount + " items");
        }
        if (itemCount > 0) {
            int i = 0;
            while (i < itemCount && i < INLINE_COUNT_LIMIT && dest.dataSize() < MAX_IPC_SIZE) {
                dest.writeInt(1);

                final ParcelImpl parcelable = mList.get(i);
                dest.writeParcelable(parcelable, flags);

                if (DEBUG) {
                    Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
                }
                i++;
            }
            if (i < itemCount) {
                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 " + itemCount);
                        }
                        while (i < itemCount && reply.dataSize() < MAX_IPC_SIZE) {
                            reply.writeInt(1);

                            final ParcelImpl parcelable = mList.get(i);
                            reply.writeParcelable(parcelable, flags);

                            if (DEBUG) {
                                Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
                            }
                            i++;
                        }
                        if (i < itemCount) {
                            if (DEBUG) {
                                Log.d(TAG, "Breaking @" + i + " of " + itemCount);
                            }
                            reply.writeInt(0);
                        }
                        return true;
                    }
                };
                if (DEBUG) {
                    Log.d(TAG, "Breaking @" + i + " of " + itemCount + ": retriever=" + retriever);
                }
                dest.writeStrongBinder(retriever);
            }
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Parcelable.Creator<ParcelImplListSlice> CREATOR =
            new Parcelable.Creator<ParcelImplListSlice>() {
        @Override
        public ParcelImplListSlice createFromParcel(Parcel in) {
            return new ParcelImplListSlice(in);
        }

        @Override
        public ParcelImplListSlice[] newArray(int size) {
            return new ParcelImplListSlice[size];
        }
    };
}