Status Update
Comments
jb...@google.com <jb...@google.com> #2
The needs to be looked at by the desugaring team. Changes in sdk levels should not affect unbundled libraries.
kj...@google.com <kj...@google.com>
mk...@google.com <mk...@google.com>
mk...@google.com <mk...@google.com> #3
Thank you for the report and the reproduction. The reason why this is crashing on 23 and below is due to ViewModelProvider$Factory.create((java.lang.Class, androidx.lifecycle.viewmodel.CreationExtras)
is a default interface method which is not supported older Android Runtimes. D8 therefore has to desugar them by adding methods to all inheriting subclasses. For that to work correctly the entire classpath needs to be passed to D8 for it to compute it correctly.
The class that is missing the desugared create methods is:
Concretely, it is the anonymous class leakcanary/internal/ViewModelClearedWatcher$Companion$install$provider.class
@gavra, to figure out what was going on here I used our compiled dumpinputtodirecty
flag that then for all compilation units emits a zip file containing library classes, classpath classes and program classes. From what I can see, when compilingleakcanary/internal/ViewModelClearedWatcher$Companion$install$provider.class
the classpath does not contain androidx
at all and therefore we cannot see androidx.lifecycle.ViewModelProvider$Factory
and that it has default methods. I've tested in AGP 7.1 and 7.2. Can you see why androidx is not added to classpath?
I've attached the compilation unit (input from gradle to D8) containing leakcanary/internal/ViewModelClearedWatcher$Companion$install$provider.class
and it is bit curious to me that there is only 5 classes here and the remaining leakcanary seems to be in a separate compilation unit.
ga...@google.com <ga...@google.com> #4
The issue is that lifecycle
is not in the runtime classpath for com.squareup.leakcanary:leakcanary-object-watcher-android-androidx:2.8.1
- see
In order to have correct desugaring, we require correct runtime dependency graph information for Maven libraries. This is because dexing happens in artifact transforms where libraries are dexed in parallel with their runtime classpath as dependencies (used to resolve types).
ga...@google.com <ga...@google.com> #6
Both POM file and Gradle metadata (.module) files should be updated to contain runtime dependency on the missing libraries. Updating the Gradle build file for the project should update both of these files, resulting in correct desugaring output.
sg...@google.com <sg...@google.com> #7
py...@squareup.com <py...@squareup.com> #8
The suggested fix is absolutely NOT a proper fix and this bug should still be open.
The issue is that lifecycle is not in the runtime classpath for com.squareup.leakcanary:leakcanary-object-watcher-android-androidx:2.8.1 - see build scan. This should be fixed in leakcanary Gradle build configuration.
It's a common pattern for Java libraries to not declare dependencies and optionally load bytecode at runtime based on the presence of a class. Jetpack does this for Android compatibility layers.
Does this mean desugaring is broken by design for libraries?
xa...@google.com <xa...@google.com> #9
I can see how there is indeed a big issue for optional dependencies on libraries (ie library is setup as compileOnly
). We should really find a way to fix this on the AGP side.
sg...@google.com <sg...@google.com> #10
Maybe I am missing something, but shouldn't leakcanary-object-watcher-android-androidx
have a provided
lifecycle
. If I understand correctly a provided
dependency is on classpath for compilation, but the presence at runtime is not through that dependency. Of course the provided
version and the runtime version (if present) must be compatible.
ga...@google.com <ga...@google.com> #11
The issue is that compileOnly
(provided
for Maven) is not added to the desugaring classpath. Each library is dexed separately, and its runtime classpath (api
, implementation
, runtimeOnly
dependencies) are in the desugaring classpath. E.g if library A has compileOnly dep B and implementation dependency C, only C will be in the desugaring classpath (even if B is in the application's runtime classpath).
Some options to tackle this may be:
- detect if some types are missing while desugaring that we are present in the full classpath, and try to desugar again against the full runtime classpath
- add a feature in Gradle to allow dynamic expansion of runtime classpath with compileOnly dependencies that are present in the resolved configuration
As a temporary workaround, you can also specify android.enableDexingArtifactTransform=false
, but please note that this has a build speed impact.
xa...@google.com <xa...@google.com> #12
We should, at the very least, detect that there are compileOnly
dependencies while desugaring is enabled and warn the users about it. Maybe it should even break unless android.enableDexingArtifactTransform
is set to false
.
We can't keep the setup as is, where the generated output is wrong.
ga...@google.com <ga...@google.com> #13
We were emitting warnings for every missing type, but because libraries ship with JVM and android code in the same jar, some types cannot be resolved correctly for code that's unreachable and users were complaining about the noisy logging, so we downgraded to info.
Using compileOnly
is very common for annotation processors, so disabling artifact transforms in this use case may impact significant number of users unnecessarily.
ga...@google.com <ga...@google.com>
il...@google.com <il...@google.com> #14
FWIW, we've added a workaround in the Lifecycle library for this particular problem in
If testing a fix on the AGP side, make sure to Lifecycle 2.5.0-rc01 or earlier to reproduce this crash as we'll silently be working around the incorrectly generated output on later versions.
to...@gmail.com <to...@gmail.com> #15
However, this solution will no longer be available. This is because this option has been deprecated in AGP 8.0 and will be removed in 8.2.
Could you please postpone the removal of the enableDexingArtifactTransform until the desugar issue regarding compileOnly is resolved?
to...@gmail.com <to...@gmail.com> #16
hu...@google.com <hu...@google.com> #17
Could you please postpone the removal of the enableDexingArtifactTransform until the desugar issue regarding compileOnly is resolved?
Yes, we'll need to fix this issue first before removing the property.
This is puzzling, but in my project, if I enable minify in the app module, desugar seems to run fine even with enableDexingArtifactTransform=true.
That's correct, it's because with minifyEnabled = true
we have a different pipeline which doesn't use dexing transforms.
hu...@google.com <hu...@google.com> #18
Update: Starting with AGP 8.3.0-alpha06, the workaround for this issue is to enable the following property in gradle.properties
:
android.useFullClasspathForDexingTransform = true
For more details on this property, please see
We're not enabling this property by default yet because it has some performance overhead and most projects don't need it.
Next steps:
- Measure the performance impact of enabling this property. (Please let us know if it significantly slows down your build.)
- Measure how many projects need to use this property.
hu...@google.com <hu...@google.com> #19
Downgrading this issue to P2 as there is a workaround & we will address this issue in a future release once we have more data (
z-...@unext.jp <z-...@unext.jp> #20
The workaround android.useFullClasspathForDexingTransform = true
breaks baseline profile generation.
You can simply reproduce it in NowInAndroid. Just add android.useFullClasspathForDexingTransform = true
into gradle.properties
and run ./gradlew :app:generateBaselineProfile
.
It will output many errors like this:
Found multiple transforms that can produce a variant of com.caverock:androidsvg-aar:1.4 with requested attributes:
- artifactType 'android-asm-instrumented-jars'
- com.android.build.api.attributes.AgpVersionAttr '8.3.0'
- com.android.build.api.attributes.BuildTypeAttr 'nonMinifiedRelease'
- com.android.build.api.attributes.ProductFlavor:contentType 'demo'
- org.gradle.category 'library'
- org.gradle.jvm.environment 'android'
- org.gradle.usage 'java-runtime'
- org.jetbrains.kotlin.platform.type 'androidJvm'
Found the following transforms:
- From 'com.caverock:androidsvg-aar:1.4 configuration runtime':
- With source attributes:
- artifactType 'aar'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Candidate transform(s):
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'demoBenchmarkRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'demoDebug'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'demoNonMinifiedRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'demoRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'prodBenchmarkRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'prodDebug'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'prodNonMinifiedRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
- Transform 'AarToClassTransform -> AsmClassesTransform' producing attributes:
- artifactType 'android-asm-instrumented-jars'
- asm-transformed-variant 'prodRelease'
- org.gradle.category 'library'
- org.gradle.libraryelements 'jar'
- org.gradle.status 'release'
- org.gradle.usage 'java-runtime'
The generation will also be failed if you disable this property due to the crash described in this issue. Any way to fix or avoid this error? If not, could you please upgrade this issue?
hu...@google.com <hu...@google.com> #21
Thanks a lot for letting us know!
I've filed
hu...@google.com <hu...@google.com> #22
cc team for visibility: The android.useFullClasspathForDexingTransform = true
flag (java.lang.AbstractMethodError
issues (e.g.,
Description
Lifecycle: 2.5.0-alpha01 - 2.5.0-beta01
Devices/Android versions reproduced on: Emulator & various tablets 5.0 - 11.
If this is a bug in the library, we would appreciate if you could attach:
Anything with a minsdk under API 24 will cause the crash. So it somehow ties into the Java 8, desugaring, and Kotlin interface default methods I think.
Seehttps://github.com/square/leakcanary/issues/2314 for extra details.