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

Commit f02395e1 authored by Robin Lee's avatar Robin Lee
Browse files

Add parcel exceptions to BaseParceledListSlice

Test: atest ParceledListSliceTest
Bug: 215106618
Change-Id: Ieaee31a0cb2debe08a91b1dd60e42fb97f710806
parent d2b9f813
Loading
Loading
Loading
Loading
+35 −25
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.pm;

import android.compat.annotation.UnsupportedAppUsage;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -92,20 +93,22 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
            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 " + N, e);
                return;
            }
                reply.readException();
                while (i < N && reply.readInt() != 0) {
                    listElementClass = readVerifyAndAddElement(creator, reply, loader,
                            listElementClass);
                    if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
                    i++;
                }
            } catch (RemoteException e) {
                throw new BadParcelableException(
                        "Failure retrieving array; only received " + i + " of " + N, e);
            } finally {
                reply.recycle();
                data.recycle();
            }
        }
    }

    private Class<?> readVerifyAndAddElement(Parcelable.Creator<?> creator, Parcel p,
            ClassLoader loader, Class<?> listElementClass) {
@@ -201,6 +204,8 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
                                    + Binder.getCallingPid() + ", sender=" + this);
                        }

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

@@ -215,8 +220,13 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
                                if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
                                reply.writeInt(0);
                            } else {
                            if (DEBUG) Log.d(TAG, "Transfer complete, clearing mList reference");
                                if (DEBUG) Log.d(TAG, "Transfer done, clearing mList reference");
                                mList = null;
                            }
                        } catch (RuntimeException e) {
                            if (DEBUG) Log.d(TAG, "Transfer failed, clearing mList reference");
                            mList = null;
                            throw e;
                        }
                        return true;
                    }
+65 −0
Original line number Diff line number Diff line
@@ -16,8 +16,11 @@

package android.content.pm;

import static org.junit.Assert.assertThrows;

import android.os.Parcel;
import android.os.Parcelable;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.LargeTest;
@@ -114,6 +117,34 @@ public class ParceledListSliceTest extends TestCase {
        }
    }

    /**
     * Test that exceptions created when parcelling data in the service are really
     * sent to the client and re-thrown.
     */
    public void testThrownException() throws Exception {
        final List<ThrowingObject> throwers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            throwers.add(new ThrowingObject(/* throws= */ false));
        }
        throwers.add(new ThrowingObject(/* throws= */ true));

        final ParceledListSlice<ThrowingObject> src = new ParceledListSlice<>(throwers);
        src.setInlineCountLimit(1);

        Parcel parcel = Parcel.obtain();
        try {
            parcel.writeParcelable(src, 0);
            parcel.setDataPosition(0);

            assertThrows(ServiceSpecificException.class, () -> {
                final ParceledListSlice<ThrowingObject> dst =
                        parcel.readParcelable(getClass().getClassLoader());
            });
        } finally {
            parcel.recycle();
        }
    }

    private void sendParcelStringList(List<String> list) {
        StringParceledListSlice slice;
        Parcel parcel = Parcel.obtain();
@@ -236,6 +267,40 @@ public class ParceledListSliceTest extends TestCase {
        };
    }

    public static class ThrowingObject implements Parcelable {

        private final boolean mShouldThrow;

        public ThrowingObject(boolean shouldThrow) {
            mShouldThrow = shouldThrow;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            if (mShouldThrow) {
                throw new ServiceSpecificException(1234);
            }
            dest.writeBoolean(mShouldThrow);
        }

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

        public static final Creator<ThrowingObject> CREATOR = new Creator<ThrowingObject>() {
            @Override
            public ThrowingObject createFromParcel(Parcel source) {
                return new ThrowingObject(source.readBoolean());
            }

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

    public static class SmallObject extends BaseObject {
        public int mFieldA;
        public int mFieldB;