diff options
Diffstat (limited to 'core/java/android/os/Parcel.java')
| -rw-r--r-- | core/java/android/os/Parcel.java | 83 |
1 files changed, 64 insertions, 19 deletions
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 61882ffcee85..dd0cb8cc62ae 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -2448,9 +2448,9 @@ public final class Parcel { writeByteArray(baos.toByteArray()); } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException writing serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException writing serializable object (name = " + + name + ")", ioe); } } @@ -3818,7 +3818,7 @@ public final class Parcel { break; case VAL_SERIALIZABLE: - object = readSerializable(loader); + object = readSerializableInternal(loader, clazz); break; case VAL_PARCELABLEARRAY: @@ -4144,12 +4144,37 @@ public final class Parcel { * wasn't found in the parcel. */ @Nullable - public final Serializable readSerializable() { - return readSerializable(null); + public Serializable readSerializable() { + return readSerializableInternal(/* loader */ null, /* clazz */ null); } + /** + * Same as {@link #readSerializable()} but accepts {@code loader} parameter + * as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter + * as the required type. + * + * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized + * is not an instance of that class or any of its children class or there there was an error + * deserializing the object. + */ @Nullable - private final Serializable readSerializable(@Nullable final ClassLoader loader) { + public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader, + @NonNull Class<T> clazz) { + Objects.requireNonNull(clazz); + return readSerializableInternal(loader, clazz); + } + + /** + * @param clazz The type of the serializable expected or {@code null} for performing no checks + */ + @Nullable + private <T> T readSerializableInternal(@Nullable final ClassLoader loader, + @Nullable Class<T> clazz) { + if (clazz != null && !Serializable.class.isAssignableFrom(clazz)) { + throw new BadParcelableException("About to unparcel a serializable object " + + " but class required " + clazz.getName() + " is not Serializable"); + } + String name = readString(); if (name == null) { // For some reason we were unable to read the name of the Serializable (either there @@ -4158,9 +4183,20 @@ public final class Parcel { return null; } - byte[] serializedData = createByteArray(); - ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); try { + if (clazz != null && loader != null) { + // If custom classloader is provided, resolve the type of serializable using the + // name, then check the type before deserialization. As in this case we can resolve + // the class the same way as ObjectInputStream, using the provided classloader. + Class<?> cl = Class.forName(name, false, loader); + if (!clazz.isAssignableFrom(cl)) { + throw new BadParcelableException("Serializable object " + + cl.getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + byte[] serializedData = createByteArray(); + ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); ObjectInputStream ois = new ObjectInputStream(bais) { @Override protected Class<?> resolveClass(ObjectStreamClass osClass) @@ -4168,22 +4204,31 @@ public final class Parcel { // try the custom classloader if provided if (loader != null) { Class<?> c = Class.forName(osClass.getName(), false, loader); - if (c != null) { - return c; - } + return Objects.requireNonNull(c); } return super.resolveClass(osClass); } }; - return (Serializable) ois.readObject(); + T object = (T) ois.readObject(); + if (clazz != null && loader == null) { + // If custom classloader is not provided, check the type of the serializable using + // the deserialized object, as we cannot resolve the class the same way as + // ObjectInputStream. + if (!clazz.isAssignableFrom(object.getClass())) { + throw new BadParcelableException("Serializable object " + + object.getClass().getName() + " is not a subclass of required class " + + clazz.getName() + " provided in the parameter"); + } + } + return object; } catch (IOException ioe) { - throw new RuntimeException("Parcelable encountered " + - "IOException reading a Serializable object (name = " + name + - ")", ioe); + throw new BadParcelableException("Parcelable encountered " + + "IOException reading a Serializable object (name = " + + name + ")", ioe); } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("Parcelable encountered " + - "ClassNotFoundException reading a Serializable object (name = " - + name + ")", cnfe); + throw new BadParcelableException("Parcelable encountered " + + "ClassNotFoundException reading a Serializable object (name = " + + name + ")", cnfe); } } |
