G. Blake Meike G. Blake Meike - 7 months ago 26
Java Question

Do DEX and Dalvik support Java binary compatibility?

I am building an Android based system that requires sending data through a binary protocol. I expect there will be many versions of multiple protocols and the nightmare that comes with maintaining them.

It occurs to me that I might be able to sidestep much of the versioning issue, by using Java's binary compatibility.

Suppose that application

A
depends on library
L
.
L
contains a class
C
, used in
A
, that implements interface
I
. I build both
L
and
A
, with definition
I(0)
of the interface
I
. I install
L(0)
, and
A(0)
on a device.
A(0)
dynamically binds
L(0)
which supplies the class
C(0)
.

Now, I extend interface
I
, adding, e.g., two new methods. When I try to compile
L
, the compile fails, because
C
does not implement the new methods. I fix
L
, by extending
C
so it implements the two new methods. I now compile
L(1)
against
I(1)
and install it on the device.

Note that, at this point,
A
will not compile against
I(1)
. None the less, if this were Java,
A(0)
will bind and run, correctly, using
C(1)
from
L(1)
.

This behavior (and more) is guaranteed, for implementations of Java, by JLS Chapter 13, Binary Compatibility. If it holds for DEX and Dalvik, then I can make a large class of protocol changes completely invisible to their clients.

So, the question is, do DEX and Dalvik adhere to the JLS Binary Compatibility spec? If not, is there is there a document the specifies DEX/Dalvik Binary Compatibility?

Answer

I can't speak authoritatively about the current shipping versions of the Dalvik VM (or related runtimes such as ART), but as the designer of the .dex format, I can speak to the intent:

I'm not going to claim I adhered strictly to any spec in the design of the .dex format. What I'll say is that I intended the format to be a suitable container for representation of programs which were originally written in the Java Programming Language, including concerns about cross-code compatibility in an environment of separate code compilation and evolution.

That said (and as I sorta implied) this is an area of implementation which is super easy to get wrong, and in which problems often in practice go undetected for extended periods of time exactly because so few programs actually depend on the kind of guarantees you are interested in.

So, it may not matter what I intended, so much as what the VMs out there in the world actually do. I would strongly recommend testing the various cross-linking and upgrade scenarios explicitly, on several different VMs in the wild. You might find that the results speak against depending on this functionality in your design.