Process of compiling Android app with Java/Kotlin code

Ban Markovic
6 min readJan 28, 2020

--

Did you ever wonder what the process of compiling your Java/Kotlin code and running application on Android device look like? What happens under the hood?

Well, the goal of this article is to explain the compilation process of an Android app.

As we all know, Android apps can be written in Java and Kotlin programming languages. So the process of Android app compilation is based on the compilation process of Java and Kotlin code (aside from Android environment). Therefor let’s familiarize ourselves with those two processes.

Java code compilation

In order for Java code to run, there are couple of steps which need to be done. For demonstration purpose let’s say we have TestClass.java file which we want to run. The steps for compiling the given file will be the following:

  1. TestClass.java is compiled by javac (Java compiler).
  2. Javac compiles Java source file into Java byte-code file as TestClass.class.
  3. Java byte-code file (TestClass.class) ends up in JVM (Java Virtual Machine).
  4. JVM understands byte-code and converts it into machine code, using JIT (Just-In-Time) compiler.
  5. The machine code is then fed to the memory and executed by computer’s central processing unit.

Generally that is the whole process of running Java code, but I would also like to explain few of the mentioned terms.

  • Java byte-code — representation of Java assembly.
// Java regular code
public int addTwoNumbers(int a, int b) {
return a + b;
}
// Java byte-code equivalent
public int addTwoNumbers(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: ireturn
  • JVM (Java Virtual Machine)— engine which provides runtime environment for execution of Java code.
  • JIT (Just-In-Time) compiler— type of compiler which does the compilation during the execution of a program (compiles the app when user opens it).

With that being said, we can conclude topic regarding Java code compilation.

Kotlin code compilation

By definition, Kotlin is a statically-typed open-source programming language generating code that can run on the JVM.

Java and Kotlin compilation processes

To be able to run on the JVM it needs to compile to Java byte-code. If we check Kotlin’s FAQ, that is exactly what Kotlin compiler does.

What does Kotlin compile down to?

When targeting the JVM, Kotlin produces Java compatible bytecode.

By looking at the left image, we can conclude that the compilation processes of Java and Kotlin are almost the same.

Android compilation process

The main difference between regular Java/Kotlin code compilation and Android compilation process is that Android doesn’t work with JVM (if you wonder why, you can find the answer at the end of the article).

Instead Android decided to create two virtual machines specifically for Android:

  1. DVM (Dalvik Virtual Machine)
  2. ART (Android Runtime) — introduced with the release of Android 4.4 (Kitkat), and before it the runtime environment for Android apps was DVM.

Differences between DVM and ART are described later on in this article.

Regarding their functionalities, ART and Dalvik are compatible runtimes running Dex byte-code which can be found in .dex file.

Now the question arises, from where do we get .dex file?

It turns out, there is one more compiler placed between Java byte-code (.class file) and DVM. Its name is DX (DEX compiler) and its purpose is to convert Java byte-code into Dalvik byte-code.

With that being said, we have all parts for Android compilation process and we can represent it as following

Also it would be interesting to check how Dalvik byte-code looks like. Here is the example of previously mentioned function addTwoNumbers as regular code, its Java byte-code equivalent and its Dalvik byte-code equivalent.

// Java regular code
public int addTwoNumbers(int a, int b) {
return a+ b;
}
// Java byte-code equivalent
public int addTwoNumbers(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: ireturn
// Dalvik byte-code equivalent
.method public addTwoNumbers(II)I
.registers 4
.param p1, "a" # I
.param p2, "b" # I
.line 6
add-int v0, p1, p2
return v0
.end method

At this point we’ve achieved the main goal of this article, we can say that we found the answers to the questions:

  • How does Android compilation process look like?
  • What happens under the hood with Java/Kotlin code?

I really hope that I’ve helped you understand, even a little bit better, Android compilation process.

Still, there are 2 more questions, which I asked myself while learning about compilation process. So as bonus, I would like to familiarize you with them before I finish this article.

  • Why does Android have two virtual machines?
  • And why didn’t Google just use JVM?

DVM vs ART

As mentioned before, ART was built as a replacement for DVM. It was introduced in Android 4.4, Kitkat.

The main improvement was that ART uses AOT (Ahead-Of-Time) compilation, while DVM uses JIT (Just-In-Time).

As explained before, JIT compilation does the compilation during the execution of a program (compiles the app on its startup process). This leads to slower startup time of apps, because it needs to compile app every time user opens it.

On other hand AOT compilation does the compilation when the app is installed. By using on-device dex2oat tool, AOT accepts .dex files as input and generates a compiled app executable for the target device. This can lead to much faster and better app performance. As ART compiles app machine code at its installation, there is no need for translation to machine code every time user opens the app, so AOT doesn’t hit the CPU as hard as Just-In-Time code compiling on Dalvik. Less CPU usage results in less battery drain, which is also important benefit for any Android device.

Apart from AOT compilation, ART brought couple of more improvements to the table: Garbage Collection improvements and Debug and Development improvements. If you would like to learn more about them, you can check out the official documentation.

Why didn’t Google use JVM instead of creating another virtual machine?

There are number of reasons why Google has chosen to abandon the JVM. They knew that Android application runtime must support a diverse set of devices with diverse set of resources, and that applications must be sandboxed for security, performance, and reliability reasons. But a virtual machine-based runtime doesn’t enable all that with limited processor speed and RAM.

As solution of mentioned problems, Google has chosen to abandon the JVM in favor of an alternative deployment target, the Dalvik virtual machine (DVM).

DVM vs JVM

credit to aatul.me

By answering to side questions, I can wrap up this article which followed my process of learning regarding Android compilation process.

Thank you for taking time to read my article. I hope it was helpful and please feel free to comment or give me any feedback regarding the article.

Cheers!

Also I am always open for commenting on Android stuff, so if you feel like talking, contact me on twitter or linkedin.

--

--

Ban Markovic

Android Engineer who writes about his learnings of KMM and Jetpack Compose