2
votes

I have an Android project with gradle. While the gradle plugin was 2.x.x the time to run ./gradlew lint was about 4 minutes. I have upgraded the project to gradle plugin 3.0.1 and now the time is about 24 minutes. I have four flavors and two variants (debug and release). The funny thing is that when I try to run ./gradlew lint[Flavor][Variant] then each of 8 combinations takes about 30 seconds.

Why running lint separately for every flavor and variant takes reasonable amount of time and running one command for all flavors and variants takes more than 20 minutes? What is the difference? Why lint worked with gradle plugin 2.x.x and went retarded after upgrade?

I tried running with --debug flag. lint does some work and then it decides to take a break for a long time and then does some more work. It is idle almost all the build time.

I tried to google something like "(gradle) lint stuck|slow" and it seems that people sometimes have slow gradle builds which could be resolved by enabling offline mode, parallel build, running daemon. But this is not the case here.

The number of issues found is the same in both cases for each combination of flavor and variant

java.lang.OutOfMemoryError: Java heap space
        at com.google.common.io.ByteStreams.createBuffer(ByteStreams.java:56)
        at com.google.common.io.ByteStreams.copy(ByteStreams.java:103)
        at com.google.common.io.ByteStreams.toByteArray(ByteStreams.java:166)
        at com.android.tools.lint.client.api.ClassEntry.addEntries(ClassEntry.java:195)
        at com.android.tools.lint.client.api.ClassEntry.fromClassPath(ClassEntry.java:120)
        at com.android.tools.lint.client.api.LintClient.createSuperClassMap(LintClient.kt:1001)
        at com.android.tools.lint.detector.api.Project.getSuperClassMap(Project.java:1471)
        at com.android.tools.lint.client.api.LintClient.getSuperClass(LintClient.kt:968)
        at com.android.tools.lint.client.api.LintDriver$LintClientWrapper.getSuperClass(LintDriver.kt:2186)
        at com.android.tools.lint.client.api.LintDriver.getSuperClass(LintDriver.kt:1141)
        at com.android.tools.lint.checks.InvalidPackageDetector.checkClass(InvalidPackageDetector.java:173)
        at com.android.tools.lint.client.api.AsmVisitor.runClassDetectors(AsmVisitor.java:151)
        at com.android.tools.lint.client.api.LintDriver.runClassDetectors(LintDriver.kt:1325)
        at com.android.tools.lint.client.api.LintDriver.checkClasses(LintDriver.kt:1210)
        at com.android.tools.lint.client.api.LintDriver.runFileDetectors(LintDriver.kt:1037)
        at com.android.tools.lint.client.api.LintDriver.checkProject(LintDriver.kt:882)
        at com.android.tools.lint.client.api.LintDriver.analyze(LintDriver.kt:385)
        at com.android.tools.lint.LintCliClient.run(LintCliClient.java:155)
        at com.android.build.gradle.internal.LintGradleClient.run(LintGradleClient.java:197)
        at com.android.build.gradle.tasks.LintBaseTask.runLint(LintBaseTask.java:198)
        at com.android.build.gradle.tasks.LintGlobalTask.lintAllVariants(LintGlobalTask.java:91)
        at com.android.build.gradle.tasks.LintGlobalTask.lint(LintGlobalTask.java:70)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:121)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:731)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:705)

This is what is printed before ./gradlew lint finishes. Probably it does some recursion for 20 minutes and when it runs out of memory it gives the result, also I see some blink after a couple of minutes like the results are ready but the task continues for another 20 minutes and the exception terminates it.

2

2 Answers

0
votes

You can see what is different using dry-run, just give -m as an argument with your gradle command

./gradlew lint[Flavor][Variant] -m

./gradlew lint -m

Now you can compare the results of both commands and you can come to know what all gradle tasks are getting executed.

Also for identifying which task is taking most of the time, you can use --profile

./gradlew lint[Flavor][Variant] --profile

./gradlew lint --profile
0
votes
  • ./gradlew lintDebug will run lint with your main sources and debug.
  • ./gradlew lintRelease will run lint with your main sources and release.
  • ./gradlew lint will run all of the variations that there are.
  • ./gradlew lintFlavor1Debug will run lint with your main sources and the debug sources of flavor1.

This goes on. It's mostly about picking the sources (both Java / Kotlin files and also resources) which will be processed to lint for further analysis.

Locally I usually just use ./gradlew lintDebug and on CI which happens in the background I run the full suite ./gradlew lint