Check desugar_jdk_libs version and flavor
Bug: 289401250
Test: CheckAarMetadataTaskTest
Change-Id: I1938170192a3d95931d7f9eb72c42c74f5ce8e70
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTask.kt
index 9616755..efc8466 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTask.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTask.kt
@@ -18,6 +18,7 @@
import com.android.SdkConstants.AAR_FORMAT_VERSION_PROPERTY
import com.android.SdkConstants.AAR_METADATA_VERSION_PROPERTY
import com.android.SdkConstants.CORE_LIBRARY_DESUGARING_ENABLED_PROPERTY
+import com.android.SdkConstants.DESUGAR_JDK_LIB_PROPERTY
import com.android.SdkConstants.FORCE_COMPILE_SDK_PREVIEW_PROPERTY
import com.android.SdkConstants.MIN_ANDROID_GRADLE_PLUGIN_VERSION_PROPERTY
import com.android.SdkConstants.MIN_COMPILE_SDK_EXTENSION_PROPERTY
@@ -30,6 +31,9 @@
import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction
import com.android.build.gradle.internal.ide.dependencies.getIdString
import com.android.build.gradle.internal.tasks.AarMetadataTask.Companion.DEFAULT_MIN_COMPILE_SDK_EXTENSION
+import com.android.build.gradle.internal.utils.checkDesugarJdkVariant
+import com.android.build.gradle.internal.utils.checkDesugarJdkVersion
+import com.android.build.gradle.internal.utils.getDesugarLibDependencyGraph
import com.android.build.gradle.internal.utils.parseTargetHash
import com.android.build.gradle.internal.utils.setDisallowChanges
import com.android.build.gradle.options.BooleanOption
@@ -42,7 +46,9 @@
import org.gradle.api.artifacts.ArtifactCollection
import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
+import org.gradle.api.artifacts.component.ModuleComponentSelector
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
+import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.ListProperty
@@ -102,6 +108,10 @@
@get:Input
abstract val coreLibraryDesugaringEnabled: Property<Boolean>
+ @get:Input
+ @get:Optional
+ abstract val desugarJdkLibDependencyGraph: Property<ResolvedComponentResult>
+
// platformSdkExtension is the actual extension level of the platform, if specified within the
// SDK directory. This value is used if the extension level is not specified in the
// compileSdkVersion hash string.
@@ -152,6 +162,12 @@
)
it.projectPath.set(projectPath)
it.disableCompileSdkChecks.set(disableCompileSdkChecks)
+ desugarJdkLibDependencyGraph.orNull?.dependencies?.firstOrNull()?.requested?.let { id ->
+ if (id is ModuleComponentSelector) {
+ it.desugarJdkVariant.set(id.module)
+ it.desugarJdkVersion.set(id.version)
+ }
+ }
}
}
@@ -193,6 +209,11 @@
creationConfig.global.compileOptions.isCoreLibraryDesugaringEnabled
}
task.coreLibraryDesugaringEnabled.setDisallowChanges(coreLibraryDesugaringEnabled)
+ if (coreLibraryDesugaringEnabled) {
+ task.desugarJdkLibDependencyGraph.set(
+ getDesugarLibDependencyGraph(creationConfig.services)
+ )
+ }
task.maxRecommendedStableCompileSdkVersionForThisAgp.setDisallowChanges(
ToolsRevisionUtils.MAX_RECOMMENDED_COMPILE_SDK_VERSION.apiLevel
)
@@ -515,6 +536,30 @@
""".trimIndent()
)
}
+
+ aarMetadataReader.desugarJdkLibId?.split(":")?.also {
+ check(it.size == 3) { "Unexpected desugarJdkLib ID format from AAR metadata"}
+ val variantFromAar = it[1]
+ val versionFromAar = it[2]
+
+ if (parameters.desugarJdkVariant.isPresent
+ && parameters.desugarJdkVersion.isPresent) {
+ checkDesugarJdkVariant(
+ variantFromAar,
+ parameters.desugarJdkVariant.get(),
+ errorMessages,
+ displayName,
+ parameters.projectPath.get()
+ )
+ checkDesugarJdkVersion(
+ versionFromAar,
+ parameters.desugarJdkVersion.get(),
+ errorMessages,
+ displayName,
+ parameters.projectPath.get()
+ )
+ }
+ }
}
}
@@ -537,6 +582,12 @@
// task).
throw RuntimeException("Unsupported target hash: $sdkVersion")
}
+
+ enum class DesugarJdkVariant(val size: Int) {
+ MINIMAL(0),
+ BASIC(1),
+ NIO(2);
+ }
}
/** [WorkParameters] for [CheckAarMetadataWorkAction] */
@@ -546,6 +597,8 @@
abstract val aarMetadataVersion: Property<String>
abstract val compileSdkVersion: Property<String>
abstract val coreLibraryDesugaringEnabled: Property<Boolean>
+ abstract val desugarJdkVariant: Property<String>
+ abstract val desugarJdkVersion: Property<String>
abstract val platformSdkExtension: Property<Int>
abstract val platformSdkApiLevel: Property<Int>
abstract val agpVersion: Property<String>
@@ -563,6 +616,7 @@
val forceCompileSdkPreview: String?
val minCompileSdkExtension: String?
val coreLibraryDesugaringEnabled: String?
+ val desugarJdkLibId: String?
constructor(file: File) : this(file.inputStream())
@@ -576,6 +630,7 @@
forceCompileSdkPreview = properties.getProperty(FORCE_COMPILE_SDK_PREVIEW_PROPERTY)
minCompileSdkExtension = properties.getProperty(MIN_COMPILE_SDK_EXTENSION_PROPERTY)
coreLibraryDesugaringEnabled = properties.getProperty(CORE_LIBRARY_DESUGARING_ENABLED_PROPERTY)
+ desugarJdkLibId = properties.getProperty(DESUGAR_JDK_LIB_PROPERTY)
}
}
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/AarMetadataCheck.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/AarMetadataCheck.kt
new file mode 100644
index 0000000..b9ed26e
--- /dev/null
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/AarMetadataCheck.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.build.gradle.internal.utils
+
+import com.android.build.gradle.internal.tasks.CheckAarMetadataWorkAction
+import com.android.repository.Revision
+
+/**
+ * Utils for checking desugar library requirements from AAR metadata
+ */
+
+fun checkDesugarJdkVariant(
+ variantFromAar: String,
+ variantFromConsumer: String,
+ errorMessages: MutableList<String>,
+ dependency: String,
+ projectPath: String,
+) {
+ val parsedVariantFromAar = parseDesugarJdkVariant(variantFromAar)
+ val parsedVariantFromConsumer = parseDesugarJdkVariant(variantFromConsumer)
+ if (parsedVariantFromAar.size > parsedVariantFromConsumer.size) {
+ errorMessages.add(
+ """
+ Dependency '$dependency' requires desugar_jdk_libs flavor to be at least
+ $variantFromAar for $projectPath, which is currently $variantFromConsumer
+
+ See https://d.android.com/r/tools/api-desugaring-flavors
+ for more details.
+ """.trimIndent()
+ )
+ }
+}
+
+fun checkDesugarJdkVersion(
+ versionFromAar: String,
+ versionFromConsumer: String,
+ errorMessages: MutableList<String>,
+ dependency: String,
+ projectPath: String,
+) {
+ val parsedVersionFromAar = Revision.parseRevision(versionFromAar)
+ val parsedVersionFromConsumer = Revision.parseRevision(versionFromConsumer)
+ if (parsedVersionFromAar > parsedVersionFromConsumer) {
+ errorMessages.add(
+ """
+ Dependency '$dependency' requires desugar_jdk_libs version to be
+ $versionFromAar or above for $projectPath, which is currently $versionFromConsumer
+
+ See https://d.android.com/studio/build/library-desugaring for more
+ details.
+ """.trimIndent()
+ )
+ }
+}
+
+private fun parseDesugarJdkVariant(variant: String): CheckAarMetadataWorkAction.DesugarJdkVariant {
+ return when(variant) {
+ DESUGAR_JDK_LIBS_MINIMAL -> CheckAarMetadataWorkAction.DesugarJdkVariant.MINIMAL
+ DESUGAR_JDK_LIBS -> CheckAarMetadataWorkAction.DesugarJdkVariant.BASIC
+ DESUGAR_JDK_LIBS_NIO -> CheckAarMetadataWorkAction.DesugarJdkVariant.NIO
+ else -> throw RuntimeException("Failed to parse desugar_jdk_libs variant from" +
+ " desugarJdkLib property of AAR metadata: unknown variant")
+ }
+}
+
+const val DESUGAR_JDK_LIBS_MINIMAL = "desugar_jdk_libs_minimal"
+const val DESUGAR_JDK_LIBS = "desugar_jdk_libs"
+const val DESUGAR_JDK_LIBS_NIO = "desugar_jdk_libs_nio"
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeModuleComponentSelector.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeModuleComponentSelector.kt
new file mode 100644
index 0000000..565b46e
--- /dev/null
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/fixtures/FakeModuleComponentSelector.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.build.gradle.internal.fixtures
+
+import org.gradle.api.artifacts.ModuleIdentifier
+import org.gradle.api.artifacts.VersionConstraint
+import org.gradle.api.artifacts.component.ComponentIdentifier
+import org.gradle.api.artifacts.component.ModuleComponentSelector
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.capabilities.Capability
+
+class FakeModuleComponentSelector(
+ private val group: String,
+ private val module: String,
+ private val version: String,
+) : ModuleComponentSelector {
+
+ override fun getDisplayName(): String {
+ TODO("Not yet implemented")
+ }
+
+ override fun matchesStrictly(identifier: ComponentIdentifier): Boolean {
+ TODO("Not yet implemented")
+ }
+
+ override fun getAttributes(): AttributeContainer {
+ TODO("Not yet implemented")
+ }
+
+ override fun getRequestedCapabilities(): MutableList<Capability> {
+ TODO("Not yet implemented")
+ }
+
+ override fun getGroup(): String {
+ return group
+ }
+
+ override fun getModule(): String {
+ return module
+ }
+
+ override fun getVersion(): String {
+ return version
+ }
+
+ override fun getVersionConstraint(): VersionConstraint {
+ TODO("Not yet implemented")
+ }
+
+ override fun getModuleIdentifier(): ModuleIdentifier {
+ TODO("Not yet implemented")
+ }
+}
diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTaskTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTaskTest.kt
index a304603..8ed16d0 100644
--- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTaskTest.kt
+++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/CheckAarMetadataTaskTest.kt
@@ -20,12 +20,18 @@
import com.android.build.gradle.internal.fixtures.FakeArtifactCollection
import com.android.build.gradle.internal.fixtures.FakeComponentIdentifier
import com.android.build.gradle.internal.fixtures.FakeGradleWorkExecutor
+import com.android.build.gradle.internal.fixtures.FakeModuleComponentSelector
import com.android.build.gradle.internal.fixtures.FakeNoOpAnalyticsService
import com.android.build.gradle.internal.fixtures.FakeResolvedArtifactResult
+import com.android.build.gradle.internal.fixtures.FakeResolvedComponentResult
+import com.android.build.gradle.internal.fixtures.FakeResolvedDependencyResult
+import com.android.build.gradle.internal.utils.DESUGAR_JDK_LIBS
+import com.android.build.gradle.internal.utils.DESUGAR_JDK_LIBS_MINIMAL
+import com.android.build.gradle.internal.utils.checkDesugarJdkVariant
+import com.android.build.gradle.internal.utils.checkDesugarJdkVersion
import com.google.common.truth.Truth.assertThat
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.workers.WorkerExecutor
-import org.junit.Assert.fail
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -724,4 +730,114 @@
""".trimIndent())
}
}
+
+ @Test
+ fun testFailsOnDesugarJdkLibId() {
+ task.aarMetadataArtifacts =
+ FakeArtifactCollection(
+ mutableSetOf(
+ FakeResolvedArtifactResult(
+ file = temporaryFolder.newFile().also {
+ writeAarMetadataFile(
+ file = it,
+ aarFormatVersion = AarMetadataTask.AAR_FORMAT_VERSION,
+ aarMetadataVersion = AarMetadataTask.AAR_METADATA_VERSION,
+ minCompileSdk = 28,
+ minCompileSdkExtension = 0,
+ minAgpVersion = "3.0.0",
+ coreLibraryDesugaringEnabled = true,
+ desugarJdkLib = "com.android.tools:desugar_jdk_libs_nio:2.0.2"
+ )
+ },
+ identifier = FakeComponentIdentifier("displayName")
+ )
+ )
+ )
+ task.aarFormatVersion.set(AarMetadataTask.AAR_FORMAT_VERSION)
+ task.aarMetadataVersion.set(AarMetadataTask.AAR_METADATA_VERSION)
+ task.compileSdkVersion.set("android-28")
+ task.disableCompileSdkChecks.set(false)
+ task.agpVersion.set(Version.ANDROID_GRADLE_PLUGIN_VERSION)
+ task.projectPath.set(":app")
+ task.coreLibraryDesugaringEnabled.set(true)
+ task.desugarJdkLibDependencyGraph.set(
+ FakeResolvedComponentResult(
+ dependencies = mutableSetOf(FakeResolvedDependencyResult(
+ requested = FakeModuleComponentSelector(
+ "com.android.tools", "desugar_jdk_libs", "1.1.5")
+ )
+ )
+ )
+ )
+ try {
+ task.taskAction()
+ } catch (e: RuntimeException) {
+ assertThat(e.message).isEqualTo("""
+ 2 issues were found when checking AAR metadata:
+
+ 1. Dependency 'displayName' requires desugar_jdk_libs flavor to be at least
+ desugar_jdk_libs_nio for :app, which is currently desugar_jdk_libs
+
+ See https://d.android.com/r/tools/api-desugaring-flavors
+ for more details.
+
+ 2. Dependency 'displayName' requires desugar_jdk_libs version to be
+ 2.0.2 or above for :app, which is currently 1.1.5
+
+ See https://d.android.com/studio/build/library-desugaring for more
+ details.
+ """.trimIndent())
+ }
+ }
+
+ @Test
+ fun testCompareDesugarJdkVariant() {
+ val errorMessages = mutableListOf<String>()
+ checkDesugarJdkVariant(
+ variantFromAar = DESUGAR_JDK_LIBS_MINIMAL,
+ variantFromConsumer = DESUGAR_JDK_LIBS,
+ errorMessages = errorMessages,
+ dependency = "",
+ projectPath = ""
+ )
+ assertThat(errorMessages).isEmpty()
+ checkDesugarJdkVariant(
+ variantFromAar = DESUGAR_JDK_LIBS,
+ variantFromConsumer = DESUGAR_JDK_LIBS_MINIMAL,
+ errorMessages = errorMessages,
+ dependency = "",
+ projectPath = ""
+ )
+ assertThat(errorMessages).isNotEmpty()
+ }
+
+ @Test
+ fun testCompareDesugarJdkVersion() {
+ val errorMessages = mutableListOf<String>()
+ checkDesugarJdkVersion(
+ versionFromAar = "1.1.3",
+ versionFromConsumer = "1.2.5",
+ errorMessages = errorMessages,
+ dependency = "",
+ projectPath = ""
+ )
+ assertThat(errorMessages).isEmpty()
+ checkDesugarJdkVersion(
+ versionFromAar = "2.1.3",
+ versionFromConsumer = "1.2.5",
+ errorMessages = errorMessages,
+ dependency = "",
+ projectPath = ""
+ )
+ assertThat(errorMessages).isNotEmpty()
+ errorMessages.clear()
+ checkDesugarJdkVersion(
+ versionFromAar = "2.1.3",
+ versionFromConsumer = "2.2.5",
+ errorMessages = errorMessages,
+ dependency = "",
+ projectPath = ""
+ )
+ assertThat(errorMessages).isEmpty()
+ }
}
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/CheckAarMetadataTaskTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/CheckAarMetadataTaskTest.kt
index ba3386d..0e647d1 100644
--- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/CheckAarMetadataTaskTest.kt
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/CheckAarMetadataTaskTest.kt
@@ -24,6 +24,7 @@
import com.android.SdkConstants.MIN_COMPILE_SDK_EXTENSION_PROPERTY
import com.android.SdkConstants.MIN_COMPILE_SDK_PROPERTY
import com.android.build.gradle.integration.common.fixture.DESUGAR_DEPENDENCY_VERSION
+import com.android.build.gradle.integration.common.fixture.DESUGAR_NIO_DEPENDENCY_VERSION
import com.android.build.gradle.integration.common.fixture.GradleTestProject
import com.android.build.gradle.integration.common.fixture.GradleTestProject.Companion.compileSdkHash
import com.android.build.gradle.integration.common.fixture.app.HelloWorldLibraryApp
@@ -579,6 +580,10 @@
android.compileOptions.coreLibraryDesugaringEnabled = false
""".trimIndent()
)
+ TestFileUtils.appendToFile(
+ project.getSubproject("app").buildFile,
+ "dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:$DESUGAR_DEPENDENCY_VERSION'}"
+ )
TestFileUtils.searchAndReplace(
project.getSubproject("app").buildFile,
"implementation files('libs/library.aar')",
@@ -587,6 +592,32 @@
project.executor().run(":app:checkAndroidTestAarMetadata")
}
+ @Test
+ fun testCheckingDesugarJdkLib() {
+ addAarWithPossiblyInvalidAarMetadataToAppProject(
+ aarFormatVersion = AarMetadataTask.AAR_FORMAT_VERSION,
+ aarMetadataVersion = AarMetadataTask.AAR_METADATA_VERSION,
+ coreLibraryDesugaringEnabled = "true",
+ minDesugarJdkLib = "com.android.tools:desugar_jdk_libs_nio:$DESUGAR_NIO_DEPENDENCY_VERSION"
+ )
+
+ TestFileUtils.appendToFile(
+ project.getSubproject("app").buildFile,
+ """
+ android.compileOptions.coreLibraryDesugaringEnabled = true
+ android.defaultConfig.multiDexEnabled = true
+ """.trimIndent()
+ )
+ TestFileUtils.appendToFile(
+ project.getSubproject("app").buildFile,
+ "dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:$DESUGAR_DEPENDENCY_VERSION'}"
+ )
+ val result = project.executor().expectFailure().run(":app:checkDebugAarMetadata")
+ ScannerSubject.assertThat(result.stderr).contains(
+ "2 issues were found when checking AAR metadata"
+ )
+ }
+
private fun addAarWithPossiblyInvalidAarMetadataToAppProject(
aarFormatVersion: String?,
aarMetadataVersion: String?,