From b67fc383553b2a3315ad09e0396a6d76d046fce7 Mon Sep 17 00:00:00 2001 From: Hao Ke Date: Mon, 22 Nov 2021 16:24:56 +0000 Subject: [PATCH] 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 --- core/api/current.txt | 1 + core/java/android/os/Parcel.java | 43 +++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index a70a0a9042905..9f622dc8686b4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31513,6 +31513,7 @@ package android.os { method @Deprecated @Nullable public android.os.Parcelable.Creator readParcelableCreator(@Nullable ClassLoader); method @Nullable public android.os.Parcelable.Creator readParcelableCreator(@Nullable ClassLoader, @NonNull Class); method @NonNull public java.util.List readParcelableList(@NonNull java.util.List, @Nullable ClassLoader); + method @NonNull public java.util.List readParcelableList(@NonNull java.util.List, @Nullable ClassLoader, @NonNull Class); method @Nullable public android.os.PersistableBundle readPersistableBundle(); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Deprecated @Nullable public java.io.Serializable readSerializable(); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 7bdb6b90c07b8..afd0ff747b93c 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -3650,22 +3650,47 @@ public final class Parcel { @NonNull public final List readParcelableList(@NonNull List 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 List readParcelableList(@NonNull List list, + @Nullable ClassLoader cl, @NonNull Class 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 List readParcelableListInternal(@NonNull List list, + @Nullable ClassLoader cl, @Nullable Class 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