Obsolete
Status Update
Comments
sa...@google.com <sa...@google.com>
pe...@googlemail.com <pe...@googlemail.com> #2
The issue can be reproduced without even using intents or activities:
Parcel parcel = Parcel.obtain();
// put a custom parcelable class in a bundle
Bundle bundle = new Bundle();
MyCustomParcelable custom = new MyCustomParcelable();
bundle.putParcelable("KEY", custom);
// parcel the bundle itself
bundle.writeToParcel(parcel, 0);
// read the bundle from parcel
parcel.setDataPosition(0);
Bundle bundle2 = Bundle.CREATOR.createFromParcel(parcel);
// read custom parcelable class from bundle again
MyCustomParcelable custom2 = bundle2.getParcelable("KEY");
-> This throws an exception:
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.MyCustomParcelable
at android.os.Parcel.readParcelableCreator(Parcel.java:2536)
at android.os.Parcel.readParcelable(Parcel.java:2462)
at android.os.Parcel.readValue(Parcel.java:2365)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2732)
at android.os.BaseBundle.unparcel(BaseBundle.java:269)
at android.os.Bundle.getParcelable(Bundle.java:864)
-> Workaround:
After bundle2 has been read, but before custom parcelable object is read from bundle2, insert this line:
bundle2.setClassLoader(getClass().getClassLoader());
Parcel parcel = Parcel.obtain();
// put a custom parcelable class in a bundle
Bundle bundle = new Bundle();
MyCustomParcelable custom = new MyCustomParcelable();
bundle.putParcelable("KEY", custom);
// parcel the bundle itself
bundle.writeToParcel(parcel, 0);
// read the bundle from parcel
parcel.setDataPosition(0);
Bundle bundle2 = Bundle.CREATOR.createFromParcel(parcel);
// read custom parcelable class from bundle again
MyCustomParcelable custom2 = bundle2.getParcelable("KEY");
-> This throws an exception:
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.MyCustomParcelable
at android.os.Parcel.readParcelableCreator(Parcel.java:2536)
at android.os.Parcel.readParcelable(Parcel.java:2462)
at android.os.Parcel.readValue(Parcel.java:2365)
at android.os.Parcel.readArrayMapInternal(Parcel.java:2732)
at android.os.BaseBundle.unparcel(BaseBundle.java:269)
at android.os.Bundle.getParcelable(Bundle.java:864)
-> Workaround:
After bundle2 has been read, but before custom parcelable object is read from bundle2, insert this line:
bundle2.setClassLoader(getClass().getClassLoader());
st...@gmail.com <st...@gmail.com> #3
It would be nice, even if this is not fixed quickly, that a google engineer
would explain what is hard in fixing the bug.
Thanks in advance, and thanks a lot for this example @pe..
2018-01-19 9:54 GMT-08:00 <buganizer-system@google.com>:
would explain what is hard in fixing the bug.
Thanks in advance, and thanks a lot for this example @pe..
2018-01-19 9:54 GMT-08:00 <buganizer-system@google.com>:
ju...@gmail.com <ju...@gmail.com> #4
> MyCustomParcelable custom2 = bundle2.getParcelable("KEY");
You're missing a call to setClassLoader() before trying to deserialize the class:
> bundle2.setClassLoader(MyCustomParcelable.class.getClassLoader());
> MyCustomParcelable custom2 = bundle2.getParcelable("KEY");
You're missing a call to setClassLoader() before trying to deserialize the class:
> bundle2.setClassLoader(MyCustomParcelable.class.getClassLoader());
> MyCustomParcelable custom2 = bundle2.getParcelable("KEY");
sa...@google.com <sa...@google.com> #5
Thank you for your feedback. We assure you that we are doing our best to address all issues reported. For now, we will be closing the issue as won't fix obsolete. If this issue currently still exists, we request that you log a new issue along with the bug report here https://goo.gl/TbMiIO and reference this bug for context.
Description
*How to reproduce :
- create an intent, name it innerIntent
- add a custom parcelable class instance to its extras
- create an intent, name it outerIntent
- add innerIntent to the extras of outerIntent
- start a new activity/service with outerIntent, the activity or service CAN EVEN be in the same process
- in the new activity/service, unparcel the innerIntent. An alternative can be to add something inside the innerIntent's extras which will cause the innerIntent bundle to be fully unparceled.
--> The app crashes with a ClassNotFoundException for your custom parcelable.
*Why does it crash ?
We could pinpoint the cause of the bug :
It comes from the method BaseBundle#readFromParcelInner.
This method is invoked when an intent is unparceled in Intent#readFromParcel(Parcel)
This method will invoke mExtras = in.readBundle, which in turn will invoke Parcel#readBundle with a null class loader. Then it invokes the BaseBundle#readFromParcelInner
And in that specific invocation chain, the class loader of the innerIntent's extras is never set (as opposed to all other constructors of the BaseBundle class). Since the class loader is null, it loses the ability to unparcel any custom parcelable class instance that is marshalled inside the bundle.
--> The class loader of extras is lost when (un)parceling an intent.
The workaround is probably to reassign a class loader when deserializing a bundle's intent. But I don't know to what extent the fix would impact IPC scenarios... So I'll leave it to you (the Android Team) ;)