Measuring JDK updates for local builds in Android projects
Tags: gradle, java, android, dpe
Published: 2022-12-29 05:00:42

## Context
Latest Android Gradle Plugin 8.0.0-alpha10 requires JDK17 min version for AGP:


![JDK min requirement](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ss2xj3uaa8xzddrayzz.png)

Perfect time to show the potential wins of updating the Java version. Some companies have already moved to newer Java versions, but most of the Android projects are still building with Java 11. This article shows the results of measuring the impact of building with different JDK versions in the project [nowinandroid](https://github.com/android/nowinandroid). We'll focus on incremental changes applied to the project, simulating the local builds.

## nowinandroid
The repository follows development best practices and is intended to be a reference for developers. It's built with Kotlin and Jetpack Compose.

Given the size of the project(27 modules) and the usage of recent build components in Android development, it's a perfect project to apply the scenario we will use to take the measurements.

## Scenario
To measure the impact of the JDK update, we need to create a scenario that is a simulation of incremental changes in the codebase. To create and automate the scenario we use [Gradle Profiler] (https://github.com/gradle/gradle-profiler). Gradle Profiler allows to use different mutations in the incremental scenario, some of them are:

- apply-build-script-change-to
- apply-project-dependency-change-to
- apply-abi-change-to
- apply-non-abi-change-to
- apply-property-resource-change-to
- apply-android-resource-change-to
- apply-android-manifest-change-to

In this article, we will use `apply-abi-change-to` in the module `:core:database`. The position of the module `:core:database` in the dependency graph is:

![Core database position](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69m3q989t7srl6yr2w2g.png)

When we execute the task `assembleDebug` with an incremental change in the module `:core:database`(class NewsRepository), the impact on the build is:

- 22 projects affected
- 462 tasks executed (31%)
- 58 different types of tasks executed.

Those numbers look good and we can replicate a local scenario by applying an incremental change. But before starting the experiment, let's discuss the methodology first.

## Methodology
- We updated nowinandroid to Gradle 7.6 to support JDK 19
- The variants of the experiment are JDK11, JDK17 and JDK19.
- Each variant execution runs a Gradle Profiler scenario with 2 warm-ups and 6 iterations.
- We've used [Gradle Enterprise API] (https://docs.gradle.com/enterprise/api-manual) to retrieve the build information of the build.
- Warm-up builds have been ignored in the results.
- Each variant execution has been repeated 48 times. That means in total, we executed 288 builds per variant. Of course, it's not needed to execute so many builds(10-20 would be enough), but the more significant the sample, the more accurate will be the [results](https://en.wikipedia.org/wiki/Regression_toward_the_mean). 
- Results are based in task execution not build execution. We tend to drive the experiments over the build execution, but I prefer to be more granular and target the components affected by the update. We need to reduce the variability of the builds. For instance, we are not interested in configuration times or potential improvements produced by I/O operations like reading from the local cache. Measuring the Kotlin/Java compiler task times on a Java update will be more significant than considering the overall build.
- To avoid noise in the results, we just considered task types with the aggregated time of 2 seconds per build.

## Results
Following the methodology, only 5 different task types have been considered in the results:

### Gradle base Plugin
#### JavaCompile
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71i3vl0pf6s7xt0gq58v.png)

### Android Gradle Plugin

##### DexMergingTask    

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5upyq0cc6jvfkj30rxzz.png)

#### DexArchiveBuilderTask
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5e3q0kfky7an6py3kcu.png)

#### PackageApplication
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9cyi71yoyml10b4uap4.png)

### Kotlin Gradle Plugin

#### KaptGenerateStubsTask

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc2gltt7fx8lq5ensyuz.png)

#### KaptWithoutKotlincTask
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cl5wwyxj3zkiz7w59rq.png)

### Summary
Collecting all the results, the improvements of updating Java 11 in the project nowinandroid are:

| Type                   | Java 17 | Java 19 |  
|------------------------|---------|---------|
| JavaCompile            |     17% |     19% |   
| DexMergingTask         |      5% |     14% |   
| DexArchiveBuilderTask  |     10% |     12% |   
| PackageApplication     |      1% |      2% |   
| KotlinCompile          |      7% |     13% |   
| KaptGenerateStubsTask  |      5% |     11% |  
| KaptWithoutKotlincTask |     11% |     16% |   

If we group by plugin:

| Plugin                | Java 17 | Java 19 |
|-----------------------|---------|---------|
| Base plugin           |     17% |     19% |
| Android Gradle Plugin |      5% |      9% |
| Kotlin Gradle Plugin  |      8% |     13% |



## Final words
This article showed the potential improvements of updating your Android project with newer Java versions. Of course, the potential win may vary depending on your project and characteristics like number of modules, dependency graph layout or type of build executed by developers. However, we have shown that updating the Java version reduces the task execution of two of the most expensive tasks like Kotlin and Java compilers. 

In terms of the update to Java 17, you have time until the release of AGP 8, but with little effort, you can be ready and improve your team's build times.

Happy new year and Happy building!