Adding typed Parcel readParcelableList API.

Added typed Parcel readParcelableList API that takes extra clazz
parameters check that the class written on the wire is the same,
or a descendant from the one provided as the key and value arguments.

Doing so could enhance the security of Parcel deserialization,
as it would prevent unexpected types of objects being deserialized.
More details can be found at go/safer-parcel.

Test: atest -d android.os.cts.ParcelTest
Bug: 195622897
Change-Id: Ibdb90fa622ef6eaa0bd2b9de629f51fc4fa7091a
This commit is contained in:
Hao Ke
2021-11-22 16:24:56 +00:00
parent 92a4b54de5
commit b67fc38355
2 changed files with 35 additions and 9 deletions

View File

@@ -31513,6 +31513,7 @@ package android.os {
method @Deprecated @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
method @NonNull public <T> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader, @NonNull Class<T>);
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
method @Deprecated @Nullable public java.io.Serializable readSerializable();

View File

@@ -3650,22 +3650,47 @@ public final class Parcel {
@NonNull
public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl) {
final int N = readInt();
if (N == -1) {
return readParcelableListInternal(list, cl, /*clazz*/ null);
}
/**
* Same as {@link #readParcelableList(List, ClassLoader)} but accepts {@code clazz} parameter as
* the type required for each item.
*
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children classes or there was an error
* trying to instantiate an element.
*/
@NonNull
public <T> List<T> readParcelableList(@NonNull List<T> list,
@Nullable ClassLoader cl, @NonNull Class<T> clazz) {
Objects.requireNonNull(list);
Objects.requireNonNull(clazz);
return readParcelableListInternal(list, cl, clazz);
}
/**
* @param clazz The type of the object expected or {@code null} for performing no checks.
*/
@NonNull
private <T> List<T> readParcelableListInternal(@NonNull List<T> list,
@Nullable ClassLoader cl, @Nullable Class<T> clazz) {
final int n = readInt();
if (n == -1) {
list.clear();
return list;
}
final int M = list.size();
final int m = list.size();
int i = 0;
for (; i < M && i < N; i++) {
list.set(i, (T) readParcelable(cl));
for (; i < m && i < n; i++) {
list.set(i, (T) readParcelableInternal(cl, clazz));
}
for (; i<N; i++) {
list.add((T) readParcelable(cl));
for (; i < n; i++) {
list.add((T) readParcelableInternal(cl, clazz));
}
for (; i<M; i++) {
list.remove(N);
for (; i < m; i++) {
list.remove(n);
}
return list;
}