Thursday, July 4, 2013

Converting classes with the Parcelable protocol

Many good tutorials can be found about the Parcelable protocol in
Android. If the Android framework has to serialize a set of values
(either for AIDL-based IPC or for Intent-based message passing), it can
serialize basic types or objects that implement the Parcelable protocol.
In short, Parcelable objects are able to serialize their states into a
Parcel object and they can retrieve their state from the serialized
form.
But what happens if the two classes (the one which is serializing and
the one which is retrieving its state from serialized form) are not the
same? If you remember my post about classloading in Android, there is no
way loading a class from another APK. If you pass a serialized object
to another application whose codebase comes from a different APK, the
target application has to rely on its own version of the class with the
same name. Android framework does not verify that the sender and
receiving classes are the same, they just have to have the same name
(including package name).

There are two apps in the package. Actually, it is one of my first
example programs, here is the description from a 2007 post of this blog.
There are two applications, intentsender and intentreceiver.
Intentsender has an internal intentreceiver plus it can talk to the
external intentreceiver app. Both applications have a version of
aexp.data.TwoNumbers class. In this example they are just slightly
different - they log different messages.

What happens when you click on the "exp / int" (explicit Intent with
internal intentreceiver) button. Both of these activities are residing
in the intentsender APK therefore the class which will be used to
serialize and deserialize the object are the same.

But if you click on the "exp / ext" (explicit Intent with external
intentreceiver) button, the message has to pass the APK boundary (it is
processed in the intentreceiver app). Intentreceiver has nothing else
but its own version of aexp.data.TwoNumbers. The log demonstrates it:

Android framework did not care that the two TwoNumbers classes were not
the same, it just called them blindly to serialize and deserialize. Actually, if you look into the Parcel implementation, you will see that the serialized version of the Parcelable only stores the fully qualified class name so it is not surprising that intentreceiver loaded whatever version of the class it could find under the given name. Fortunately, the two versions were compatible (they produced and
consumed the same serialized stream) so there were no problems.

Why is this useful other than misleading yourself with classes that look
the same but they aren't? If you want to expose just part of your
serialized object to the receiver application, this trick comes handy.
Otherwise it is best to avoid it.

No comments:

About the blog

This blog is a personal diary about my adventures with the Google Android platform. I write it in the hope that others may find my experiences useful but please, beware. The blog is created as I gain experience about the platform myself so errors, omissions, etc. may be found in the entries.