Add parcel exceptions to BaseParceledListSlice

Test: atest ParceledListSliceTest
Bug: 215106618
Change-Id: Ieaee31a0cb2debe08a91b1dd60e42fb97f710806
This commit is contained in:
Robin Lee
2023-01-23 07:31:31 +01:00
parent d2b9f813b9
commit f02395e195
2 changed files with 98 additions and 23 deletions

View File

@@ -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,18 +93,20 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
data.writeInt(i);
try {
retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
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) {
Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
return;
throw new BadParcelableException(
"Failure retrieving array; only received " + i + " of " + N, e);
} finally {
reply.recycle();
data.recycle();
}
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++;
}
reply.recycle();
data.recycle();
}
}
@@ -201,22 +204,29 @@ abstract class BaseParceledListSlice<T> implements Parcelable {
+ Binder.getCallingPid() + ", sender=" + this);
}
while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
reply.writeInt(1);
try {
reply.writeNoException();
while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
reply.writeInt(1);
final T parcelable = mList.get(i);
verifySameType(listElementClass, parcelable.getClass());
writeElement(parcelable, reply, callFlags);
final T parcelable = mList.get(i);
verifySameType(listElementClass, parcelable.getClass());
writeElement(parcelable, reply, callFlags);
if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
i++;
}
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");
if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
i++;
}
if (i < N) {
if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
reply.writeInt(0);
} else {
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;
}

View File

@@ -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;