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

Commit 122a8ec2 authored by Tim Murray's avatar Tim Murray
Browse files

BaseParceledListSlice: remove List reference once transfer completes

Currently, BaseParceledListSlice will hold a reference to the List<>
until the Binder object is destroyed. However, this requires that the
receiver run GC before the sender's global Binder reference can be
removed, causing the List to be retained until both receiver and
sender perform GC. Since the List is usually the large part of the
object, instead clear the reference to the List once the transfer to
the receiver completes, allowing the List to be GC'd before the
receiver GC's its reference to the sender's Binder object.

Test: boots
Bug: 213236807
Change-Id: I22d6e56c953db3c85179911b909d5b6e7c8ba784
parent 3b5acfe2
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -50,10 +50,12 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
     */
    private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();

    private final List<T> mList;
    private List<T> mList;

    private int mInlineCountLimit = Integer.MAX_VALUE;

    private boolean mHasBeenParceled = false;

    public BaseParceledListSlice(List<T> list) {
        mList = list;
    }
@@ -151,9 +153,17 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
     * 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.
     *
     * This method can only be called once per BaseParceledListSlice to ensure that
     * the referenced list can be cleaned up before the recipient cleans up the
     * Binder reference.
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        if (mHasBeenParceled) {
            throw new IllegalStateException("Can't Parcel a ParceledListSlice more than once");
        }
        mHasBeenParceled = true;
        final int N = mList.size();
        final int callFlags = flags;
        dest.writeInt(N);
@@ -180,9 +190,17 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
                            throws RemoteException {
                        if (code != FIRST_CALL_TRANSACTION) {
                            return super.onTransact(code, data, reply, flags);
                        } else if (mList == null) {
                            throw new IllegalArgumentException("Attempt to transfer null list, "
                                    + "did transfer finish?");
                        }
                        int i = data.readInt();
                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);

                        if (DEBUG) {
                            Log.d(TAG, "Writing more @" + i + " of " + N + " to "
                                    + Binder.getCallingPid() + ", sender=" + this);
                        }

                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
                            reply.writeInt(1);

@@ -196,6 +214,9 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
                        if (i < N) {
                            if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
                            reply.writeInt(0);
                        } else {
                            if (DEBUG) Log.d(TAG, "Transfer complete, clearing mList reference");
                            mList = null;
                        }
                        return true;
                    }