OH NIO! What is this system property?
Posted on 2024-01-18

AndroidX wanted to take a dip into a beautiful world of build.gradle.kts after years of using good-ole-speedy-Groovy build.gradle. The smallest step towards that was converting a single build.gradle file and see how that affects our builds, especially the time before the task execution phase. It all looked good locally.

Enter our CI failing with:

The new output:
  Calculating task graph as configuration cache cannot be reused because system property 'idea.io.use.nio2' has changed.

Our log creep detection system spotted a brand-new warning indicating that the task up-to-date validation run (androidx runs our build twice to make sure that tasks do nothing the second time they run). This warning means that we did not have a configuration cache hit the second time Gradle is invoked, and the reason was that there was a change to idea.io.use.nio2 system property. This is bad as it means we unexpectedly rerun the configuration phase in the second invocation making overall build CI slower, but also slowing down AndroidX devs locally in the same way too.

There are two questions that arise: 1. why is AndroidX build reading this system property at configuration time? 2. why is the value of the system property changing?

For where it is being read, Gradle gives you a breadcrumb in configuration cache report: Configuration cache report showing idea.io.use.nio2 being read by PomResolver class

Sadly, this does not give you a stacktrace, so you have to use a debugger with a breakpoint on ConfigurationCacheFingerprintWriter#systemPropertyRead in Gradle to find that PomResolver#resolveEffectivePom from SPDX gradle plugin gets every system property through .putAll(System.getProperties()) call.

JVM Debugger stacktrace showing PomResolver reading nio2 property

The second part, on what sets it and why it only happens in the first build Gradle does not really help you. I quickly did a search through Gradle, Android Gradle Plugin, and Kotlin codebases and spotted setIdeaIoUseFallback and configureKotlinCompilerIoForWindowsSupport that seemed suspect. To confirm my hunch, I attached a debugger with a breakpoint on System.setProperty:

JVM Debugger stacktrace showing setIdeaIoUseFallback setting nio2 property

Gradle only sets this value when it detects usage of build.gradle.kts and it is compiling these scripts. On the second run, the scripts are already compiled, so it never calls this code.

To get out of this situation, we have created an issue for SPDX gradle plugin to remove reading of all properties at configuration time. Ideally, Gradle also would not go toggling properties, as this specific one is a workaround for Windows but is run on other OSes as well.