Understanding the android build process, what is Dalvik(JIT),ART(AOT),D8,R8?

Android Build Process Steps

Some of you might be already aware of JVMs, for those who are not aware, these are just runtime environments to execute java applications. These environments basically helps us in converting the compiled java code to machine code.

Coming to the android side, we can't use he JVM directly since JVMs are designed for machines with high computational power, storage etc. Android devices, when compared with these machines offers limitations in a lot of aspects like small RAM availability, limited storage etc.

In order to make the JVM compatible with android devices, necessary changes where made and hence Dalvik was born. Dalvik continued to be the default runtime environment for android versions till 4.4 kitkat. Dalvik followed JIT based compilation process, which means that code is complied Just - In - Time when the app is opened each time. Here the app gets compiled to machine code each time the app is opened.

Android Runtime replaces Dalvik

The JIT based compilation comes with a lot of disadvantages considering battery drain, app stuttering/lag etc. This lead to the development of a new JVM, which is the The Android Runtime(ART). ART follows Ahead - Of - Time (AOT) based compilation process. As the name suggests, here compilation happens before app start. Here the compilation process happens during the app installation process itself. Even though this lead to higher app installation time, it reduces app lag, increases battery usage efficiency etc. Also the ART environment demands very high app size/storage in comparison with dalvik. But above all ART offers great speed and performance, which is why it was made the default runtime environment for android starting from lollipop onwards.

Even though dalvik was replaced as the default runtime, dalvik bytecode format is still in use(.dex)

A new runtime was introduced in Android Version 7.0 Nougat, which offers a hybrid environment combining features from both a JIT compiler and ART.

Now that we have had a brief understanding of JVM, dalvik,JIT,ART,AOT etc, we will see more about what happens during an android build process.

java bytecode(*.class) 

Take a look at the above diagram, you can see that, at first the java source code is converted into java bytecode using the java compiler(javac). The java bytecode will be having .class extension. This java bytecode is stack based, ie, all variables are stored in a stack.

dex bytecode(*.dex)

Next, the java bytecode(*.class) is then converted into a dex bytecode. This conversion is done using the android dexer, which use to be the historic "dx". But starting from android studio 3.1 onwards, D8 was made the default compiler. D8 produces smaller dex files with better performance when compared with dx. dex files generated with d8 offers significantly higher runtime performance when compared with dx.

The hence obtained dex bytecode undergoes minifying using proguard. The result is still a dex file, but minified. Further this dex file is used to build the apk and finally deployed on an android device.

desugaring and the advent of D8 dexer

Before we go through the D8 dexer in detail we must know what caused its formation. You must have used the jack toolchain briefly which helped us in supporting java 8 language features on android, but it was deprecated because of its direct conversion of source code to dex bytecode.

As a result, android's default toolchain was updated with java 8 language features like the super cool lambdas. Wait.., but the android runtimes(dalvik or ART) won't support java 8 features. Yes, you guessed it correct - it won't, but the updated android toolchain supports a feature just to overcome this big hurdle - Desugaring. Since the android runtime won't support java 8 language features, desugaring can be used to convert java 8 bytecode to java 7 bytecode.

Hence we can now use java 8 features like lambda functions on android.

As i said before, D8 offers significantly higher runtime performance when compared with dx and it also helps in generating smaller apk files. Now we will see how to integrate desugaring with D8. As seen before, in default toolchain, desugaring is a separate step which runs before the android dexer is executed. With D8, we can integrate desugaring with along with it. The integrated desugaring
will further improve the build time

Finally,What is R8?

R8 basically provides all the features offered by D8, but with a lot of add on features. So R8 can be called a successor to D8, but not exactly. Confused? Don't worry, lets see what all features does R8 offers.

Apart from supporting java 8 language features like D8, R8 also enables further optimisation to the dex bytecode. As of now, proguard is run as a separate step in the build process, but R8 provides features like optimisation, obfuscation, remove unused classes etc(which proguard already offers) within itself. Even though R8 only offers a subset of features provided by proguard, now we can perform the entire java/kotlin bytecode to dex bytecode conversion process within a single transformation itself(further improves build time), which is - R8. Hence you must always keep in mind that R8 is not a complete replacement to proguard.

You can enable R8 by adding the following in your app's build.gradle

android {
 buildTypes {
                       release {
                                    useProguard false  
                                              minifyEnabled true
                                    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

1 comment: