From 03c34f57c05feecfb090de3917787f049cb5f804 Mon Sep 17 00:00:00 2001 From: Hani Kazmi Date: Tue, 7 Jun 2022 16:52:57 +0000 Subject: [PATCH] Parcel.java: Fix bug where non-nested creators threw NullPointer Upon deserialization, various APIs would check that the passed in class was assignable from the creator's enclosing class - which was assumed to always be the Parcelable type. This assumption is not always true, so updating the check to explicitely store the parcelable type Fix: 232589966 Test: m && atest ParcelTest && atest BundleTest Change-Id: I59b650a854944e9020615a65798c5e54f5540aaa --- core/java/android/os/Parcel.java | 49 +++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 40e6780854450..9649d3875342b 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -33,6 +33,7 @@ import android.util.ArraySet; import android.util.ExceptionUtils; import android.util.Log; import android.util.MathUtils; +import android.util.Pair; import android.util.Size; import android.util.SizeF; import android.util.Slog; @@ -4858,28 +4859,36 @@ public final class Parcel { if (name == null) { return null; } - Parcelable.Creator creator; - HashMap> map; - synchronized (mCreators) { - map = mCreators.get(loader); + + Pair, Class> creatorAndParcelableClass; + synchronized (sPairedCreators) { + HashMap, Class>> map = + sPairedCreators.get(loader); if (map == null) { - map = new HashMap<>(); - mCreators.put(loader, map); + sPairedCreators.put(loader, new HashMap<>()); + mCreators.put(loader, new HashMap<>()); + creatorAndParcelableClass = null; + } else { + creatorAndParcelableClass = map.get(name); } - creator = map.get(name); } - if (creator != null) { + + if (creatorAndParcelableClass != null) { + Parcelable.Creator creator = creatorAndParcelableClass.first; + Class parcelableClass = creatorAndParcelableClass.second; if (clazz != null) { - Class parcelableClass = creator.getClass().getEnclosingClass(); if (!clazz.isAssignableFrom(parcelableClass)) { throw new BadTypeParcelableException("Parcelable creator " + name + " is not " + "a subclass of required class " + clazz.getName() + " provided in the parameter"); } } + return (Parcelable.Creator) creator; } + Parcelable.Creator creator; + Class parcelableClass; try { // If loader == null, explicitly emulate Class.forName(String) "caller // classloader" behavior. @@ -4887,7 +4896,7 @@ public final class Parcel { (loader == null ? getClass().getClassLoader() : loader); // Avoid initializing the Parcelable class until we know it implements // Parcelable and has the necessary CREATOR field. http://b/1171613. - Class parcelableClass = Class.forName(name, false /* initialize */, + parcelableClass = Class.forName(name, false /* initialize */, parcelableClassLoader); if (!Parcelable.class.isAssignableFrom(parcelableClass)) { throw new BadParcelableException("Parcelable protocol requires subclassing " @@ -4934,8 +4943,9 @@ public final class Parcel { + "CREATOR on class " + name); } - synchronized (mCreators) { - map.put(name, creator); + synchronized (sPairedCreators) { + sPairedCreators.get(loader).put(name, Pair.create(creator, parcelableClass)); + mCreators.get(loader).put(name, creator); } return (Parcelable.Creator) creator; @@ -5086,12 +5096,17 @@ public final class Parcel { } } - // Cache of previously looked up CREATOR.createFromParcel() methods for - // particular classes. Keys are the names of the classes, values are - // Method objects. + + // Left due to the UnsupportedAppUsage. Do not use anymore - use sPairedCreators instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) - private static final HashMap>> - mCreators = new HashMap<>(); + private static final HashMap>> + mCreators = new HashMap<>(); + + // Cache of previously looked up CREATOR.createFromParcel() methods for particular classes. + // Keys are the names of the classes, values are a pair consisting of a parcelable creator, + // and the class of the parcelable type for the object. + private static final HashMap, Class>>> sPairedCreators = new HashMap<>(); /** @hide for internal use only. */ static protected final Parcel obtain(int obj) {