diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-08-18 14:36:26 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-08-18 14:36:26 +0000 |
commit | e0f43800a5920816448ec001c76f783059764ca6 (patch) | |
tree | 449424a4ef2226c9110ca1377911ea36b390a362 | |
parent | 0a2ee0993b13789da3745bac1f376f8311631902 (diff) | |
parent | 96e25f968022e6b368d7809f4f5ea4ab86438836 (diff) | |
download | base-e0f43800a5920816448ec001c76f783059764ca6.tar.gz |
Snap for 8962753 from 96e25f968022e6b368d7809f4f5ea4ab86438836 to studio-ee-release
Change-Id: I04c795285fef0c12929e1539cdb2a17258f9698b
279 files changed, 6420 insertions, 3983 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 69a6633c0f..2ff19985c5 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,11 +4,14 @@ sync-inspection-profiles = ${REPO_ROOT}/tools/repohooks/tools/sync-inspection-pr [Builtin Hooks] google_java_format = true clang_format = true +ktfmt = true [Builtin Hooks Options] google_java_format = --sort-imports clang_format = --style=google --extensions cc,h --commit HEAD --git-clang-format ${REPO_ROOT}/prebuilts/tools/common/clang-format/git-clang-format --clang-format ${REPO_ROOT}/prebuilts/tools/${BUILD_OS}/clang-format/clang-format${BUILD_OS_EXEC_EXTENSION} +ktfmt = --include-dirs=device-provisioner --google-style [Tool Paths] google-java-format = ${REPO_ROOT}/prebuilts/tools/common/google-java-format/google-java-format google-java-format-diff = ${REPO_ROOT}/tools/repohooks/tools/google-java-format-diff.py +ktfmt = ${REPO_ROOT}/prebuilts/tools/common/ktfmt/ktfmt diff --git a/adblib/test/src/com/android/adblib/AdbDeviceServicesTest.kt b/adblib/test/src/com/android/adblib/AdbDeviceServicesTest.kt index e1c0504e8c..79a3d96a17 100644 --- a/adblib/test/src/com/android/adblib/AdbDeviceServicesTest.kt +++ b/adblib/test/src/com/android/adblib/AdbDeviceServicesTest.kt @@ -97,11 +97,11 @@ class AdbDeviceServicesTest { # This is some build info # This is more build info + [ro.build.version.release]: [model] + [ro.build.version.sdk]: [30] [ro.product.cpu.abi]: [x86_64] [ro.product.manufacturer]: [test1] [ro.product.model]: [test2] - [ro.build.version.release]: [model] - [ro.build.version.sdk]: [30] """.trimIndent() Assert.assertEquals(expectedOutput, AdbProtocolUtils.byteBufferToString(bytes)) @@ -125,10 +125,11 @@ class AdbDeviceServicesTest { # This is some build info # This is more build info - [ro.product.manufacturer]: [test1] - [ro.product.model]: [test2] [ro.build.version.release]: [model] [ro.build.version.sdk]: [30] + [ro.product.cpu.abi]: [x86_64] + [ro.product.manufacturer]: [test1] + [ro.product.model]: [test2] """.trimIndent() Assert.assertEquals(expectedOutput, commandOutput.stdout) @@ -157,10 +158,11 @@ class AdbDeviceServicesTest { # This is some build info # This is more build info - [ro.product.manufacturer]: [test1] - [ro.product.model]: [test2] [ro.build.version.release]: [model] [ro.build.version.sdk]: [30] + [ro.product.cpu.abi]: [x86_64] + [ro.product.manufacturer]: [test1] + [ro.product.model]: [test2] """.trimIndent() Assert.assertEquals(expectedOutput.lines(), lines) @@ -584,10 +586,11 @@ class AdbDeviceServicesTest { # This is some build info # This is more build info - [ro.product.manufacturer]: [test1] - [ro.product.model]: [test2] [ro.build.version.release]: [model] [ro.build.version.sdk]: [30] + [ro.product.cpu.abi]: [x86_64] + [ro.product.manufacturer]: [test1] + [ro.product.model]: [test2] """.trimIndent() Assert.assertEquals(expectedOutput, AdbProtocolUtils.byteBufferToString(bytes)) @@ -613,10 +616,11 @@ class AdbDeviceServicesTest { # This is some build info # This is more build info - [ro.product.manufacturer]: [test1] - [ro.product.model]: [test2] [ro.build.version.release]: [model] [ro.build.version.sdk]: [30] + [ro.product.cpu.abi]: [x86_64] + [ro.product.manufacturer]: [test1] + [ro.product.model]: [test2] """.trimIndent() Assert.assertEquals( diff --git a/bazel/BUILD b/bazel/BUILD index 1718eaab4d..cb50cf2230 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -377,6 +377,13 @@ java_jarjar( visibility = ["//visibility:public"], ) +java_jarjar( + name = "utp-core-proto-jarjar", + srcs = ["//prebuilts/tools/common/m2:utp-core-proto"], + rules = "jarjar_rules.txt", + visibility = ["//visibility:public"], +) + config_setting( name = "host_linux", values = {"host_cpu": "linux"}, diff --git a/bazel/avd/src/com/android/tools/bazel/avd/Emulator.java b/bazel/avd/src/com/android/tools/bazel/avd/Emulator.java index 5817b25b99..fd133787d9 100644 --- a/bazel/avd/src/com/android/tools/bazel/avd/Emulator.java +++ b/bazel/avd/src/com/android/tools/bazel/avd/Emulator.java @@ -16,8 +16,6 @@ package com.android.tools.bazel.avd; -import java.io.BufferedReader; -import java.io.InputStreamReader; import org.junit.rules.ExternalResource; /** JUnit rule that calls the executable generated by the avd rule to start and stop an emulator. */ @@ -40,7 +38,7 @@ public final class Emulator extends ExternalResource { @Override public void before() throws Throwable { System.out.println("Starting emulator"); - System.out.println(exec(devicePath + " " + port)); + exec(devicePath, port); System.out.println("Emulator started"); } @@ -48,25 +46,18 @@ public final class Emulator extends ExternalResource { public void after() { try { System.out.println("Killing emulator"); - System.out.println(exec(devicePath + " kill " + port)); + exec(devicePath, "kill", port); System.out.println("Emulator killed"); } catch (Exception ex) { ex.printStackTrace(); } } - private static String exec(String cmd) throws Exception { - Runtime r = Runtime.getRuntime(); - Process p = r.exec(cmd); - p.waitFor(); - String res = ""; - try (BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()))) { - String l = ""; - while ((l = b.readLine()) != null) { - res += l + "\n"; - } - } + private static void exec(String... cmd) throws Exception { + int exitCode = new ProcessBuilder().command(cmd).inheritIO().start().waitFor(); - return res; + if (exitCode != 0) { + throw new Exception(String.format("Emulator script exited with code: %d", exitCode)); + } } } diff --git a/bazel/common.bazelrc b/bazel/common.bazelrc index 0dad12ef52..895c5abd9f 100644 --- a/bazel/common.bazelrc +++ b/bazel/common.bazelrc @@ -21,6 +21,35 @@ test --jvmopt='-XX:+UseG1GC' test --jvmopt='-XX:ErrorFile=$TEST_UNDECLARED_OUTPUTS_DIR/jvm_crash.log' test --verbose_failures +# TODO(b/242203555) cleanup opens/exports that was added for JDK17 migration +test:jdk17 --jvmopt='--add-opens=java.base/java.io=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.base/java.lang=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.base/java.nio.charset=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.base/java.util=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.base/java.util.concurrent=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/java.awt=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/java.awt.event=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/javax.swing=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/sun.awt=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-opens=java.desktop/sun.font=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports java.base/jdk.internal.vm=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=java.desktop/sun.java2d=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=java.desktop/sun.swing=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=jdk.attach/sun.tools.attach=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED' +test:jdk17 --jvmopt='--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED' + +build:jdk17 --jvmopt='--add-exports java.base/jdk.internal.vm=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=java.desktop/sun.java2d=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=java.desktop/sun.swing=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=jdk.attach/sun.tools.attach=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED' +build:jdk17 --jvmopt='--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED' + # Local runs require longer timeouts. test:local --test_timeout=120,600,1800,7200 diff --git a/bazel/coverage/BUILD b/bazel/coverage/BUILD index 3ec6b48187..bfdf9c316d 100644 --- a/bazel/coverage/BUILD +++ b/bazel/coverage/BUILD @@ -996,6 +996,7 @@ coverage_report( "//tools/apksig:all", "//tools/apkzlib:apkzlib_tests", "//tools/base/adblib:adblib.tests.test", + "//tools/base/adblib-tools:adblib.tools.tests.test", "//tools/base/apkparser:studio.android.sdktools.binary-resources_tests", "//tools/base/apkparser:tools.tests", "//tools/base/apkparser/analyzer:studio.android.sdktools.analyzer_tests", @@ -1064,6 +1065,7 @@ coverage_report( "//tools/base/ddmlib:tools.tests.test", "//tools/base/deploy/deployer:deployer.tests", "//tools/base/deploy/deployer:studio.android.sdktools.deployer_tests", + "//tools/base/device-provisioner:studio.android.sdktools.device-provisioner_tests", "//tools/base/draw9patch:studio.android.sdktools.draw9patch_tests", "//tools/base/dynamic-layout-inspector/agent/appinspection:agent_tests.test", "//tools/base/fakeadbserver:studio.android.sdktools.fakeadbserver_tests", diff --git a/bazel/perfgate_linux.sh b/bazel/perfgate_linux.sh index 360aad42a3..c651747c93 100755 --- a/bazel/perfgate_linux.sh +++ b/bazel/perfgate_linux.sh @@ -30,6 +30,7 @@ readonly invocation_id="$(uuidgen)" ${config_options} --config=ants \ --build_metadata=ab_build_id="${BUILD_NUMBER}" \ --build_metadata=ab_target=perfgate-linux \ + --build_metadata=ANDROID_TEST_INVESTIGATE="http://ab/tests/bazel/${invocation_id}" \ --invocation_id=${invocation_id} \ --build_tag_filters=${build_tag_filters} \ --define=meta_android_build_number=${build_number} \ diff --git a/bazel/perfgate_win.cmd b/bazel/perfgate_win.cmd index 272a6ce384..c58c3fd27e 100644 --- a/bazel/perfgate_win.cmd +++ b/bazel/perfgate_win.cmd @@ -34,6 +34,7 @@ CALL %SCRIPTDIR%bazel.cmd ^ --config=ci --config=ants ^ --build_metadata=ab_build_id=%BUILDNUMBER% ^ --build_metadata=ab_target=perfgate-win ^ + --build_metadata=ANDROID_TEST_INVESTIGATE="http://ab/tests/bazel/%INVOCATIONID%" ^ --build_tag_filters=-no_windows ^ --invocation_id=%INVOCATIONID% ^ --build_event_binary_file=%DISTDIR%\bazel-%BUILDNUMBER%.bes ^ diff --git a/bazel/proto.bzl b/bazel/proto.bzl index 3e9801abd9..982f3f9b1d 100644 --- a/bazel/proto.bzl +++ b/bazel/proto.bzl @@ -200,7 +200,8 @@ def android_java_proto_library( protoc_grpc_version = PROTOC_GRPC_VERSION, java_deps = [], proto_deps = [], - visibility = None): + visibility = None, + **kwargs): """Compiles protobuf into a .jar file in Android Studio compatible runtime version. Unlike java_proto_library rule defined above, android_java_proto_library @@ -230,6 +231,7 @@ def android_java_proto_library( protoc_grpc_version = protoc_grpc_version, java_deps = java_deps, proto_deps = proto_deps, + **kwargs ) java_jarjar( name = name, diff --git a/bazel/sdk/README.md b/bazel/sdk/README.md index 8190cd2177..e91f83f3ae 100644 --- a/bazel/sdk/README.md +++ b/bazel/sdk/README.md @@ -152,7 +152,7 @@ the file from local_manifests. $ cd /path/to/studio-main/ # This branch name will become the topic name for your CLs so choose a unique name. -# Of course, your branch name will be different... +# Of course, your branch name will be different... $ repo start devsdk+build-tools+19_0_3 \ prebuilts/studio/sdk/darwin \ prebuilts/studio/sdk/linux \ @@ -253,7 +253,7 @@ $ repo forall \ prebuilts/studio/sdk/linux \ prebuilts/studio/sdk/windows \ tools/base \ - -c git add -A; git commit -a -m "Updated SDK with build-tools;19.0.3" + -c 'git add -A; git commit -a -m "Updated SDK with build-tools;19.0.3"' # When uploading, include -t to ensure all code reviews have the # same topic (the topic will be set to your current branch name). @@ -317,4 +317,4 @@ $ rm -rf prebuilts/studio/sdk/windows # unless you're windows $ repo upload --cbr -t # This opens an editor. Uncomment all SDK branches and save. - ```
\ No newline at end of file + ``` diff --git a/bazel/sdk/dev-sdk-packages b/bazel/sdk/dev-sdk-packages index 095d83518a..a8dbd83ed7 100644 --- a/bazel/sdk/dev-sdk-packages +++ b/bazel/sdk/dev-sdk-packages @@ -19,6 +19,7 @@ build-tools;25.0.0 build-tools;24.0.3 # Platforms. +platforms;android-TiramisuPrivacySandbox platforms;android-33 platforms;android-32 platforms;android-31 @@ -53,5 +54,3 @@ cmake;3.22.1 # Instant apps sdk used in integration tests extras;google;instantapps - -ndk;21.4.7075529:**:{**/OWNERS,**/BUILD.bazel} diff --git a/bazel/sdk/prebuilts.studio.sdk.BUILD b/bazel/sdk/prebuilts.studio.sdk.BUILD index ec3e3ea333..fbeff3a574 100644 --- a/bazel/sdk/prebuilts.studio.sdk.BUILD +++ b/bazel/sdk/prebuilts.studio.sdk.BUILD @@ -84,7 +84,7 @@ filegroup( srcs = sdk_glob( include = ["build-tools/30.0.3/**"], ), - visibility = ["//visibility:private"], + visibility = ["//tools/adt/idea/old-agp-tests:__pkg__"], ) filegroup( @@ -233,8 +233,9 @@ java_import( ) platform_filegroup( - name = "platforms/android-Tiramisu", + name = "platforms/android-TiramisuPrivacySandbox", visibility = [ + "//prebuilts/studio/buildbenchmarks:__pkg__", "//tools/base/build-system/integration-test:__subpackages__", ], ) diff --git a/bazel/studio_coverage.sh b/bazel/studio_coverage.sh index 7eaaa12e34..dc73ebb09a 100755 --- a/bazel/studio_coverage.sh +++ b/bazel/studio_coverage.sh @@ -73,6 +73,7 @@ fi --build_event_binary_file="${dist_dir:-/tmp}/bazel-${build_number}.bes" \ --profile="${dist_dir:-/tmp}/profile-${build_number}.json.gz" \ --build_metadata=ANDROID_BUILD_ID="${build_number}" \ + --build_metadata=ANDROID_TEST_INVESTIGATE="http://ab/tests/bazel/${invocation_id}" \ --build_metadata=ab_build_id="${build_number}" \ --build_metadata=ab_target=studio-coverage \ ${auth_options} \ diff --git a/bazel/studio_linux.sh b/bazel/studio_linux.sh index e5554eb1ed..971fba8862 100755 --- a/bazel/studio_linux.sh +++ b/bazel/studio_linux.sh @@ -46,6 +46,7 @@ function copy_bazel_artifacts() {( cp -a ${bin_dir}/tools/adt/idea/studio/android-studio.mac.zip ${artifacts_dir} cp -a ${bin_dir}/tools/adt/idea/studio/android-studio.mac_arm.zip ${artifacts_dir} cp -a ${bin_dir}/tools/adt/idea/studio/android-studio_build_manifest.textproto ${artifacts_dir}/android-studio_build_manifest.textproto + cp -a ${bin_dir}/tools/adt/idea/studio/android-studio_update_message.html ${artifacts_dir}/android-studio_update_message.html cp -a ${bin_dir}/tools/adt/idea/studio/updater_deploy.jar ${artifacts_dir}/android-studio-updater.jar cp -a ${bin_dir}/tools/adt/idea/updater-ui/sdk-patcher.zip ${artifacts_dir} cp -a ${bin_dir}/tools/adt/idea/native/installer/android-studio-bundle-data.zip ${artifacts_dir} @@ -137,6 +138,7 @@ function run_bazel_test() { --build_event_binary_file="${DIST_DIR:-/tmp}/bazel-${BUILD_NUMBER}.bes" \ --define=meta_android_build_number="${BUILD_NUMBER}" \ --build_metadata=ANDROID_BUILD_ID="${BUILD_NUMBER}" \ + --build_metadata=ANDROID_TEST_INVESTIGATE="http://ab/tests/bazel/${invocation_id}" \ --build_metadata=ab_build_id="${BUILD_NUMBER}" \ --build_metadata=ab_target="${target_name}" \ --test_tag_filters=${test_tag_filters} \ diff --git a/bazel/studio_win.cmd b/bazel/studio_win.cmd index 00bd3c48da..422b44171f 100755 --- a/bazel/studio_win.cmd +++ b/bazel/studio_win.cmd @@ -84,6 +84,7 @@ setlocal --build_event_binary_file=%DISTDIR%\bazel-%BUILDNUMBER%.bes ^
--test_tag_filters=%TESTTAGFILTERS% ^
--build_metadata=ANDROID_BUILD_ID=%BUILDNUMBER% ^
+ --build_metadata=ANDROID_TEST_INVESTIGATE="http://ab/tests/bazel/%INVOCATIONID%" ^
--build_metadata=ab_build_id=%BUILDNUMBER% ^
--build_metadata=ab_target=studio-win ^
--profile=%DISTDIR%\winprof%BUILDNUMBER%.json.gz ^
diff --git a/bazel/testSrc/com/android/tools/gradle/BenchmarkTest.java b/bazel/testSrc/com/android/tools/gradle/BenchmarkTest.java index 5a81ebd86d..ea89b6c670 100644 --- a/bazel/testSrc/com/android/tools/gradle/BenchmarkTest.java +++ b/bazel/testSrc/com/android/tools/gradle/BenchmarkTest.java @@ -20,6 +20,7 @@ import com.android.SdkConstants; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.testutils.diff.UnifiedDiff; +import com.android.testutils.TestUtils; import com.android.tools.gradle.benchmarkassertions.BenchmarkProjectAssertion; import com.android.tools.perflogger.Benchmark; import com.android.tools.perflogger.PerfData; @@ -29,6 +30,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Path; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -76,6 +78,7 @@ public class BenchmarkTest { private String yourKitAgentPath = null; private String yourKitLibraryPath = null; private String yourKitSettingsPath = null; + private boolean useJdk11 = false; @Before public void setUp() throws Exception { @@ -176,6 +179,10 @@ public class BenchmarkTest { if (value != null && !value.isEmpty()) { enableYourKit = Boolean.parseBoolean(value); } + value = System.getProperty("use_jdk11"); + if (value != null && !value.isEmpty()) { + useJdk11 = Boolean.parseBoolean(value); + } yourKitAgentPath = getStringProperty("yourkit_agent_path"); yourKitLibraryPath = getStringProperty("yourkit_library_path"); yourKitSettingsPath = getStringProperty("yourkit_settings"); @@ -314,8 +321,11 @@ public class BenchmarkTest { } File projectRoot = new File(src, testProjectGradleRootFromSourceRoot); - addJvmArgs( - new File(projectRoot, "gradle.properties"), enableYourKit, src, yourKitAgentPath); + File gradleProperties = new File(projectRoot, "gradle.properties"); + addJvmArgs(gradleProperties, enableYourKit, src, yourKitAgentPath); + if (useJdk11) { + useJdk11ForGradle(gradleProperties); + } try (Gradle gradle = new Gradle(projectRoot, out, distribution)) { for (File repo : repos) { gradle.addRepo(repo); @@ -424,6 +434,8 @@ public class BenchmarkTest { String jvmArgs = p.getProperty("org.gradle.jvmargs", ""); jvmArgs += " -XX:+UseParallelGC"; + jvmArgs += " --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED"; + jvmArgs += " --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"; // See https://www.yourkit.com/docs/java/help/startup_options.jsp for a comprehensive list // of all agent options. if (enableYourKit) { @@ -455,6 +467,28 @@ public class BenchmarkTest { } } + /** + * Sets java.home to point to JDK11 if Gradle versions is less than 7.3 + * + * Gradle supports JDK17 satrting from version 7.3 Also Gradle prior to 6.9 don't works well + * with symlinks, so path from bazel runfiles is resolved to real one. + */ + private void useJdk11ForGradle(File gradleProperties) throws IOException { + Path javaPath = TestUtils.getJava11Jdk().resolve("release").toRealPath(); + Path javaHome = javaPath.getParent(); + + Properties p = new Properties(); + if (gradleProperties.exists()) { + try (FileInputStream fis = new FileInputStream(gradleProperties)) { + p.load(fis); + } + } + p.put("org.gradle.java.home", javaHome.toString()); + try (FileWriter fw = new FileWriter(gradleProperties)) { + p.store(fw, ""); + } + } + private static String hostName() { if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX) { return "Linux"; diff --git a/build-system/BUILD b/build-system/BUILD index 013f491c13..846ced349b 100644 --- a/build-system/BUILD +++ b/build-system/BUILD @@ -99,6 +99,12 @@ filegroup( ) filegroup( + name = "gradle-distrib-7.4", + srcs = ["//tools/external/gradle:gradle-distrib-7.4"], + visibility = ["//tools/adt/idea/old-agp-tests:__pkg__"], +) + +filegroup( name = "gradle-distrib-7.3.3", srcs = ["//tools/external/gradle:gradle-distrib-7.3.3"], visibility = ["//visibility:public"], diff --git a/build-system/builder/src/main/java/com/android/builder/dexing/D8DexArchiveBuilder.java b/build-system/builder/src/main/java/com/android/builder/dexing/D8DexArchiveBuilder.java index 51c0aadec0..1aa65b4fb6 100644 --- a/build-system/builder/src/main/java/com/android/builder/dexing/D8DexArchiveBuilder.java +++ b/build-system/builder/src/main/java/com/android/builder/dexing/D8DexArchiveBuilder.java @@ -26,17 +26,22 @@ import com.android.tools.r8.D8Command; import com.android.tools.r8.Diagnostic; import com.android.tools.r8.OutputMode; import com.android.tools.r8.StringConsumer.FileConsumer; +import com.android.tools.r8.errors.UnsupportedFeatureDiagnostic; import com.google.common.util.concurrent.MoreExecutors; import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; final class D8DexArchiveBuilder extends DexArchiveBuilder { private static final String INVOKE_CUSTOM = - "Invoke-customs are only supported starting with Android O"; + "Invoke-customs are only supported starting with Android O (--min-api 26)"; private static final String DEFAULT_INTERFACE_METHOD = "Default interface methods are only supported starting with Android N (--min-api 24)"; @@ -56,10 +61,10 @@ final class D8DexArchiveBuilder extends DexArchiveBuilder { @NonNull Path output, @Nullable DependencyGraphUpdater<File> desugarGraphUpdater) throws DexArchiveBuilderException { - D8DiagnosticsHandler d8DiagnosticsHandler = new InterceptingDiagnosticsHandler(); + InterceptingDiagnosticsHandler diagnosticsHandler = new InterceptingDiagnosticsHandler(); try { - D8Command.Builder builder = D8Command.builder(d8DiagnosticsHandler); + D8Command.Builder builder = D8Command.builder(diagnosticsHandler); AtomicInteger entryCount = new AtomicInteger(); input.forEach( entry -> { @@ -114,7 +119,7 @@ final class D8DexArchiveBuilder extends DexArchiveBuilder { D8.run(builder.build(), MoreExecutors.newDirectExecutorService()); } catch (Throwable e) { - throw getExceptionToRethrow(e, d8DiagnosticsHandler); + throw getExceptionToRethrow(e, diagnosticsHandler, dexParams.getWithDesugaring()); } } @@ -129,14 +134,52 @@ final class D8DexArchiveBuilder extends DexArchiveBuilder { @NonNull private static DexArchiveBuilderException getExceptionToRethrow( - @NonNull Throwable t, D8DiagnosticsHandler d8DiagnosticsHandler) { + @NonNull Throwable t, + InterceptingDiagnosticsHandler diagnosticsHandler, + boolean isDesugaring) { StringBuilder msg = new StringBuilder(); msg.append("Error while dexing."); - for (String hint : d8DiagnosticsHandler.getPendingHints()) { + Set<String> unsupportedFeatures = diagnosticsHandler.getUnsupportedFeatures(); + if (!unsupportedFeatures.isEmpty()) { + // Get the largest required level needed to support the features. + int minSdkVersion = diagnosticsHandler.getRequiredSdkVersion(); + if (!isDesugaring) { + diagnosticsHandler.addHint(getEnableDesugaringHint(minSdkVersion)); + } else if (minSdkVersion != -1) { + diagnosticsHandler.addHint( + "Increase the minSdkVersion to " + minSdkVersion + " or above.\n"); + } + // Construct a new exception to replace the D8 thrown exception. + // This avoids the need to maintain pattern-match on D8 exceptions and + // instead base matching on the stable diagnostics API. + StringBuilder builder = new StringBuilder(); + if (unsupportedFeatures.contains("invoke-custom")) { + builder.append("Error: ").append(INVOKE_CUSTOM); + } else if (unsupportedFeatures.contains("default-interface-method")) { + builder.append("Error: ").append(DEFAULT_INTERFACE_METHOD); + } else if (unsupportedFeatures.contains("static-interface-method")) { + builder.append("Error: ").append(STATIC_INTERFACE_METHOD); + } else { + // If not one of the three above legacy cases, construct an error message with a + // line + // for each unsupported feature. These are not currently pattern-matched on, so + // generalizing the reporting of these can be changed at a later point. + List<String> sorted = new ArrayList<>(unsupportedFeatures); + sorted.sort(String::compareTo); + for (String featureDescriptor : sorted) { + builder.append("Error: UnsupportedFeature(") + .append(featureDescriptor) + .append(")\n"); + } + } + Throwable rt = new RuntimeException(builder.toString()); + rt.addSuppressed(t); + t = rt; + } + for (String hint : diagnosticsHandler.getPendingHints()) { msg.append(System.lineSeparator()); msg.append(hint); } - return new DexArchiveBuilderException(msg.toString(), t); } @@ -156,25 +199,33 @@ final class D8DexArchiveBuilder extends DexArchiveBuilder { } private class InterceptingDiagnosticsHandler extends D8DiagnosticsHandler { + + private Set<String> unsupportedFeatureDescriptors = new HashSet<>(); + private int requiredSdkVersion = -1; + public InterceptingDiagnosticsHandler() { super(D8DexArchiveBuilder.this.dexParams.getMessageReceiver()); } - @Override - protected Message convertToMessage(Message.Kind kind, Diagnostic diagnostic) { - - if (diagnostic.getDiagnosticMessage().startsWith(INVOKE_CUSTOM)) { - addHint(getEnableDesugaringHint(26)); - } + public int getRequiredSdkVersion() { + return requiredSdkVersion; + } - if (diagnostic.getDiagnosticMessage().startsWith(DEFAULT_INTERFACE_METHOD)) { - addHint(getEnableDesugaringHint(24)); - } + public Set<String> getUnsupportedFeatures() { + return unsupportedFeatureDescriptors; + } - if (diagnostic.getDiagnosticMessage().startsWith(STATIC_INTERFACE_METHOD)) { - addHint(getEnableDesugaringHint(24)); + @Override + protected Message convertToMessage(Message.Kind kind, Diagnostic diagnostic) { + if (diagnostic instanceof UnsupportedFeatureDiagnostic) { + UnsupportedFeatureDiagnostic feature = (UnsupportedFeatureDiagnostic) diagnostic; + String featureDescriptor = feature.getFeatureDescriptor(); + int minSdkVersion = feature.getSupportedApiLevel(); + unsupportedFeatureDescriptors.add(featureDescriptor); + if (requiredSdkVersion < minSdkVersion) { + requiredSdkVersion = minSdkVersion; + } } - return super.convertToMessage(kind, diagnostic); } } diff --git a/build-system/builder/src/main/java/com/android/builder/dexing/D8DiagnosticsHandler.java b/build-system/builder/src/main/java/com/android/builder/dexing/D8DiagnosticsHandler.java index bc24ba79b7..c270ab712f 100644 --- a/build-system/builder/src/main/java/com/android/builder/dexing/D8DiagnosticsHandler.java +++ b/build-system/builder/src/main/java/com/android/builder/dexing/D8DiagnosticsHandler.java @@ -107,9 +107,13 @@ public class D8DiagnosticsHandler implements DiagnosticsHandler { protected Message convertToMessage(Message.Kind kind, Diagnostic diagnostic) { String textMessage = diagnostic.getDiagnosticMessage(); - Origin origin = diagnostic.getOrigin(); Position positionInOrigin = diagnostic.getPosition(); + return convertToMessage(kind, textMessage, origin, positionInOrigin); + } + + protected Message convertToMessage( + Message.Kind kind, String textMessage, Origin origin, Position positionInOrigin) { SourceFilePosition position; if (origin instanceof PathOrigin) { File originFile = ((PathOrigin) origin).getPath().toFile(); diff --git a/build-system/gradle-api/api/current.txt b/build-system/gradle-api/api/current.txt index aa9eb6489f..495f5e36aa 100644 --- a/build-system/gradle-api/api/current.txt +++ b/build-system/gradle-api/api/current.txt @@ -2024,13 +2024,11 @@ package com.android.build.api.variant { public interface AndroidTest extends com.android.build.api.variant.GeneratesTestApk com.android.build.api.variant.HasAndroidResources com.android.build.api.variant.TestComponent { method public org.gradle.api.provider.Property<java.lang.String> getApplicationId(); method public org.gradle.api.provider.MapProperty<java.lang.String,? extends com.android.build.api.variant.BuildConfigField<? extends java.io.Serializable>> getBuildConfigFields(); - method public org.gradle.api.provider.MapProperty<java.lang.String,java.lang.String> getManifestPlaceholders(); method public org.gradle.api.provider.Provider<java.lang.String> getNamespace(); method public org.gradle.api.provider.ListProperty<org.gradle.api.file.RegularFile> getProguardFiles(); method public com.android.build.api.variant.SigningConfig? getSigningConfig(); property public abstract org.gradle.api.provider.Property<java.lang.String> applicationId; property public abstract org.gradle.api.provider.MapProperty<java.lang.String,? extends com.android.build.api.variant.BuildConfigField<? extends java.io.Serializable>> buildConfigFields; - property public abstract org.gradle.api.provider.MapProperty<java.lang.String,java.lang.String> manifestPlaceholders; property public abstract org.gradle.api.provider.Provider<java.lang.String> namespace; property public abstract org.gradle.api.provider.ListProperty<org.gradle.api.file.RegularFile> proguardFiles; property public abstract com.android.build.api.variant.SigningConfig? signingConfig; @@ -2493,6 +2491,7 @@ package com.android.build.api.variant { method public com.android.build.api.variant.SourceDirectories.Layered? getMlModels(); method @Deprecated public com.android.build.api.variant.SourceDirectories.Flat? getRenderscript(); method public com.android.build.api.variant.SourceDirectories.Layered? getRes(); + method public com.android.build.api.variant.SourceDirectories.Flat? getResources(); method public com.android.build.api.variant.SourceDirectories.Layered? getShaders(); property public abstract com.android.build.api.variant.SourceDirectories.Flat? aidl; property public abstract com.android.build.api.variant.SourceDirectories.Layered? assets; @@ -2502,6 +2501,7 @@ package com.android.build.api.variant { property public abstract com.android.build.api.variant.SourceDirectories.Layered? mlModels; property @Deprecated public abstract com.android.build.api.variant.SourceDirectories.Flat? renderscript; property public abstract com.android.build.api.variant.SourceDirectories.Layered? res; + property public abstract com.android.build.api.variant.SourceDirectories.Flat? resources; property public abstract com.android.build.api.variant.SourceDirectories.Layered? shaders; } @@ -2509,6 +2509,8 @@ package com.android.build.api.variant { } public interface TestComponent extends com.android.build.api.variant.Component { + method public org.gradle.api.provider.MapProperty<java.lang.String,java.lang.String> getManifestPlaceholders(); + property public abstract org.gradle.api.provider.MapProperty<java.lang.String,java.lang.String> manifestPlaceholders; } @org.gradle.api.Incubating public interface TestFixtures extends com.android.build.api.variant.GeneratesAar com.android.build.api.variant.Component com.android.build.api.variant.HasAndroidResources { diff --git a/build-system/gradle-api/src/main/java/com/android/build/api/variant/AndroidTest.kt b/build-system/gradle-api/src/main/java/com/android/build/api/variant/AndroidTest.kt index 16d12c5d56..4eeda30030 100644 --- a/build-system/gradle-api/src/main/java/com/android/build/api/variant/AndroidTest.kt +++ b/build-system/gradle-api/src/main/java/com/android/build/api/variant/AndroidTest.kt @@ -45,16 +45,6 @@ interface AndroidTest : GeneratesTestApk, TestComponent, HasAndroidResources { val buildConfigFields: MapProperty<String, out BuildConfigField<out Serializable>> /** - * [MapProperty] of the variant's manifest placeholders. - * - * Placeholders are organized with a key and a value. The value is a [String] that will be - * used as is in the merged manifest. - * - * @return The [MapProperty] with keys as [String]. - */ - val manifestPlaceholders: MapProperty<String, String> - - /** * Variant's signingConfig, initialized by the corresponding DSL element. * @return Variant's config or null if the variant is not configured for signing. */ diff --git a/build-system/gradle-api/src/main/java/com/android/build/api/variant/Sources.kt b/build-system/gradle-api/src/main/java/com/android/build/api/variant/Sources.kt index 5188957c5d..ea03c3adf4 100644 --- a/build-system/gradle-api/src/main/java/com/android/build/api/variant/Sources.kt +++ b/build-system/gradle-api/src/main/java/com/android/build/api/variant/Sources.kt @@ -42,6 +42,11 @@ interface Sources { val res: SourceDirectories.Layered? /** + * Access to the Java-style resources sources folders. + */ + val resources: SourceDirectories.Flat? + + /** * Access to the Android assets sources folders. */ val assets: SourceDirectories.Layered? diff --git a/build-system/gradle-api/src/main/java/com/android/build/api/variant/TestComponent.kt b/build-system/gradle-api/src/main/java/com/android/build/api/variant/TestComponent.kt index 97dc50d78b..a959fb3c4e 100644 --- a/build-system/gradle-api/src/main/java/com/android/build/api/variant/TestComponent.kt +++ b/build-system/gradle-api/src/main/java/com/android/build/api/variant/TestComponent.kt @@ -16,4 +16,16 @@ package com.android.build.api.variant -interface TestComponent: Component +import org.gradle.api.provider.MapProperty + +interface TestComponent: Component { + /** + * [MapProperty] of the test component's manifest placeholders. + * + * Placeholders are organized with a key and a value. The value is a [String] that will be + * used as is in the merged manifest. + * + * @return the [MapProperty] with keys as [String] + */ + val manifestPlaceholders: MapProperty<String, String> +} diff --git a/build-system/gradle-core/lint_baseline.xml b/build-system/gradle-core/lint_baseline.xml index b616cbaac8..4d68aa1f6c 100755 --- a/build-system/gradle-core/lint_baseline.xml +++ b/build-system/gradle-core/lint_baseline.xml @@ -14,7 +14,7 @@ message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."> <location file="src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt" - line="152"/> + line="155"/> </issue> <issue @@ -22,7 +22,7 @@ message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."> <location file="src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt" - line="158"/> + line="161"/> </issue> <issue @@ -30,7 +30,7 @@ message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."> <location file="src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt" - line="195"/> + line="198"/> </issue> <issue @@ -38,7 +38,7 @@ message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."> <location file="src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt" - line="201"/> + line="204"/> </issue> <issue @@ -56,22 +56,6 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt" - line="56"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt" - line="56"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location file="src/main/java/com/android/build/gradle/internal/test/AbstractTestDataImpl.kt" line="66"/> </issue> @@ -161,7 +145,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledTestVariant.kt" - line="89"/> + line="82"/> </issue> <issue @@ -177,7 +161,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="56"/> + line="54"/> </issue> <issue @@ -185,7 +169,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="62"/> + line="60"/> </issue> <issue @@ -193,7 +177,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="75"/> + line="73"/> </issue> <issue @@ -201,7 +185,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="98"/> + line="96"/> </issue> <issue @@ -224,8 +208,16 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt" - line="114"/> + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/AndroidTestComponentDslInfoImpl.kt" + line="70"/> + </issue> + + <issue + id="AvoidByLazy" + message="Avoid `by lazy` for simple lazy initialization"> + <location + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/AndroidTestComponentDslInfoImpl.kt" + line="133"/> </issue> <issue @@ -233,7 +225,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt" - line="143"/> + line="116"/> </issue> <issue @@ -241,7 +233,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt" - line="151"/> + line="145"/> </issue> <issue @@ -249,7 +241,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt" - line="225"/> + line="153"/> </issue> <issue @@ -257,7 +249,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt" - line="258"/> + line="227"/> </issue> <issue @@ -288,6 +280,14 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/ApplicationVariantDslInfoImpl.kt" + line="76"/> + </issue> + + <issue + id="AvoidByLazy" + message="Avoid `by lazy` for simple lazy initialization"> + <location file="src/main/java/com/android/build/api/variant/impl/ApplicationVariantImpl.kt" line="93"/> </issue> @@ -464,8 +464,8 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="169"/> + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/ComponentDslInfoImpl.kt" + line="79"/> </issue> <issue @@ -473,7 +473,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="205"/> + line="167"/> </issue> <issue @@ -481,7 +481,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="301"/> + line="291"/> </issue> <issue @@ -489,7 +489,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="382"/> + line="371"/> </issue> <issue @@ -497,7 +497,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="390"/> + line="379"/> </issue> <issue @@ -505,7 +505,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/impl/ComponentImpl.kt" - line="420"/> + line="409"/> </issue> <issue @@ -513,7 +513,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/cxx/gradle/generator/CxxConfigurationModel.kt" - line="75"/> + line="76"/> </issue> <issue @@ -608,22 +608,6 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt" - line="55"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt" - line="63"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location file="src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryVariantScopeImpl.kt" line="37"/> </issue> @@ -689,7 +673,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt" - line="121"/> + line="120"/> </issue> <issue @@ -704,16 +688,16 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/databinding/MergingFileLookup.kt" - line="36"/> + file="src/main/java/com/android/build/api/component/impl/features/ManifestPlaceholdersCreationConfigImpl.kt" + line="28"/> </issue> <issue id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="64"/> + file="src/main/java/com/android/build/gradle/internal/databinding/MergingFileLookup.kt" + line="36"/> </issue> <issue @@ -721,15 +705,15 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="68"/> + line="71"/> </issue> <issue id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/ndk/NdkPlatform.kt" - line="59"/> + file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" + line="75"/> </issue> <issue @@ -737,14 +721,6 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/ndk/NdkPlatform.kt" - line="67"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" line="59"/> </issue> @@ -752,8 +728,8 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" - line="75"/> + file="src/main/java/com/android/build/gradle/internal/ndk/NdkPlatform.kt" + line="67"/> </issue> <issue @@ -761,7 +737,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" - line="94"/> + line="92"/> </issue> <issue @@ -912,6 +888,22 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestProjectVariantDslInfoImpl.kt" + line="128"/> + </issue> + + <issue + id="AvoidByLazy" + message="Avoid `by lazy` for simple lazy initialization"> + <location + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestProjectVariantDslInfoImpl.kt" + line="140"/> + </issue> + + <issue + id="AvoidByLazy" + message="Avoid `by lazy` for simple lazy initialization"> + <location file="src/main/java/com/android/build/api/variant/impl/TestVariantImpl.kt" line="97"/> </issue> @@ -952,23 +944,23 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt" - line="137"/> + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/UnitTestComponentDslInfoImpl.kt" + line="59"/> </issue> <issue id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="142"/> + file="src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt" + line="137"/> </issue> <issue id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/api/variant/impl/VariantImpl.kt" + file="src/main/java/com/android/build/gradle/internal/core/dsl/impl/VariantDslInfoImpl.kt" line="135"/> </issue> @@ -977,7 +969,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/variant/impl/VariantImpl.kt" - line="206"/> + line="137"/> </issue> <issue @@ -985,7 +977,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/variant/impl/VariantImpl.kt" - line="300"/> + line="215"/> </issue> <issue @@ -993,7 +985,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="54"/> + line="129"/> </issue> <issue @@ -1001,7 +993,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="119"/> + line="194"/> </issue> <issue @@ -1009,7 +1001,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="160"/> + line="235"/> </issue> <issue @@ -1017,7 +1009,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="163"/> + line="238"/> </issue> <issue @@ -1025,7 +1017,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="171"/> + line="246"/> </issue> <issue @@ -1033,7 +1025,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="200"/> + line="275"/> </issue> <issue @@ -1041,7 +1033,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="210"/> + line="285"/> </issue> <issue @@ -1049,7 +1041,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt" - line="215"/> + line="290"/> </issue> <issue @@ -1073,7 +1065,7 @@ message="Do not use `java.nio.file.Files.copy(Path, Path)`. Instead, use `FileUtils.copyFile(Path, Path)` or Kotlin's `File#copyTo(File)`"> <location file="src/main/java/com/android/build/gradle/internal/tasks/AsarToApksTransform.kt" - line="72"/> + line="73"/> </issue> <issue @@ -1081,7 +1073,7 @@ message="This reference is unused: name"> <location file="src/main/java/com/android/build/gradle/internal/tasks/DependencyReportTask.kt" - line="49"/> + line="51"/> </issue> <issue @@ -1089,7 +1081,7 @@ message="This reference is unused: name"> <location file="src/main/java/com/android/build/gradle/internal/tasks/DependencyReportTask.kt" - line="56"/> + line="58"/> </issue> <issue @@ -1105,7 +1097,7 @@ message="This reference is unused: FD_OUTPUT"> <location file="src/main/java/com/android/build/gradle/tasks/FusedLibraryManifestMergerTask.kt" - line="173"/> + line="176"/> </issue> <issue @@ -1129,47 +1121,7 @@ message="This reference is unused: FD_OUTPUT"> <location file="src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestMergerTask.kt" - line="80"/> - </issue> - - <issue - id="NoOp" - message="This reference is unused: testApplicationId"> - <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="216"/> - </issue> - - <issue - id="NoOp" - message="This reference is unused: testApplicationId"> - <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="312"/> - </issue> - - <issue - id="NoOp" - message="This reference is unused: testInstrumentationRunner"> - <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="484"/> - </issue> - - <issue - id="NoOp" - message="This reference is unused: testHandleProfiling"> - <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="527"/> - </issue> - - <issue - id="NoOp" - message="This reference is unused: testFunctionalTest"> - <location - file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="548"/> + line="83"/> </issue> <issue @@ -1177,7 +1129,7 @@ message="Avoid using `org.gradle.api.Project.exec` as it is incompatible with Gradle instant execution."> <location file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="56"/> + line="63"/> </issue> <issue @@ -1201,7 +1153,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/internal/tasks/featuresplit/FeatureSetMetadataWriterTask.kt" - line="127"/> + line="130"/> </issue> <issue @@ -1217,7 +1169,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt" - line="58"/> + line="61"/> </issue> <issue @@ -1225,7 +1177,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt" - line="60"/> + line="63"/> </issue> <issue @@ -1249,7 +1201,7 @@ message="Use `Integer.valueOf(index)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="79"/> + line="81"/> </issue> <issue @@ -1257,7 +1209,7 @@ message="Use `Integer.valueOf(libraryList.size)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="102"/> + line="104"/> </issue> <issue @@ -1265,7 +1217,7 @@ message="Use `Integer.valueOf(origIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="112"/> + line="114"/> </issue> <issue @@ -1273,7 +1225,7 @@ message="Use `Integer.valueOf(libraryDep.libraryIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="117"/> + line="119"/> </issue> <issue @@ -1281,7 +1233,7 @@ message="Use `Integer.valueOf(depIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="120"/> + line="122"/> </issue> <issue @@ -1289,7 +1241,7 @@ message="Use `Integer.valueOf(depIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="133"/> + line="135"/> </issue> <issue @@ -1409,7 +1361,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/AsarToApksTransform.kt" - line="77"/> + line="78"/> </issue> <issue @@ -1417,7 +1369,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleToApkTask.kt" - line="111"/> + line="113"/> </issue> <issue @@ -1425,7 +1377,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleToStandaloneApkTask.kt" - line="124"/> + line="126"/> </issue> <issue @@ -1449,7 +1401,7 @@ message="Avoid using new ForkJoinPool instances when possible. Prefer using the IntelliJ application pool via `com.intellij.openapi.application.Application#executeOnPooledThread`, or for the Android Gradle Plugin use `com.android.build.gradle.internal.tasks.Workers`. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt" - line="797"/> + line="799"/> </issue> </issues> diff --git a/build-system/gradle-core/src/apiTest/kotlin/com/android/build/api/apiTest/kotlin/AddCustomSourceTest.kt b/build-system/gradle-core/src/apiTest/kotlin/com/android/build/api/apiTest/kotlin/AddCustomSourceTest.kt index 3c13b7f932..d7ad65620f 100644 --- a/build-system/gradle-core/src/apiTest/kotlin/com/android/build/api/apiTest/kotlin/AddCustomSourceTest.kt +++ b/build-system/gradle-core/src/apiTest/kotlin/com/android/build/api/apiTest/kotlin/AddCustomSourceTest.kt @@ -318,7 +318,7 @@ where source files will be generated and added to the compilation task. Truth.assertThat(output).contains("addCustomSourceTypeInDslAndVariantTest/app/src/main/toml") Truth.assertThat(output).contains("addCustomSourceTypeInDslAndVariantTest/app/src/debug/toml") Truth.assertThat(output).contains("addCustomSourceTypeInDslAndVariantTest/app/third_party/debug/toml") - Truth.assertThat(output).contains("addCustomSourceTypeInDslAndVariantTest/app/build/toml/debugAddCustomSources") + Truth.assertThat(output).contains("addCustomSourceTypeInDslAndVariantTest/app/build/generated/toml/debugAddCustomSources") Truth.assertThat(output).contains("BUILD SUCCESSFUL") super.onVariantStats { super.onVariantStats { diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledSources.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledSources.kt index a18aa3a901..1928eed5a1 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledSources.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledSources.kt @@ -130,6 +130,17 @@ open class AnalyticsEnabledSources @Inject constructor( objectFactory) } + override val resources: SourceDirectories.Flat + get() { + stats.variantApiAccessBuilder.addVariantPropertiesAccessBuilder().type = + VariantPropertiesMethodType.SOURCES_RESOURCES_ACCESS_VALUE + return objectFactory.newInstance( + AnalyticsEnabledFlat::class.java, + delegate.resources, + stats, + objectFactory) + } + override fun getByName(name: String): SourceDirectories.Flat { stats.variantApiAccessBuilder.addVariantPropertiesAccessBuilder().type = VariantPropertiesMethodType.SOURCES_EXTRAS_ACCESS_VALUE diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledUnitTest.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledUnitTest.kt index e90b5434e8..1ca890dc00 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledUnitTest.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledUnitTest.kt @@ -17,12 +17,21 @@ package com.android.build.api.component.analytics import com.android.build.api.variant.UnitTest +import com.android.tools.build.gradle.internal.profile.VariantPropertiesMethodType import com.google.wireless.android.sdk.stats.GradleBuildVariant import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.MapProperty import javax.inject.Inject open class AnalyticsEnabledUnitTest @Inject constructor( override val delegate: UnitTest, stats: GradleBuildVariant.Builder, objectFactory: ObjectFactory -) : AnalyticsEnabledTestComponent(delegate, stats, objectFactory), UnitTest +) : AnalyticsEnabledTestComponent(delegate, stats, objectFactory), UnitTest { + override val manifestPlaceholders: MapProperty<String, String> + get() { + stats.variantApiAccessBuilder.addVariantPropertiesAccessBuilder().type = + VariantPropertiesMethodType.MANIFEST_PLACEHOLDERS_VALUE + return delegate.manifestPlaceholders + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt index 8497bf44c5..ef37969e38 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/AndroidTestImpl.kt @@ -21,6 +21,7 @@ import com.android.build.api.artifact.impl.ArtifactsImpl import com.android.build.api.component.analytics.AnalyticsEnabledAndroidTest import com.android.build.api.component.impl.features.AndroidResourcesCreationConfigImpl import com.android.build.api.component.impl.features.BuildConfigCreationConfigImpl +import com.android.build.api.component.impl.features.ManifestPlaceholdersCreationConfigImpl import com.android.build.api.component.impl.features.RenderscriptCreationConfigImpl import com.android.build.api.dsl.CommonExtension import com.android.build.api.extension.impl.VariantApiOperationsRegistrar @@ -46,6 +47,7 @@ import com.android.build.gradle.internal.component.VariantCreationConfig import com.android.build.gradle.internal.component.features.AndroidResourcesCreationConfig import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig import com.android.build.gradle.internal.component.features.FeatureNames +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig import com.android.build.gradle.internal.component.features.RenderscriptCreationConfig import com.android.build.gradle.internal.core.VariantSources import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo @@ -124,9 +126,6 @@ open class AndroidTestImpl @Inject constructor( override val debuggable: Boolean get() = dslInfo.isDebuggable - override val profileable: Boolean - get() = dslInfo.isProfileable - override val namespaceForR: Provider<String> = dslInfo.namespaceForR override val minSdkVersion: AndroidVersion @@ -150,7 +149,7 @@ open class AndroidTestImpl @Inject constructor( override val packaging: ApkPackaging by lazy { ApkPackagingImpl( - dslInfo.testedVariant!!.packaging, + dslInfo.testedVariantDslInfo.packaging, variantServices, minSdkVersion.apiLevel ) @@ -160,9 +159,9 @@ open class AndroidTestImpl @Inject constructor( get() { return when { mainVariant.componentType.isAar -> false - !dslInfo.getPostProcessingOptions().hasPostProcessingConfiguration() -> + !dslInfo.postProcessingOptions.hasPostProcessingConfiguration() -> mainVariant.minifiedEnabled - else -> dslInfo.getPostProcessingOptions().codeShrinkerEnabled() + else -> dslInfo.postProcessingOptions.codeShrinkerEnabled() } } @@ -170,9 +169,9 @@ open class AndroidTestImpl @Inject constructor( get() { return when { mainVariant.componentType.isAar -> false - !dslInfo.getPostProcessingOptions().hasPostProcessingConfiguration() -> + !dslInfo.postProcessingOptions.hasPostProcessingConfiguration() -> mainVariant.resourcesShrink - else -> dslInfo.getPostProcessingOptions().resourcesShrinkingEnabled() + else -> dslInfo.postProcessingOptions.resourcesShrinkingEnabled() } } @@ -249,13 +248,16 @@ open class AndroidTestImpl @Inject constructor( ) } + override val manifestPlaceholders: MapProperty<String, String> + get() = manifestPlaceholdersCreationConfig.placeholders + // --------------------------------------------------------------------------------------------- // INTERNAL API // --------------------------------------------------------------------------------------------- // Even if android resources is disabled in a library project, we still need to merge and link // external resources to create the test apk. - override val androidResourcesCreationConfig: AndroidResourcesCreationConfig by lazy { + override val androidResourcesCreationConfig: AndroidResourcesCreationConfig by lazy(LazyThreadSafetyMode.NONE) { AndroidResourcesCreationConfigImpl( this, dslInfo, @@ -263,7 +265,7 @@ open class AndroidTestImpl @Inject constructor( ) } - override val buildConfigCreationConfig: BuildConfigCreationConfig? by lazy { + override val buildConfigCreationConfig: BuildConfigCreationConfig? by lazy(LazyThreadSafetyMode.NONE) { if (buildFeatures.buildConfig) { BuildConfigCreationConfigImpl( this, @@ -275,7 +277,7 @@ open class AndroidTestImpl @Inject constructor( } } - override val renderscriptCreationConfig: RenderscriptCreationConfig? by lazy { + override val renderscriptCreationConfig: RenderscriptCreationConfig? by lazy(LazyThreadSafetyMode.NONE) { if (buildFeatures.renderScript) { RenderscriptCreationConfigImpl( dslInfo, @@ -287,6 +289,13 @@ open class AndroidTestImpl @Inject constructor( } } + override val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig by lazy(LazyThreadSafetyMode.NONE) { + ManifestPlaceholdersCreationConfigImpl( + dslInfo, + internalServices + ) + } + override val targetSdkVersionOverride: AndroidVersion? get() = mainVariant.targetSdkVersionOverride @@ -368,9 +377,6 @@ open class AndroidTestImpl @Inject constructor( override fun getJava8LangSupportType(): Java8LangSupport = delegate.getJava8LangSupportType() - override val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? = - dslInfo.signingConfig - override val defaultGlslcArgs: List<String> get() = dslInfo.defaultGlslcArgs override val scopedGlslcArgs: Map<String, List<String>> @@ -390,7 +396,7 @@ open class AndroidTestImpl @Inject constructor( get() = isTestCoverageEnabled && mainVariant.componentType.isAar override val postProcessingFeatures: PostprocessingFeatures? - get() = dslInfo.getPostProcessingOptions().getPostprocessingFeatures() + get() = dslInfo.postProcessingOptions.getPostprocessingFeatures() // --------------------------------------------------------------------------------------------- // DO NOT USE, Deprecated DSL APIs. diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ApkCreationConfigImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ApkCreationConfigImpl.kt index 8efde530c2..8da9ba6214 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ApkCreationConfigImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ApkCreationConfigImpl.kt @@ -32,9 +32,6 @@ open class ApkCreationConfigImpl<T: ApkCreationConfig>( val isDebuggable: Boolean get() = dslInfo.isDebuggable - val isProfileable: Boolean - get() = dslInfo.isProfileable - override val needsShrinkDesugarLibrary: Boolean get() { if (!isCoreLibraryDesugaringEnabled(config)) { diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt index 66327cc676..8228bd6d98 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ComponentImpl.kt @@ -45,10 +45,9 @@ import com.android.build.gradle.internal.component.features.InstrumentationCreat import com.android.build.gradle.internal.component.features.ResValuesCreationConfig import com.android.build.gradle.internal.component.legacy.OldVariantApiLegacySupport import com.android.build.gradle.internal.core.ProductFlavor -import com.android.build.gradle.internal.core.VariantDslInfoImpl import com.android.build.gradle.internal.core.VariantSources import com.android.build.gradle.internal.core.dsl.ComponentDslInfo -import com.android.build.gradle.internal.core.dsl.PublishableVariantDslInfo +import com.android.build.gradle.internal.core.dsl.PublishableComponentDslInfo import com.android.build.gradle.internal.dependency.AndroidAttributes import com.android.build.gradle.internal.dependency.VariantDependencies import com.android.build.gradle.internal.dependency.getProvidedClasspath @@ -84,7 +83,6 @@ import org.gradle.api.attributes.DocsType import org.gradle.api.attributes.LibraryElements import org.gradle.api.file.FileCollection import org.gradle.api.file.FileSystemLocation -import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import java.io.File @@ -202,14 +200,6 @@ abstract class ComponentImpl<DslInfoT: ComponentDslInfo>( ProductFlavor(it) } - override val manifestPlaceholders: MapProperty<String, String> by lazy { - internalServices.mapPropertyOf( - String::class.java, - String::class.java, - dslInfo.manifestPlaceholders - ) - } - // --------------------------------------------------------------------------------------------- // Private stuff // --------------------------------------------------------------------------------------------- @@ -332,7 +322,7 @@ abstract class ComponentImpl<DslInfoT: ComponentDslInfo>( outputSpec.publishedConfigTypes.any { it.isPublicationConfig } if (isPublicationConfigs) { - val components = (dslInfo as PublishableVariantDslInfo).publishInfo!!.components + val components = (dslInfo as PublishableComponentDslInfo).publishInfo!!.components for(component in components) { publishIntermediateArtifact( artifactProvider, @@ -376,13 +366,12 @@ abstract class ComponentImpl<DslInfoT: ComponentDslInfo>( override val isAndroidTestCoverageEnabled: Boolean get() = dslInfo.isAndroidTestCoverageEnabled - override val modelV1LegacySupport = - ModelV1LegacySupportImpl(dslInfo as VariantDslInfoImpl) + override val modelV1LegacySupport = ModelV1LegacySupportImpl(dslInfo) override val oldVariantApiLegacySupport: OldVariantApiLegacySupport? by lazy { OldVariantApiLegacySupportImpl( this, - dslInfo as VariantDslInfoImpl, + dslInfo, variantData!! ) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ConsumableCreationConfigImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ConsumableCreationConfigImpl.kt index 1e093e97b4..58e57e2312 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ConsumableCreationConfigImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ConsumableCreationConfigImpl.kt @@ -18,8 +18,8 @@ package com.android.build.api.component.impl import com.android.build.api.variant.AndroidVersion import com.android.build.api.variant.impl.getFeatureLevel import com.android.build.gradle.internal.component.ConsumableCreationConfig +import com.android.build.gradle.internal.component.DynamicFeatureCreationConfig import com.android.build.gradle.internal.core.dsl.ConsumableComponentDslInfo -import com.android.build.gradle.internal.core.dsl.DynamicFeatureVariantDslInfo import com.android.build.gradle.internal.scope.Java8LangSupport import com.android.builder.dexing.DexingType import com.android.builder.errors.IssueReporter @@ -49,17 +49,20 @@ open class ConsumableCreationConfigImpl<T: ConsumableCreationConfig>( ) { val dexingType: DexingType - get() = (dslInfo as? DynamicFeatureVariantDslInfo)?.dexingType ?: - if (config.isMultiDexEnabled) { - if (config.minSdkVersion.getFeatureLevel() >= 21 || - dslInfo.targetDeployApiFromIDE?.let { it >= 21 } == true - ) { - // if minSdkVersion is 21+ or we are deploying to 21+ device, use native multidex + get() = + if (config is DynamicFeatureCreationConfig) { + // dynamic features can always be build in native multidex mode DexingType.NATIVE_MULTIDEX - } else DexingType.LEGACY_MULTIDEX - } else { - DexingType.MONO_DEX - } + } else if (config.isMultiDexEnabled) { + if (config.minSdkVersion.getFeatureLevel() >= 21 || + dslInfo.targetDeployApiFromIDE?.let { it >= 21 } == true + ) { + // if minSdkVersion is 21+ or we are deploying to 21+ device, use native multidex + DexingType.NATIVE_MULTIDEX + } else DexingType.LEGACY_MULTIDEX + } else { + DexingType.MONO_DEX + } fun getNeedsMergedJavaResStream(): Boolean { // We need to create a stream from the merged java resources if we're in a library module, diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProvider.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProvider.kt index 3c1461ebd7..cb23259a2c 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProvider.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProvider.kt @@ -47,6 +47,11 @@ interface DefaultSourcesProvider { fun getRes(lateAdditionsDelegate: LayeredSourceDirectoriesImpl): List<DirectoryEntries> /** + * the list of sources [DirectoryEntry] for java resources. + */ + fun getResources(lateAdditionsDelegate: FlatSourceDirectoriesImpl): List<DirectoryEntry> + + /** * the list of [DirectoryEntries] for assets. * * The [List] is ordered in ascending order of importance, meaning the first set is meant to be diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProviderImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProviderImpl.kt index 8f9963fc52..fb7234cca1 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProviderImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/DefaultSourcesProviderImpl.kt @@ -63,6 +63,7 @@ class DefaultSourcesProviderImpl( } override fun getRes(lateAdditionsDelegate: LayeredSourceDirectoriesImpl): List<DirectoryEntries> = component.defaultResSources(lateAdditionsDelegate) + override fun getResources(lateAdditionsDelegate: FlatSourceDirectoriesImpl): List<DirectoryEntry> = flattenSourceProviders(lateAdditionsDelegate) { sourceSet -> sourceSet.resources } override fun getAssets(lateAdditionsDelegate: LayeredSourceDirectoriesImpl): List<DirectoryEntries> = defaultAssetsSources(lateAdditionsDelegate) override fun getJniLibs(lateAdditionsDelegate: LayeredSourceDirectoriesImpl): List<DirectoryEntries> = getSourceList(lateAdditionsDelegate, DefaultAndroidSourceSet::jniLibs) diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ModelV1LegacySupportImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ModelV1LegacySupportImpl.kt index aff7ab573e..822fe0c78c 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ModelV1LegacySupportImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/ModelV1LegacySupportImpl.kt @@ -18,16 +18,17 @@ package com.android.build.api.component.impl import com.android.build.gradle.internal.component.legacy.ModelV1LegacySupport import com.android.build.gradle.internal.core.MergedFlavor -import com.android.build.gradle.internal.core.VariantDslInfoImpl +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.core.dsl.impl.ComponentDslInfoImpl import org.gradle.api.provider.Provider class ModelV1LegacySupportImpl( - private val variantDslInfo: VariantDslInfoImpl + private val dslInfo: ComponentDslInfo ): ModelV1LegacySupport { override val mergedFlavor: MergedFlavor - get() = variantDslInfo.mergedFlavor + get() = (dslInfo as ComponentDslInfoImpl).mergedFlavor override val dslApplicationId: Provider<String> - get() = variantDslInfo.applicationId + get() = dslInfo.applicationId } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/OldVariantApiLegacySupportImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/OldVariantApiLegacySupportImpl.kt index ef579427bf..040203ec95 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/OldVariantApiLegacySupportImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/OldVariantApiLegacySupportImpl.kt @@ -27,7 +27,9 @@ import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.component.TestComponentCreationConfig import com.android.build.gradle.internal.component.legacy.OldVariantApiLegacySupport import com.android.build.gradle.internal.core.MergedFlavor -import com.android.build.gradle.internal.core.VariantDslInfoImpl +import com.android.build.gradle.internal.core.dsl.ApkProducingComponentDslInfo +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.core.dsl.impl.ComponentDslInfoImpl import com.android.build.gradle.internal.dependency.ArtifactCollectionWithExtraArtifact import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.publishing.PublishingSpecs.Companion.getVariantPublishingSpec @@ -43,18 +45,20 @@ import java.io.Serializable class OldVariantApiLegacySupportImpl( private val component: ComponentCreationConfig, - private val variantDslInfo: VariantDslInfoImpl, + private val dslInfo: ComponentDslInfo, override val variantData: BaseVariantData ): OldVariantApiLegacySupport { override val buildTypeObj: BuildType - get() = variantDslInfo.buildTypeObj + get() = (dslInfo as ComponentDslInfoImpl).buildTypeObj override val productFlavorList: List<ProductFlavor> - get() = variantDslInfo.productFlavorList + get() = dslInfo.productFlavorList override val mergedFlavor: MergedFlavor - get() = variantDslInfo.mergedFlavor + get() = (dslInfo as ComponentDslInfoImpl).mergedFlavor override val javaCompileOptions: JavaCompileOptions - get() = variantDslInfo.javaCompileOptions + get() = dslInfo.javaCompileOptions + override val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? = + (dslInfo as? ApkProducingComponentDslInfo)?.signingConfig override fun getJavaClasspathArtifacts( configType: AndroidArtifacts.ConsumedConfigType, @@ -155,7 +159,7 @@ class OldVariantApiLegacySupportImpl( } override fun addDataBindingArgsToOldVariantApi(args: DataBindingCompilerArguments) { - variantDslInfo.javaCompileOptions.annotationProcessorOptions + dslInfo.javaCompileOptions.annotationProcessorOptions .compilerArgumentProviders.add(args) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt index ba2f384da3..acecbaf670 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/TestFixturesImpl.kt @@ -35,6 +35,7 @@ import com.android.build.gradle.internal.component.TestFixturesCreationConfig import com.android.build.gradle.internal.component.VariantCreationConfig import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig import com.android.build.gradle.internal.component.features.FeatureNames +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig import com.android.build.gradle.internal.component.legacy.OldVariantApiLegacySupport import com.android.build.gradle.internal.core.VariantSources import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo @@ -89,7 +90,7 @@ open class TestFixturesImpl @Inject constructor( ), TestFixtures, TestFixturesCreationConfig { override val description: String - get() = if (dslInfo.hasFlavors()) { + get() = if (productFlavorList.isNotEmpty()) { val sb = StringBuilder(50) dslInfo.componentIdentity.buildType?.let { sb.appendCapitalized(it) } sb.append(" build for flavor ") @@ -110,8 +111,6 @@ open class TestFixturesImpl @Inject constructor( internalServices.providerOf(String::class.java, variantDslInfo.namespace) override val debuggable: Boolean get() = mainVariant.debuggable - override val profileable: Boolean - get() = mainVariant.profileable override val minSdkVersion: AndroidVersion get() = mainVariant.minSdkVersion override val targetSdkVersion: AndroidVersion @@ -121,14 +120,9 @@ open class TestFixturesImpl @Inject constructor( override val aarMetadata: AarMetadata = internalServices.newInstance(AarMetadata::class.java).also { - it.minCompileSdk.set(variantDslInfo.aarMetadata.minCompileSdk ?: 1) - it.minCompileSdkExtension.set( - variantDslInfo.aarMetadata.minCompileSdkExtension - ?: DEFAULT_MIN_COMPILE_SDK_EXTENSION - ) - it.minAgpVersion.set( - variantDslInfo.aarMetadata.minAgpVersion ?: DEFAULT_MIN_AGP_VERSION - ) + it.minCompileSdk.set(1) + it.minCompileSdkExtension.set(DEFAULT_MIN_COMPILE_SDK_EXTENSION) + it.minAgpVersion.set(DEFAULT_MIN_AGP_VERSION) } override val javaCompilation: JavaCompilation = @@ -144,6 +138,9 @@ open class TestFixturesImpl @Inject constructor( override val buildConfigCreationConfig: BuildConfigCreationConfig? = null + override val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig? + get() = mainVariant.manifestPlaceholdersCreationConfig + override val targetSdkVersionOverride: AndroidVersion? get() = mainVariant.targetSdkVersionOverride diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt index 877a9dbdb8..bada50a19c 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/UnitTestImpl.kt @@ -20,6 +20,7 @@ import com.android.build.api.artifact.impl.ArtifactsImpl import com.android.build.api.component.UnitTest import com.android.build.api.component.analytics.AnalyticsEnabledUnitTest import com.android.build.api.component.impl.features.AndroidResourcesCreationConfigImpl +import com.android.build.api.component.impl.features.ManifestPlaceholdersCreationConfigImpl import com.android.build.api.dsl.CommonExtension import com.android.build.api.extension.impl.VariantApiOperationsRegistrar import com.android.build.api.variant.AndroidVersion @@ -31,9 +32,10 @@ import com.android.build.gradle.internal.component.UnitTestCreationConfig import com.android.build.gradle.internal.component.VariantCreationConfig import com.android.build.gradle.internal.component.features.AndroidResourcesCreationConfig import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig -import com.android.build.gradle.internal.core.VariantDslInfoImpl +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig import com.android.build.gradle.internal.core.VariantSources import com.android.build.gradle.internal.core.dsl.UnitTestComponentDslInfo +import com.android.build.gradle.internal.core.dsl.impl.DEFAULT_TEST_RUNNER import com.android.build.gradle.internal.dependency.VariantDependencies import com.android.build.gradle.internal.pipeline.TransformManager import com.android.build.gradle.internal.scope.BuildFeatureValues @@ -45,6 +47,7 @@ import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig import com.android.build.gradle.internal.variant.BaseVariantData import com.android.build.gradle.internal.variant.VariantPathHelper import com.google.wireless.android.sdk.stats.GradleBuildVariant +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Provider import javax.inject.Inject @@ -105,7 +108,7 @@ open class UnitTestImpl @Inject constructor( * the instrumentation tag to be present in the merged manifest to process android resources. */ override val instrumentationRunner: Provider<String> - get() = services.provider { VariantDslInfoImpl.DEFAULT_TEST_RUNNER } + get() = services.provider { DEFAULT_TEST_RUNNER } override val testedApplicationId: Provider<String> get() = mainVariant.applicationId @@ -113,15 +116,15 @@ open class UnitTestImpl @Inject constructor( override val debuggable: Boolean get() = mainVariant.debuggable - override val profileable: Boolean - get() = mainVariant.profileable + override val manifestPlaceholders: MapProperty<String, String> + get() = manifestPlaceholdersCreationConfig.placeholders // these would normally be public but not for unit-test. They are there to feed the // manifest but aren't actually used. override val isTestCoverageEnabled: Boolean get() = dslInfo.isUnitTestCoverageEnabled - override val androidResourcesCreationConfig: AndroidResourcesCreationConfig? by lazy { + override val androidResourcesCreationConfig: AndroidResourcesCreationConfig? by lazy(LazyThreadSafetyMode.NONE) { // in case of unit tests, we add the R jar even if android resources are // disabled (includeAndroidResources) as we want to be able to compile against // the values inside. @@ -136,6 +139,13 @@ open class UnitTestImpl @Inject constructor( } } + override val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig by lazy(LazyThreadSafetyMode.NONE) { + ManifestPlaceholdersCreationConfigImpl( + dslInfo.testedVariantDslInfo, + internalServices + ) + } + override fun <T : Component> createUserVisibleVariantObject( projectServices: ProjectServices, operationsRegistrar: VariantApiOperationsRegistrar<out CommonExtension<*, *, *, *>, out VariantBuilder, out Variant>, diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/features/ManifestPlaceholdersCreationConfigImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/features/ManifestPlaceholdersCreationConfigImpl.kt new file mode 100644 index 0000000000..ae7bee65c8 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/api/component/impl/features/ManifestPlaceholdersCreationConfigImpl.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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.api.component.impl.features + +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig +import com.android.build.gradle.internal.core.dsl.ConsumableComponentDslInfo +import com.android.build.gradle.internal.services.VariantServices +import org.gradle.api.provider.MapProperty + +class ManifestPlaceholdersCreationConfigImpl( + dslInfo: ConsumableComponentDslInfo, + internalServices: VariantServices +): ManifestPlaceholdersCreationConfig { + override val placeholders: MapProperty<String, String> by lazy { + internalServices.mapPropertyOf( + String::class.java, + String::class.java, + dslInfo.manifestPlaceholders + ) + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantBuilderImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantBuilderImpl.kt index f12c843af7..a93d533abb 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantBuilderImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantBuilderImpl.kt @@ -76,11 +76,11 @@ open class ApplicationVariantBuilderImpl @Inject constructor( } override var isMinifyEnabled: Boolean = - dslInfo.getPostProcessingOptions().codeShrinkerEnabled() + dslInfo.postProcessingOptions.codeShrinkerEnabled() set(value) = setMinificationIfPossible("minifyEnabled", value){ field = it } override var shrinkResources: Boolean = - dslInfo.getPostProcessingOptions().resourcesShrinkingEnabled() + dslInfo.postProcessingOptions.resourcesShrinkingEnabled() set(value) = setMinificationIfPossible("shrinkResources", value){ field = it } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantImpl.kt index 6c56e364b7..6bb95f7b55 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/ApplicationVariantImpl.kt @@ -179,7 +179,7 @@ open class ApplicationVariantImpl @Inject constructor( override val debuggable: Boolean get() = delegate.isDebuggable override val profileable: Boolean - get() = delegate.isProfileable + get() = dslInfo.isProfileable override val isCoreLibraryDesugaringEnabled: Boolean get() = delegate.isCoreLibraryDesugaringEnabled @@ -203,12 +203,6 @@ open class ApplicationVariantImpl @Inject constructor( } // --------------------------------------------------------------------------------------------- - // DO NOT USE, only present for old variant API. - // --------------------------------------------------------------------------------------------- - override val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? = - dslInfo.signingConfig - - // --------------------------------------------------------------------------------------------- // DO NOT USE, Deprecated DSL APIs. // --------------------------------------------------------------------------------------------- diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/DynamicFeatureVariantImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/DynamicFeatureVariantImpl.kt index f38f247dfa..0a2ca46c11 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/DynamicFeatureVariantImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/DynamicFeatureVariantImpl.kt @@ -55,6 +55,7 @@ import com.android.build.gradle.internal.variant.BaseVariantData import com.android.build.gradle.internal.variant.VariantPathHelper import com.android.build.gradle.options.StringOption import com.android.builder.dexing.DexingType +import com.android.builder.errors.IssueReporter import com.google.wireless.android.sdk.stats.GradleBuildVariant import org.gradle.api.provider.Property import org.gradle.api.provider.Provider @@ -91,6 +92,17 @@ open class DynamicFeatureVariantImpl @Inject constructor( ), DynamicFeatureVariant, DynamicFeatureCreationConfig, HasAndroidTest, HasTestFixtures { init { + // TODO: Should be removed once we stop implementing all build type interfaces in one class + if (dslInfo.isMultiDexSetFromDsl) { + services.issueReporter + .reportWarning( + IssueReporter.Type.GENERIC, + "Native multidex is always used for dynamic features. Please " + + "remove 'multiDexEnabled true|false' from your " + + "build.gradle file." + ) + } + dslInfo.multiDexKeepProguard?.let { artifacts.getArtifactContainer(MultipleArtifact.MULTIDEX_KEEP_PROGUARD) .addInitialProvider(null, internalServices.toRegularFileProvider(it)) @@ -171,8 +183,6 @@ open class DynamicFeatureVariantImpl @Inject constructor( override val shouldPackageDesugarLibDex: Boolean = false override val debuggable: Boolean get() = delegate.isDebuggable - override val profileable: Boolean - get() = delegate.isProfileable override val isCoreLibraryDesugaringEnabled: Boolean get() = delegate.isCoreLibraryDesugaringEnabled @@ -191,12 +201,6 @@ open class DynamicFeatureVariantImpl @Inject constructor( get() = dslInfo.isAndroidTestCoverageEnabled // --------------------------------------------------------------------------------------------- - // DO NOT USE, only present for old variant API. - // --------------------------------------------------------------------------------------------- - override val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? = - dslInfo.signingConfig - - // --------------------------------------------------------------------------------------------- // DO NOT USE, Deprecated DSL APIs. // --------------------------------------------------------------------------------------------- diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantBuilderImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantBuilderImpl.kt index 8c147d1061..94e0a1c2c8 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantBuilderImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantBuilderImpl.kt @@ -84,6 +84,6 @@ open class LibraryVariantBuilderImpl @Inject constructor( } override var isMinifyEnabled: Boolean = - dslInfo.getPostProcessingOptions().codeShrinkerEnabled() + dslInfo.postProcessingOptions.codeShrinkerEnabled() set(value) = setMinificationIfPossible("minifyEnabled", value) { field = it } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt index 5104785a90..ba9fbe7137 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt @@ -125,9 +125,6 @@ open class LibraryVariantImpl @Inject constructor( override val debuggable: Boolean get() = dslInfo.isDebuggable - override val profileable: Boolean - get() = dslInfo.isProfileable - override val isCoreLibraryDesugaringEnabled: Boolean get() = delegate.isCoreLibraryDesugaringEnabled @@ -151,7 +148,7 @@ open class LibraryVariantImpl @Inject constructor( override val resourcesShrink: Boolean // need to return shrink flag for PostProcessing as this API has the flag for libraries // return false otherwise - get() = dslInfo.getPostProcessingOptions() + get() = dslInfo.postProcessingOptions .let { it.hasPostProcessingConfiguration() && it.resourcesShrinkingEnabled() } override val needsMergedJavaResStream: Boolean = delegate.getNeedsMergedJavaResStream() diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourceType.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourceType.kt index 2fb09fe6eb..daec70db14 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourceType.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourceType.kt @@ -26,4 +26,5 @@ enum class SourceType(val folder: String) { RENDERSCRIPT("renderscript"), RES("res"), SHADERS("shaders"), + JAVA_RESOURCES("resources"), } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourcesImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourcesImpl.kt index fd0f3e06a3..5c18bb4971 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourcesImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/SourcesImpl.kt @@ -87,6 +87,19 @@ class SourcesImpl( updateSourceDirectories(sourceDirectoriesImpl, variantSourceSet?.res) } + override val resources: FlatSourceDirectoriesImpl = + FlatSourceDirectoriesImpl( + SourceType.JAVA_RESOURCES.name, + variantServices, + variantSourceSet?.resources?.filter, + ).also { sourceDirectoriesImpl -> + + defaultSourceProvider.getResources(sourceDirectoriesImpl).run { + sourceDirectoriesImpl.addSources(this) + } + updateSourceDirectories(sourceDirectoriesImpl, variantSourceSet?.resources) + } + override val assets: AssetSourceDirectoriesImpl = AssetSourceDirectoriesImpl( SourceType.ASSETS.folder, diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantBuilderImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantBuilderImpl.kt index 671d348e0b..4fa73fa013 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantBuilderImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantBuilderImpl.kt @@ -53,6 +53,6 @@ open class TestVariantBuilderImpl @Inject constructor( } override var isMinifyEnabled: Boolean = - dslInfo.getPostProcessingOptions().codeShrinkerEnabled() + dslInfo.postProcessingOptions.codeShrinkerEnabled() set(value) = setMinificationIfPossible("minifyEnabled", value){ field = it } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantImpl.kt index 17dafc7b87..2bcd964cfa 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/TestVariantImpl.kt @@ -185,8 +185,6 @@ open class TestVariantImpl @Inject constructor( override val shouldPackageDesugarLibDex: Boolean = delegate.isCoreLibraryDesugaringEnabled(this) override val debuggable: Boolean get() = delegate.isDebuggable - override val profileable: Boolean - get() = delegate.isProfileable override val isCoreLibraryDesugaringEnabled: Boolean get() = delegate.isCoreLibraryDesugaringEnabled @@ -208,12 +206,6 @@ open class TestVariantImpl @Inject constructor( get() = false // --------------------------------------------------------------------------------------------- - // DO NOT USE, only present for old variant API. - // --------------------------------------------------------------------------------------------- - override val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? = - dslInfo.signingConfig - - // --------------------------------------------------------------------------------------------- // DO NOT USE, Deprecated DSL APIs. // --------------------------------------------------------------------------------------------- override val multiDexKeepFile = dslInfo.multiDexKeepFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt index 0d653dd7fb..b30832cd43 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantBuilderImpl.kt @@ -152,7 +152,7 @@ abstract class VariantBuilderImpl( newValue: Boolean, setter: (Boolean) -> Unit ) { - if (dslInfo.getPostProcessingOptions().hasPostProcessingConfiguration()) + if (dslInfo.postProcessingOptions.hasPostProcessingConfiguration()) variantBuilderServices.issueReporter.reportWarning( IssueReporter.Type.GENERIC, "You cannot set $varName via Variant API as build uses postprocessing{...} " + diff --git a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantImpl.kt index 13bd2a8097..27178e4214 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantImpl.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/api/variant/impl/VariantImpl.kt @@ -19,6 +19,7 @@ import com.android.build.api.artifact.impl.ArtifactsImpl import com.android.build.api.component.impl.ComponentImpl import com.android.build.api.component.impl.UnitTestImpl import com.android.build.api.component.impl.features.BuildConfigCreationConfigImpl +import com.android.build.api.component.impl.features.ManifestPlaceholdersCreationConfigImpl import com.android.build.api.component.impl.features.RenderscriptCreationConfigImpl import com.android.build.api.component.impl.warnAboutAccessingVariantApiValueForDisabledFeature import com.android.build.api.variant.AndroidVersion @@ -36,6 +37,7 @@ import com.android.build.gradle.internal.component.TestFixturesCreationConfig import com.android.build.gradle.internal.component.VariantCreationConfig import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig import com.android.build.gradle.internal.component.features.FeatureNames +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig import com.android.build.gradle.internal.component.features.RenderscriptCreationConfig import com.android.build.gradle.internal.core.MergedNdkConfig import com.android.build.gradle.internal.core.NativeBuiltType @@ -176,7 +178,7 @@ abstract class VariantImpl<DslInfoT: VariantDslInfo>( // INTERNAL API // --------------------------------------------------------------------------------------------- - override val buildConfigCreationConfig: BuildConfigCreationConfig? by lazy { + override val buildConfigCreationConfig: BuildConfigCreationConfig? by lazy(LazyThreadSafetyMode.NONE) { if (buildFeatures.buildConfig) { BuildConfigCreationConfigImpl( this, @@ -188,7 +190,7 @@ abstract class VariantImpl<DslInfoT: VariantDslInfo>( } } - override val renderscriptCreationConfig: RenderscriptCreationConfig? by lazy { + override val renderscriptCreationConfig: RenderscriptCreationConfig? by lazy(LazyThreadSafetyMode.NONE) { if (buildFeatures.renderScript) { RenderscriptCreationConfigImpl( dslInfo, @@ -200,10 +202,17 @@ abstract class VariantImpl<DslInfoT: VariantDslInfo>( } } + override val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig by lazy(LazyThreadSafetyMode.NONE) { + ManifestPlaceholdersCreationConfigImpl( + dslInfo, + internalServices + ) + } + override val testComponents = mutableMapOf<ComponentType, TestComponentCreationConfig>() override var testFixturesComponent: TestFixturesCreationConfig? = null - val externalExtensions: Map<Class<*>, Any>? by lazy { + private val externalExtensions: Map<Class<*>, Any>? by lazy { variantBuilder.getRegisteredExtensions() } @@ -296,8 +305,8 @@ abstract class VariantImpl<DslInfoT: VariantDslInfo>( get() = dslInfo.supportedAbis override val postProcessingFeatures: PostprocessingFeatures? - get() = dslInfo.getPostProcessingOptions().getPostprocessingFeatures() - override val consumerProguardFiles: List<File> by lazy { + get() = dslInfo.postProcessingOptions.getPostprocessingFeatures() + override val consumerProguardFiles: List<File> by lazy(LazyThreadSafetyMode.NONE) { immutableListBuilder<File> { addAll(dslInfo.gatherProguardFiles(ProguardFileType.CONSUMER)) // We include proguardFiles if we're in a dynamic-feature module. @@ -306,4 +315,6 @@ abstract class VariantImpl<DslInfoT: VariantDslInfo>( } } } + override val manifestPlaceholders: MapProperty<String, String> + get() = manifestPlaceholdersCreationConfig.placeholders } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/DependencyResourcesComputer.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/DependencyResourcesComputer.kt index ca15e2190f..62bfefe47e 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/DependencyResourcesComputer.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/DependencyResourcesComputer.kt @@ -16,6 +16,7 @@ package com.android.build.gradle.internal import com.android.SdkConstants.FD_RES_VALUES +import com.android.build.api.variant.impl.DirectoryEntry import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.utils.fromDisallowChanges @@ -231,6 +232,22 @@ abstract class DependencyResourcesComputer { } resources.disallowChanges() + // Add the user added generated directories to the extraGeneratedResFolders. + // this should be cleaned up once the old variant API is removed. + creationConfig.sources.res.getVariantSources().get().forEach { directoryEntries -> + directoryEntries.directoryEntries + .filter { + it.isUserAdded && it.isGenerated + } + .forEach { + extraGeneratedResFolders.from( + it.asFiles( + creationConfig.services::directoryProperty + ) + ) + } + } + creationConfig.oldVariantApiLegacySupport?.variantData?.extraGeneratedResFolders?.let { extraGeneratedResFolders.from(it) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/VariantManager.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/VariantManager.kt index 5438e76766..49ddb3af4e 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/VariantManager.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/VariantManager.kt @@ -44,16 +44,16 @@ import com.android.build.gradle.internal.component.NestedComponentCreationConfig import com.android.build.gradle.internal.component.TestComponentCreationConfig import com.android.build.gradle.internal.component.TestFixturesCreationConfig import com.android.build.gradle.internal.component.VariantCreationConfig -import com.android.build.gradle.internal.core.VariantDslInfoBuilder -import com.android.build.gradle.internal.core.VariantDslInfoBuilder.Companion.computeSourceSetName -import com.android.build.gradle.internal.core.VariantDslInfoBuilder.Companion.getBuilder -import com.android.build.gradle.internal.core.VariantDslInfoImpl import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo import com.android.build.gradle.internal.core.dsl.ComponentDslInfo import com.android.build.gradle.internal.core.dsl.TestComponentDslInfo import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo import com.android.build.gradle.internal.core.dsl.UnitTestComponentDslInfo import com.android.build.gradle.internal.core.dsl.VariantDslInfo +import com.android.build.gradle.internal.core.dsl.impl.DslInfoBuilder +import com.android.build.gradle.internal.core.dsl.impl.DslInfoBuilder.Companion.getBuilder +import com.android.build.gradle.internal.core.dsl.impl.computeSourceSetName import com.android.build.gradle.internal.crash.ExternalApiUsageException import com.android.build.gradle.internal.dependency.VariantDependenciesBuilder import com.android.build.gradle.internal.dsl.BuildType @@ -169,16 +169,6 @@ class VariantManager< private lateinit var _buildFeatureValues: BuildFeatureValues - - private fun hasDynamicFeatures(): Boolean = - (dslExtension as? ApplicationExtension)?.dynamicFeatures?.isNotEmpty() ?: false - - private fun getCompileSdkVersion(): String? { - val newExtension = dslExtension as? CommonExtensionImpl<*,*,*,*> ?: throw RuntimeException("Wrong DSL instance") - return newExtension.compileSdkVersion - } - - /** * Creates the variants. * @@ -282,12 +272,11 @@ class VariantManager< getLazyManifestParser( defaultConfigSourceProvider.manifestFile, componentType.requiresManifest) { canParseManifest() }, - dslServices, variantPropertiesApiServices, oldExtension, dslExtension, - hasDynamicFeatures = hasDynamicFeatures(), - dslExtension.experimentalProperties, + project.layout.buildDirectory, + dslServices ) // We must first add the flavors to the variant config, in order to get the proper @@ -296,8 +285,7 @@ class VariantManager< variantDslInfoBuilder.addProductFlavor( productFlavorData.productFlavor, productFlavorData.sourceSet) } - val variantDslInfo = variantDslInfoBuilder.createVariantDslInfo( - project.layout.buildDirectory) + val variantDslInfo = variantDslInfoBuilder.createDslInfo() val componentIdentity = variantDslInfo.componentIdentity // create the Variant object so that we can run the action which may interrupt the creation @@ -420,24 +408,24 @@ class VariantManager< private fun<DslInfoT: ComponentDslInfo> createCompoundSourceSets( productFlavorList: List<ProductFlavorData<ProductFlavor>>, - variantDslInfoBuilder: VariantDslInfoBuilder<CommonExtensionT, DslInfoT>) { - val componentType = variantDslInfoBuilder.componentType + dslInfoBuilder: DslInfoBuilder<CommonExtensionT, DslInfoT>) { + val componentType = dslInfoBuilder.componentType if (productFlavorList.isNotEmpty() /* && !variantConfig.getType().isSingleBuildType()*/) { val variantSourceSet = variantInputModel .sourceSetManager .setUpSourceSet( - computeSourceSetName(variantDslInfoBuilder.name, componentType), + computeSourceSetName(dslInfoBuilder.name, componentType), componentType.isTestComponent) as DefaultAndroidSourceSet - variantDslInfoBuilder.variantSourceProvider = variantSourceSet + dslInfoBuilder.variantSourceProvider = variantSourceSet } if (productFlavorList.size > 1) { val multiFlavorSourceSet = variantInputModel .sourceSetManager .setUpSourceSet( - computeSourceSetName(variantDslInfoBuilder.flavorName, + computeSourceSetName(dslInfoBuilder.flavorName, componentType), componentType.isTestComponent) as DefaultAndroidSourceSet - variantDslInfoBuilder.multiFlavorSourceProvider = multiFlavorSourceSet + dslInfoBuilder.multiFlavorSourceProvider = multiFlavorSourceSet } } @@ -461,15 +449,15 @@ class VariantManager< getLazyManifestParser( testFixturesSourceSet.manifestFile, testFixturesComponentType.requiresManifest) { canParseManifest() }, - dslServices, variantPropertiesApiServices, oldExtension = oldExtension, extension = dslExtension, - hasDynamicFeatures = hasDynamicFeatures(), - testFixtureMainVariantName = mainComponentInfo.variant.name + buildDirectory = project.layout.buildDirectory, + dslServices = dslServices ) - variantDslInfoBuilder.productionVariant = mainComponentInfo.variantDslInfo as VariantDslInfoImpl + variantDslInfoBuilder.productionVariant = + mainComponentInfo.variantDslInfo as TestedVariantDslInfo val productFlavorList = mainComponentInfo.variantDslInfo.productFlavorList @@ -484,9 +472,7 @@ class VariantManager< ) } } - val variantDslInfo = variantDslInfoBuilder.createVariantDslInfo( - project.layout.buildDirectory - ) + val variantDslInfo = variantDslInfoBuilder.createDslInfo() // now that we have the result of the filter, we can continue configuring the variant createCompoundSourceSets(productFlavorDataList, variantDslInfoBuilder) @@ -608,13 +594,14 @@ class VariantManager< getLazyManifestParser( testSourceSet.manifestFile, componentType.requiresManifest) { canParseManifest() }, - dslServices, variantPropertiesApiServices, oldExtension = oldExtension, extension = dslExtension, - hasDynamicFeatures = hasDynamicFeatures()) + buildDirectory = project.layout.buildDirectory, + dslServices = dslServices + ) variantDslInfoBuilder.productionVariant = - testedComponentInfo.variantDslInfo as VariantDslInfoImpl + testedComponentInfo.variantDslInfo as TestedVariantDslInfo variantDslInfoBuilder.inconsistentTestAppId = inconsistentTestAppId val productFlavorList = testedComponentInfo.variantDslInfo.productFlavorList @@ -629,8 +616,7 @@ class VariantManager< it.getTestSourceSet(componentType)!!) } } - val variantDslInfo = variantDslInfoBuilder.createVariantDslInfo( - project.layout.buildDirectory) + val variantDslInfo = variantDslInfoBuilder.createDslInfo() val apiAccessStats = testedComponentInfo.stats if (componentType.isApk && testedComponentInfo.variantBuilder is HasAndroidTestBuilder) { diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/AndroidArtifactVariantImpl.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/AndroidArtifactVariantImpl.java index 8b61525b19..0f81bb5b5d 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/AndroidArtifactVariantImpl.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/AndroidArtifactVariantImpl.java @@ -21,7 +21,6 @@ import com.android.annotations.Nullable; import com.android.build.api.component.impl.ComponentUtils; import com.android.build.gradle.api.AndroidArtifactVariant; import com.android.build.gradle.api.BaseVariantOutput; -import com.android.build.gradle.internal.component.ApkCreationConfig; import com.android.build.gradle.internal.component.ComponentCreationConfig; import com.android.build.gradle.internal.services.DslServices; import com.android.build.gradle.internal.variant.ApkVariantData; @@ -52,9 +51,9 @@ public abstract class AndroidArtifactVariantImpl extends BaseVariantImpl @Override public SigningConfig getSigningConfig() { - if (component instanceof ApkCreationConfig) { + if (component.getOldVariantApiLegacySupport() != null) { return readOnlyObjectProvider.getSigningConfig( - ((ApkCreationConfig) component).getDslSigningConfig()); + component.getOldVariantApiLegacySupport().getDslSigningConfig()); } else return null; } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/VariantFilter.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/VariantFilter.kt index c9063a7066..98e09e4219 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/VariantFilter.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/api/VariantFilter.kt @@ -16,7 +16,7 @@ package com.android.build.gradle.internal.api import com.android.build.api.variant.VariantFilter -import com.android.build.gradle.internal.core.VariantDslInfoBuilder.Companion.computeName +import com.android.build.gradle.internal.core.dsl.impl.computeName import com.android.build.gradle.internal.variant.DimensionCombination import com.android.builder.core.ComponentType import com.android.builder.model.BuildType diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApkCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApkCreationConfig.kt index c8d4b38beb..ad6d4e767d 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApkCreationConfig.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApkCreationConfig.kt @@ -50,11 +50,6 @@ interface ApkCreationConfig: ConsumableCreationConfig { */ val signingConfigImpl: SigningConfigImpl? - /** - * DO NOT USE, only present for old variant API. - */ - val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? - val multiDexKeepFile: File? val bundleConfig: BundleConfigImpl? diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApplicationCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApplicationCreationConfig.kt index c01ab18c84..873281130b 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApplicationCreationConfig.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ApplicationCreationConfig.kt @@ -20,6 +20,7 @@ import com.android.build.api.variant.impl.BundleConfigImpl import com.android.build.gradle.internal.dsl.NdkOptions interface ApplicationCreationConfig: ApkCreationConfig, VariantCreationConfig, PublishableCreationConfig { + val profileable: Boolean val consumesFeatureJars: Boolean val needAssetPackTasks: Boolean val nativeDebugSymbolLevel: NdkOptions.DebugSymbolLevel diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt index 491d4b60c6..c8e367d6be 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ComponentCreationConfig.kt @@ -32,6 +32,7 @@ import com.android.build.gradle.internal.component.features.AndroidResourcesCrea import com.android.build.gradle.internal.component.features.AssetsCreationConfig import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig import com.android.build.gradle.internal.component.features.InstrumentationCreationConfig +import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig import com.android.build.gradle.internal.component.features.ResValuesCreationConfig import com.android.build.gradle.internal.component.legacy.ModelV1LegacySupport import com.android.build.gradle.internal.component.legacy.OldVariantApiLegacySupport @@ -49,7 +50,6 @@ import com.android.build.gradle.internal.variant.VariantPathHelper import com.android.builder.core.ComponentType import com.google.wireless.android.sdk.stats.GradleBuildVariant import org.gradle.api.file.FileCollection -import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Provider import java.io.File import java.util.function.Predicate @@ -81,8 +81,6 @@ interface ComponentCreationConfig : ComponentIdentity { val applicationId: Provider<String> val namespace: Provider<String> val debuggable: Boolean - val profileable: Boolean - val manifestPlaceholders: MapProperty<String, String> val supportedAbis: Set<String> val minSdkVersion: AndroidVersion @@ -98,6 +96,7 @@ interface ComponentCreationConfig : ComponentIdentity { val resValuesCreationConfig: ResValuesCreationConfig? val buildConfigCreationConfig: BuildConfigCreationConfig? val instrumentationCreationConfig: InstrumentationCreationConfig? + val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig? // TODO figure out whether these properties are needed by all // TODO : remove as it is now in Variant. diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ConsumableCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ConsumableCreationConfig.kt index 6a176deb8f..7c2ad5da46 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ConsumableCreationConfig.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/ConsumableCreationConfig.kt @@ -25,6 +25,7 @@ import com.android.build.gradle.internal.scope.Java8LangSupport import com.android.builder.dexing.DexingType import org.gradle.api.file.RegularFile import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Provider /** @@ -81,4 +82,6 @@ interface ConsumableCreationConfig: ComponentCreationConfig { val defaultGlslcArgs: List<String> val scopedGlslcArgs: Map<String, List<String>> + + val manifestPlaceholders: MapProperty<String, String> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/DynamicFeatureCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/DynamicFeatureCreationConfig.kt index 92882b7fe2..3f518548e9 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/DynamicFeatureCreationConfig.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/DynamicFeatureCreationConfig.kt @@ -22,6 +22,5 @@ interface DynamicFeatureCreationConfig: VariantCreationConfig, ApkCreationConfig val featureName: Provider<String> val resOffset: Provider<Int> - val baseModuleDebuggable: Provider<Boolean> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/features/ManifestPlaceholdersCreationConfig.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/features/ManifestPlaceholdersCreationConfig.kt new file mode 100644 index 0000000000..640a6e7f40 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/features/ManifestPlaceholdersCreationConfig.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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.component.features + +import org.gradle.api.provider.MapProperty + +/** + * Creation config for components that support manifest placeholders. + */ +interface ManifestPlaceholdersCreationConfig { + val placeholders: MapProperty<String, String> +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/legacy/OldVariantApiLegacySupport.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/legacy/OldVariantApiLegacySupport.kt index 85c56a23cc..b8a5b1adab 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/legacy/OldVariantApiLegacySupport.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/component/legacy/OldVariantApiLegacySupport.kt @@ -34,6 +34,7 @@ interface OldVariantApiLegacySupport { val mergedFlavor: MergedFlavor val javaCompileOptions: JavaCompileOptions val variantData: BaseVariantData + val dslSigningConfig: com.android.build.gradle.internal.dsl.SigningConfig? fun getJavaClasspathArtifacts( configType: AndroidArtifacts.ConsumedConfigType, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAarMetadata.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAarMetadata.kt index e3ea292780..feac2bbc6e 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAarMetadata.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAarMetadata.kt @@ -40,4 +40,10 @@ class MergedAarMetadata : MergedOptions<AarMetadata> { option.minCompileSdkExtension?.let { minCompileSdkExtension = it } option.minAgpVersion?.let { minAgpVersion = it } } + + fun append(option: MergedAarMetadata) { + option.minCompileSdk?.let { minCompileSdk = it } + option.minCompileSdkExtension?.let { minCompileSdkExtension = it } + option.minAgpVersion?.let { minAgpVersion = it } + } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAnnotationProcessorOptions.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAnnotationProcessorOptions.kt new file mode 100644 index 0000000000..d4ca11d25c --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedAnnotationProcessorOptions.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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.core + +import com.android.build.gradle.internal.dsl.AnnotationProcessorOptions +import org.gradle.process.CommandLineArgumentProvider + +class MergedAnnotationProcessorOptions: + AnnotationProcessorOptions(), + MergedOptions<com.android.build.gradle.api.AnnotationProcessorOptions> { + + override fun setClassNames(classNames: MutableList<String>) { + this.classNames.clear() + this.classNames.addAll(classNames) + } + + override fun setArguments(arguments: MutableMap<String, String>) { + this.arguments.clear() + this.arguments.putAll(arguments) + } + + override fun setCompilerArgumentProviders(compilerArgumentProviders: MutableList<CommandLineArgumentProvider>) { + this.compilerArgumentProviders.clear() + this.compilerArgumentProviders.addAll(compilerArgumentProviders) + } + + override val classNames = mutableListOf<String>() + override val arguments = mutableMapOf<String, String>() + override val compilerArgumentProviders = mutableListOf<CommandLineArgumentProvider>() + + override fun reset() { + classNames.clear() + arguments.clear() + compilerArgumentProviders.clear() + } + + override fun append(option: com.android.build.gradle.api.AnnotationProcessorOptions) { + classNames.addAll(option.classNames) + arguments.putAll(option.arguments) + compilerArgumentProviders.addAll(option.compilerArgumentProviders) + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedFlavor.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedFlavor.kt index a27d25f4c3..a169278716 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedFlavor.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedFlavor.kt @@ -20,7 +20,7 @@ import com.android.build.api.component.impl.ENABLE_LEGACY_API import com.android.build.gradle.internal.api.BaseVariantImpl import com.android.build.gradle.internal.dsl.VectorDrawablesOptions import com.android.build.gradle.internal.errors.DeprecationReporter -import com.android.build.gradle.internal.services.DslServices +import com.android.build.gradle.internal.services.VariantServices import com.android.build.gradle.options.BooleanOption import com.android.builder.core.AbstractProductFlavor import com.android.builder.core.DefaultVectorDrawablesOptions @@ -36,7 +36,7 @@ import org.gradle.api.provider.Property class MergedFlavor( name: String, private val _applicationId: Property<String>, - private val dslServices: DslServices + private val services: VariantServices ) : AbstractProductFlavor(name), InternalBaseVariant.MergedFlavor { override var dimension: String? = null @@ -48,8 +48,8 @@ class MergedFlavor( override var testHandleProfiling: Boolean? = null override var testFunctionalTest: Boolean? = null override var wearAppUnbundled: Boolean? = null - protected override var _versionCode: Int? = null - protected override var _versionName: String? = null + override var _versionCode: Int? = null + override var _versionName: String? = null override val resourceConfigurations: MutableSet<String> = mutableSetOf() // in the merged flavor scenario which is still accessible from the old variant API, we need @@ -57,7 +57,7 @@ class MergedFlavor( override var applicationId: String? get() { // consider throwing an exception instead, as this is not reliable. - dslServices.deprecationReporter + services.deprecationReporter .reportDeprecatedApi( "Variant.getApplicationId()", "MergedFlavor.getApplicationId()", @@ -65,8 +65,8 @@ class MergedFlavor( DeprecationReporter.DeprecationTarget.USE_PROPERTIES ) - if (!dslServices.projectOptions.get(BooleanOption.ENABLE_LEGACY_API)) { - dslServices.issueReporter + if (!services.projectOptions.get(BooleanOption.ENABLE_LEGACY_API)) { + services.issueReporter .reportError( IssueReporter.Type.GENERIC, RuntimeException( @@ -99,8 +99,8 @@ class MergedFlavor( * @return a new MergedFlavor instance that is a clone of the flavor. */ @JvmStatic - fun clone(productFlavor: ProductFlavor, applicationId: Property<String>, dslServices: DslServices): MergedFlavor { - val mergedFlavor = MergedFlavor(productFlavor.name, applicationId, dslServices) + fun clone(productFlavor: ProductFlavor, applicationId: Property<String>, services: VariantServices): MergedFlavor { + val mergedFlavor = MergedFlavor(productFlavor.name, applicationId, services) mergedFlavor._initWith(productFlavor) return mergedFlavor } @@ -123,9 +123,9 @@ class MergedFlavor( lowestPriority: ProductFlavor, flavors: List<ProductFlavor>, applicationId: Property<String>, - dslServices: DslServices + services: VariantServices ): MergedFlavor { - val mergedFlavor = clone(lowestPriority, applicationId, dslServices) + val mergedFlavor = clone(lowestPriority, applicationId, services) for (flavor in Lists.reverse(flavors)) { mergedFlavor.mergeWithHigherPriorityFlavor(flavor) } @@ -202,6 +202,6 @@ class MergedFlavor( | } |}""".trimMargin() - dslServices.issueReporter.reportError(IssueReporter.Type.GENERIC, message) + services.issueReporter.reportError(IssueReporter.Type.GENERIC, message) } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedJavaCompileOptions.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedJavaCompileOptions.kt index d7b19c9ab7..5bc8be8101 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedJavaCompileOptions.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/MergedJavaCompileOptions.kt @@ -17,30 +17,23 @@ package com.android.build.gradle.internal.core import com.android.build.gradle.api.JavaCompileOptions -import com.android.build.gradle.internal.dsl.AnnotationProcessorOptions /** Implementation of CoreJavaCompileOptions used to merge multiple configs together. */ -abstract class MergedJavaCompileOptions : JavaCompileOptions, +class MergedJavaCompileOptions : JavaCompileOptions, com.android.build.api.dsl.JavaCompileOptions, MergedOptions<JavaCompileOptions> { - abstract override val annotationProcessorOptions: AnnotationProcessorOptions + override val annotationProcessorOptions = MergedAnnotationProcessorOptions() + + override fun annotationProcessorOptions(action: com.android.build.api.dsl.AnnotationProcessorOptions.() -> Unit) { + action.invoke(annotationProcessorOptions) + } override fun reset() { - annotationProcessorOptions.classNames.clear() - annotationProcessorOptions.arguments.clear() - annotationProcessorOptions.compilerArgumentProviders.clear() + annotationProcessorOptions.reset() } override fun append(option: JavaCompileOptions) { - annotationProcessorOptions.classNames.addAll( - option.annotationProcessorOptions.classNames - ) - annotationProcessorOptions.arguments.putAll( - option.annotationProcessorOptions.arguments - ) - annotationProcessorOptions.compilerArgumentProviders.addAll( - option.annotationProcessorOptions.compilerArgumentProviders - ) + annotationProcessorOptions.append(option.annotationProcessorOptions) } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfo.kt deleted file mode 100644 index fc8296a60d..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfo.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2014 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.core - -import com.android.build.gradle.internal.core.dsl.AarProducingComponentDslInfo -import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo -import com.android.build.gradle.internal.core.dsl.ApkProducingComponentDslInfo -import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo -import com.android.build.gradle.internal.core.dsl.ComponentDslInfo -import com.android.build.gradle.internal.core.dsl.DynamicFeatureVariantDslInfo -import com.android.build.gradle.internal.core.dsl.InstrumentedTestComponentDslInfo -import com.android.build.gradle.internal.core.dsl.LibraryVariantDslInfo -import com.android.build.gradle.internal.core.dsl.PublishableVariantDslInfo -import com.android.build.gradle.internal.core.dsl.TestComponentDslInfo -import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo -import com.android.build.gradle.internal.core.dsl.TestProjectVariantDslInfo -import com.android.build.gradle.internal.core.dsl.TestedComponentDslInfo -import com.android.build.gradle.internal.core.dsl.UnitTestComponentDslInfo - -@Deprecated("Do not use or add any new properties here, use the fine-grained interfaces") -interface VariantDslInfo: AarProducingComponentDslInfo, - AndroidTestComponentDslInfo, - ApkProducingComponentDslInfo, - ApplicationVariantDslInfo, - ComponentDslInfo, - DynamicFeatureVariantDslInfo, - InstrumentedTestComponentDslInfo, - LibraryVariantDslInfo, - PublishableVariantDslInfo, - TestComponentDslInfo, - TestedComponentDslInfo, - TestFixturesComponentDslInfo, - TestProjectVariantDslInfo, - UnitTestComponentDslInfo, - com.android.build.gradle.internal.core.dsl.VariantDslInfo diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoBuilder.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoBuilder.kt deleted file mode 100644 index 5d6283d8d3..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoBuilder.kt +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2019 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.core - -import com.android.build.api.component.impl.ComponentIdentityImpl -import com.android.build.api.dsl.BuildType -import com.android.build.api.dsl.CommonExtension -import com.android.build.api.dsl.ProductFlavor -import com.android.build.api.variant.ComponentIdentity -import com.android.build.gradle.BaseExtension -import com.android.build.gradle.internal.api.DefaultAndroidSourceSet -import com.android.build.gradle.internal.core.VariantDslInfoBuilder.Companion.getBuilder -import com.android.build.gradle.internal.core.dsl.ComponentDslInfo -import com.android.build.gradle.internal.dsl.ApplicationPublishingImpl -import com.android.build.gradle.internal.dsl.DefaultConfig -import com.android.build.gradle.internal.dsl.InternalApplicationExtension -import com.android.build.gradle.internal.dsl.InternalLibraryExtension -import com.android.build.gradle.internal.dsl.LibraryPublishingImpl -import com.android.build.gradle.internal.dsl.SigningConfig -import com.android.build.gradle.internal.manifest.ManifestDataProvider -import com.android.build.gradle.internal.services.DslServices -import com.android.build.gradle.internal.services.VariantServices -import com.android.build.gradle.internal.utils.createPublishingInfoForApp -import com.android.build.gradle.internal.utils.createPublishingInfoForLibrary -import com.android.build.gradle.internal.utils.toImmutableList -import com.android.build.gradle.internal.variant.DimensionCombination -import com.android.builder.core.ComponentType -import com.android.builder.model.SourceProvider -import com.android.utils.appendCapitalized -import com.android.utils.combineAsCamelCase -import org.gradle.api.file.DirectoryProperty - -/** Builder for [VariantDslInfo]. - * - * This allows setting all temporary items on the builder before actually - * instantiating the configuration, in order to keep it immutable. - * - * Use [getBuilder] as an entry point. - */ -class VariantDslInfoBuilder<CommonExtensionT: CommonExtension<*, *, *, *>, DslInfoT: ComponentDslInfo> private constructor( - private val dimensionCombination: DimensionCombination, - val componentType: ComponentType, - private val defaultConfig: DefaultConfig, - private val defaultSourceProvider: SourceProvider, - private val buildType: BuildType, - private val buildTypeSourceProvider: SourceProvider? = null, - private val signingConfigOverride: SigningConfig?, - private val manifestDataProvider: ManifestDataProvider, - private val dslServices: DslServices, - private val variantServices: VariantServices, - private val oldExtension: BaseExtension, - private val extension: CommonExtensionT, - private val hasDynamicFeatures: Boolean, - private val experimentalProperties: Map<String, Any>, - private val testFixtureMainVariantName: String? -) { - - companion object { - /** - * Returns a new builder - */ - @JvmStatic - fun <CommonExtensionT: CommonExtension<*, *, *, *>, DslInfoT: ComponentDslInfo> getBuilder( - dimensionCombination: DimensionCombination, - componentType: ComponentType, - defaultConfig: DefaultConfig, - defaultSourceSet: SourceProvider, - buildType: BuildType, - buildTypeSourceSet: SourceProvider? = null, - signingConfigOverride: SigningConfig? = null, - manifestDataProvider: ManifestDataProvider, - dslServices: DslServices, - variantServices: VariantServices, - oldExtension: BaseExtension, - extension: CommonExtensionT, - hasDynamicFeatures: Boolean, - experimentalProperties: Map<String, Any> = mapOf(), - testFixtureMainVariantName: String? = null - ): VariantDslInfoBuilder<CommonExtensionT, DslInfoT> { - return VariantDslInfoBuilder( - dimensionCombination, - componentType, - defaultConfig, - defaultSourceSet, - buildType, - buildTypeSourceSet, - signingConfigOverride?.let { signingOverride -> - dslServices.newDecoratedInstance( - SigningConfig::class.java, - signingOverride.name, - dslServices - ).also { - it.initWith(signingOverride) - } - }, - manifestDataProvider, - dslServices, - variantServices, - oldExtension, - extension, - hasDynamicFeatures, - experimentalProperties, - testFixtureMainVariantName, - ) - } - - /** - * Returns the full, unique name of the variant in camel case (starting with a lower case), - * including BuildType, Flavors and Test (if applicable). - * - * This is to be used for the normal variant name. In case of Feature plugin, the library - * side will be called the same as for library plugins, while the feature side will add - * 'feature' to the name. - * - * Also computes the flavor name if applicable - */ - @JvmStatic - @JvmOverloads - fun computeName( - dimensionCombination: DimensionCombination, - componentType: ComponentType, - flavorNameCallback: ((String) -> Unit)? = null - ): String { - // compute the flavor name - val flavorName = if (dimensionCombination.productFlavors.isNullOrEmpty()) { - "" - } else { - combineAsCamelCase(dimensionCombination.productFlavors, Pair<String,String>::second) - } - flavorNameCallback?.let { it(flavorName) } - - val sb = StringBuilder() - val buildType = dimensionCombination.buildType - if (buildType == null) { - if (flavorName.isNotEmpty()) { - sb.append(flavorName) - } else if (!componentType.isTestComponent && !componentType.isTestFixturesComponent) { - sb.append("main") - } - } else { - if (flavorName.isNotEmpty()) { - sb.append(flavorName) - sb.appendCapitalized(buildType) - } else { - sb.append(buildType) - } - } - if (componentType.isNestedComponent) { - if (sb.isEmpty()) { - // need the lower case version - sb.append(componentType.prefix) - } else { - sb.append(componentType.suffix) - } - } - return sb.toString() - } - - /** - * Turns a string into a valid source set name for the given [ComponentType], e.g. - * "fooBarUnitTest" becomes "testFooBar". - */ - @JvmStatic - fun computeSourceSetName( - baseName: String, - componentType: ComponentType - ): String { - var name = baseName - if (name.endsWith(componentType.suffix)) { - name = name.substring(0, name.length - componentType.suffix.length) - } - if (!componentType.prefix.isEmpty()) { - name = componentType.prefix.appendCapitalized(name) - } - return name - } - - /** - * Returns the full, unique name of the variant, including BuildType, flavors and test, dash - * separated. (similar to full name but with dashes) - * - * @return the name of the variant - */ - @JvmStatic - fun computeBaseName( - dimensionCombination: DimensionCombination, - componentType: ComponentType) : String { - val sb = StringBuilder() - if (dimensionCombination.productFlavors.isNotEmpty()) { - for ((_, name) in dimensionCombination.productFlavors) { - if (sb.isNotEmpty()) { - sb.append('-') - } - sb.append(name) - } - } - - dimensionCombination.buildType?.let { - if (sb.isNotEmpty()) { - sb.append('-') - } - sb.append(it) - } - - if (componentType.isNestedComponent) { - if (sb.isNotEmpty()) { - sb.append('-') - } - sb.append(componentType.prefix) - } - - if (sb.isEmpty()) { - sb.append("main") - } - - return sb.toString() - } - - /** - * Returns a full name that includes the given splits name. - * - * @param splitName the split name - * @return a unique name made up of the variant and split names. - */ - @JvmStatic - fun computeFullNameWithSplits( - variantConfiguration: ComponentIdentity, - componentType: ComponentType, - splitName: String): String { - val sb = StringBuilder() - - val flavorName = variantConfiguration.flavorName - - if (!flavorName.isNullOrEmpty()) { - sb.append(flavorName) - sb.appendCapitalized(splitName) - } else { - sb.append(splitName) - } - - variantConfiguration.buildType?.let { - sb.appendCapitalized(it) - } - - if (componentType.isNestedComponent) { - sb.append(componentType.suffix) - } - return sb.toString() - } - } - - private lateinit var variantName: String - private lateinit var multiFlavorName: String - - val name: String - get() { - if (!::variantName.isInitialized) { - computeNames() - } - - return variantName - } - - val flavorName: String - get() { - if (!::multiFlavorName.isInitialized) { - computeNames() - } - return multiFlavorName - - } - - private val flavors = mutableListOf<Pair<ProductFlavor, SourceProvider>>() - - var variantSourceProvider: DefaultAndroidSourceSet? = null - var multiFlavorSourceProvider: DefaultAndroidSourceSet? = null - var productionVariant: VariantDslInfoImpl? = null - var inconsistentTestAppId: Boolean = false - - fun addProductFlavor( - productFlavor: ProductFlavor, - sourceProvider: SourceProvider - ) { - if (::variantName.isInitialized) { - throw RuntimeException("call to getName() before calling all addProductFlavor") - } - flavors.add(Pair(productFlavor, sourceProvider)) - } - - /** Creates a variant configuration */ - fun createVariantDslInfo(buildDirectory: DirectoryProperty): DslInfoT { - val flavorList = flavors.map { it.first } - - val publishingInfo = if (extension is InternalLibraryExtension) { - createPublishingInfoForLibrary( - extension.publishing as LibraryPublishingImpl, - dslServices.projectOptions, - name, - buildType, - flavorList, - extension.buildTypes, - extension.productFlavors, - testFixtureMainVariantName, - dslServices.issueReporter - ) - } else if (extension is InternalApplicationExtension) { - createPublishingInfoForApp( - extension.publishing as ApplicationPublishingImpl, - dslServices.projectOptions, - name, - hasDynamicFeatures, - dslServices.issueReporter - ) - } else null - - return VariantDslInfoImpl( - ComponentIdentityImpl( - name, - flavorName, - dimensionCombination.buildType, - dimensionCombination.productFlavors - ), - componentType, - defaultConfig, - buildType, - // this could be removed once the product flavor is internal only. - flavorList.toImmutableList(), - signingConfigOverride, - productionVariant, - manifestDataProvider, - dslServices, - variantServices, - buildDirectory, - publishingInfo, - experimentalProperties, - inconsistentTestAppId, - oldExtension, - extension - ) as DslInfoT - } - - fun createVariantSources(): VariantSources { - return VariantSources( - name, - componentType, - defaultSourceProvider, - buildTypeSourceProvider, - flavors.map { it.second }.toImmutableList(), - multiFlavorSourceProvider, - variantSourceProvider - ) - } - - /** - * computes the name for the variant and the multi-flavor combination - */ - private fun computeNames() { - variantName = computeName(dimensionCombination, componentType) { - multiFlavorName = it - } - } -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt deleted file mode 100644 index 742cd5567f..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt +++ /dev/null @@ -1,1218 +0,0 @@ -/* - * Copyright (C) 2019 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.core - -import com.android.build.api.dsl.AndroidResources -import com.android.build.api.dsl.ApplicationBuildType -import com.android.build.api.dsl.ApplicationProductFlavor -import com.android.build.api.dsl.BuildType -import com.android.build.api.dsl.CommonExtension -import com.android.build.api.dsl.CompileOptions -import com.android.build.api.dsl.DynamicFeatureBuildType -import com.android.build.api.dsl.LibraryVariantDimension -import com.android.build.api.dsl.Lint -import com.android.build.api.dsl.PackagingOptions -import com.android.build.api.dsl.ProductFlavor -import com.android.build.api.dsl.TestFixtures -import com.android.build.api.dsl.TestedExtension -import com.android.build.api.dsl.VariantDimension -import com.android.build.api.transform.Transform -import com.android.build.api.variant.BuildConfigField -import com.android.build.api.variant.ComponentIdentity -import com.android.build.api.variant.ResValue -import com.android.build.api.variant.impl.MutableAndroidVersion -import com.android.build.api.variant.impl.ResValueKeyImpl -import com.android.build.gradle.BaseExtension -import com.android.build.gradle.ProguardFiles -import com.android.build.gradle.api.JavaCompileOptions -import com.android.build.gradle.internal.PostprocessingFeatures -import com.android.build.gradle.internal.ProguardFileType -import com.android.build.gradle.internal.core.MergedFlavor.Companion.mergeFlavors -import com.android.build.gradle.internal.core.dsl.ApkProducingComponentDslInfo -import com.android.build.gradle.internal.core.dsl.TestedComponentDslInfo -import com.android.build.gradle.internal.cxx.configure.ninja -import com.android.build.gradle.internal.dsl.BuildType.PostProcessingConfiguration -import com.android.build.gradle.internal.dsl.CoreExternalNativeBuildOptions -import com.android.build.gradle.internal.dsl.CoreNdkOptions -import com.android.build.gradle.internal.dsl.DefaultConfig -import com.android.build.gradle.internal.dsl.OptimizationImpl -import com.android.build.gradle.internal.dsl.SigningConfig -import com.android.build.gradle.internal.manifest.ManifestDataProvider -import com.android.build.gradle.internal.profile.ProfilingMode -import com.android.build.gradle.internal.publishing.VariantPublishingInfo -import com.android.build.gradle.internal.services.DslServices -import com.android.build.gradle.internal.services.VariantServices -import com.android.build.gradle.internal.testFixtures.testFixturesFeatureName -import com.android.build.gradle.options.IntegerOption -import com.android.build.gradle.options.StringOption -import com.android.build.gradle.options.Version -import com.android.builder.core.AbstractProductFlavor -import com.android.builder.core.BuilderConstants -import com.android.builder.core.ComponentType -import com.android.builder.dexing.DexingType -import com.android.builder.dexing.isLegacyMultiDexMode -import com.android.builder.errors.IssueReporter -import com.android.builder.model.BaseConfig -import com.android.builder.model.ClassField -import com.android.builder.model.VectorDrawablesOptions -import com.google.common.collect.ImmutableList -import com.google.common.collect.ImmutableMap -import com.google.common.collect.ImmutableSet -import com.google.common.collect.Lists -import com.google.common.collect.Maps -import com.google.common.collect.Sets -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider -import java.io.File -import java.util.concurrent.Callable - -/** - * Represents a variant, initialized from the DSL object model (default config, build type, flavors) - * - * This class allows querying for the values set via the DSL model. - * - * Use [VariantDslInfoBuilder] to instantiate. - * - */ -open class VariantDslInfoImpl internal constructor( - override val componentIdentity: ComponentIdentity, - final override val componentType: ComponentType, - private val defaultConfig: DefaultConfig, - /** - * Public because this is needed by the old Variant API. Nothing else should touch this. - */ - val buildTypeObj: BuildType, - /** The list of product flavors. Items earlier in the list override later items. */ - override val productFlavorList: List<ProductFlavor>, - private val signingConfigOverride: SigningConfig? = null, - /** - * The production variant. This is only valid for test and test fixtures variants. - * This is mostly used to derive some property values from the parent when it's either - * not present in the DSL for this (test/test-fixture) variant, or when it's always - * derived from the parent (e.g. test fixture namespace). - */ - private val productionVariant: VariantDslInfoImpl? = null, - val dataProvider: ManifestDataProvider, - @Deprecated("Only used for merged flavor") - private val dslServices: DslServices, - private val services: VariantServices, - private val buildDirectory: DirectoryProperty, - override val publishInfo: VariantPublishingInfo?, - override val experimentalProperties: Map<String, Any>, - /** - * Whether there are inconsistent applicationId in the test. - * This trigger a mode where the namespaceForR just returns the same as namespace. - */ - private val inconsistentTestAppId: Boolean, - @Deprecated("use extension") private val oldExtension: BaseExtension, - private val extension: CommonExtension<*,*,*,*> -): VariantDslInfo { - - private val dslNamespaceProvider: Provider<String>? = extension.getDslNamespace(componentType)?.let { - services.provider { - if (componentType.isTestComponent && extension.testNamespaceEqualsNamespace()) { - services.issueReporter - .reportError( - IssueReporter.Type.GENERIC, - "namespace and testNamespace have the same value (\"$it\"), which is not allowed." - ) - } - it - } - } - - override val buildType: String? - get() = componentIdentity.buildType - override val productFlavors: List<Pair<String, String>> - get() = componentIdentity.productFlavors - - /** - * This should be mostly private and not used outside of this class. - * Unfortunately there are a few cases where this cannot happen. - * - * Still, DO NOT USE. You should mostly use [VariantDslInfo] which does not give access to this. - */ - val mergedFlavor: MergedFlavor by lazy { - mergeFlavors( - defaultConfig, - productFlavorList.map { it as com.android.build.gradle.internal.dsl.ProductFlavor }, - applicationId, - dslServices - ) - } - - /** - * Optional tested config in case this variant is used for testing another variant. - * - * @see ComponentType.isTestComponent - */ - override val testedVariant: TestedComponentDslInfo? - get() = if (componentType.isTestComponent) { productionVariant } else null - - private val mergedNdkConfig = MergedNdkConfig() - private val mergedExternalNativeBuildOptions = - MergedExternalNativeBuildOptions() - private val mergedJavaCompileOptions = - dslServices.newDecoratedInstance(MergedJavaCompileOptions::class.java, dslServices) - private val mergedAarMetadata = MergedAarMetadata() - private val mergedOptimization = MergedOptimization() - - init { - mergeOptions() - } - - override fun hasFlavors(): Boolean { - return productFlavorList.isNotEmpty() - } - - // use lazy mechanism as this is referenced by other properties, like applicationId or itself - override val namespace: Provider<String> by lazy { - val testedVariant = testedVariant - when { - // ------------- - // Special case for test components - // We first look for a value specified via the DSL - either testNamespace or namespace + - // ".test". Otherwise, we use the package attribute from either the test manifest or the - // main manifest (appending ".test" if from the main manifest). - testedVariant != null -> { - dslNamespaceProvider - ?: extension.namespace?.let { services.provider {"$it.test" } } - ?: testedVariant.namespace.flatMap { testedVariantNamespace -> - dataProvider.manifestData.map { manifestData -> - manifestData.packageName ?: "$testedVariantNamespace.test" - } - } - } - - // ------------- - // Special case for test fixtures - // Namespace is always derived from the parent variant's namespace - componentType.isTestFixturesComponent -> { - val parentVariant = - productionVariant - ?: throw RuntimeException("null parentVariantImpl in test-fixtures VariantDslInfoImpl") - parentVariant.namespace.map { "$it.$testFixturesFeatureName" } - } - - // ------------- - // Special case for separate test sub-projects - // If there is no namespace from the DSL or package attribute in the manifest, we use - // testApplicationId, if present. This allows the test project to not have a manifest if - // all is declared in the DSL. - // TODO(b/170945282, b/172361895) Remove this special case - users should use namespace - // DSL instead of testApplicationId DSL for this... currently a warning - componentType.isSeparateTestProject -> { - if (dslNamespaceProvider != null) { - dslNamespaceProvider - } else { - val testAppIdFromFlavors = - productFlavorList.asSequence().map { it.testApplicationId } - .firstOrNull { it != null } - ?: defaultConfig.testApplicationId - - dataProvider.manifestData.map { - it.packageName - ?: testAppIdFromFlavors?.also { - val message = - "Namespace not specified. Please specify a namespace for " + - "the generated R and BuildConfig classes via " + - "android.namespace in the test module's " + - "build.gradle file. Currently, this test module " + - "uses the testApplicationId " + - "($testAppIdFromFlavors) as its namespace, but " + - "version ${Version.VERSION_8_0} of the Android " + - "Gradle Plugin will require that a namespace be " + - "specified explicitly like so:\n\n" + - "android {\n" + - " namespace '$testAppIdFromFlavors'\n" + - "}\n\n" - services.issueReporter - .reportWarning(IssueReporter.Type.GENERIC, message) - } - ?: throw RuntimeException( - getMissingPackageNameErrorMessage(dataProvider.manifestLocation) - ) - } - } - } - - // ------------- - // All other types of projects, get it from the DSL or read it from the manifest. - else -> dslOrManifestNamespace - } - } - - override val namespaceForR: Provider<String> by lazy { - if (inconsistentTestAppId) { - namespace - } else { - if (!componentType.isTestComponent) { - throw RuntimeException("namespaceForR should only be used by test variants") - } - - val testedVariant = productionVariant!! - - // For legacy reason, this code does the following: - // - If testNamespace is set, use it. - // - If android.namespace is set, use it with .test added - // - else, use the variant applicationId. - // TODO(b/176931684) Remove this and use [namespace] directly everywhere. - dslNamespaceProvider - ?: (testedVariant.dslNamespaceProvider?.let { it.map { "$it.test" } } - ?: applicationId) - } - } - - // The namespace as specified by the user, either via the DSL or the `package` attribute of the - // source AndroidManifest.xml - private val dslOrManifestNamespace: Provider<String> by lazy { - dslNamespaceProvider - ?: dataProvider.manifestData.map { - it.packageName - ?: throw RuntimeException( - getMissingPackageNameErrorMessage(dataProvider.manifestLocation) - ) - } - } - - private fun getMissingPackageNameErrorMessage(manifestLocation: String): String = - "Package Name not found in $manifestLocation, and namespace not specified. Please " + - "specify a namespace for the generated R and BuildConfig classes via " + - "android.namespace in the module's build.gradle file like so:\n\n" + - "android {\n" + - " namespace 'com.example.namespace'\n" + - "}\n\n" - - /** - * Returns the application ID for this variant. This could be coming from the manifest or could - * be overridden through the product flavors and/or the build type. - * - * @return the application ID - */ - override val applicationId: Property<String> = - services.newPropertyBackingDeprecatedApi( - String::class.java, - initApplicationId() - ) - - - private fun initApplicationId(): Provider<String> { - // ------------- - // Special case for test components and separate test sub-projects - if (componentType.isForTesting) { - // get first non null testAppId from flavors/default config - val testAppIdFromFlavors = - productFlavorList.asSequence().map { it.testApplicationId } - .firstOrNull { it != null } - ?: defaultConfig.testApplicationId - - return if (testAppIdFromFlavors == null) { - (testedVariant as? ApkProducingComponentDslInfo)?.applicationId?.map { - "$it.test" - } ?: namespace - } else { - // needed to make nullability work in kotlinc - val finalTestAppIdFromFlavors: String = testAppIdFromFlavors - services.provider(Callable { finalTestAppIdFromFlavors }) - } - } - - // ------------- - // All other project types - - // get first non null appId from flavors/default config - val appIdFromFlavors = - productFlavorList - .asSequence() - .filterIsInstance(ApplicationProductFlavor::class.java) - .map { it.applicationId } - .firstOrNull { it != null } - ?: defaultConfig.applicationId - - return if (appIdFromFlavors == null) { - // No appId value set from DSL; use the namespace value from the DSL or manifest. - // using map will allow us to keep task dependency should the manifest be generated - // or transformed via a task. - dslOrManifestNamespace.map { "$it${computeApplicationIdSuffix()}" } - } else { - // use value from flavors/defaultConfig - // needed to make nullability work in kotlinc - val finalAppIdFromFlavors: String = appIdFromFlavors - services.provider( - Callable { "$finalAppIdFromFlavors${computeApplicationIdSuffix()}" }) - } - } - - /** - * Combines all the appId suffixes into a single one. - * - * The suffixes are separated by '.' whether their first char is a '.' or not. - */ - private fun computeApplicationIdSuffix(): String { - // for the suffix we combine the suffix from all the flavors. However, we're going to - // want the higher priority one to be last. - val suffixes = mutableListOf<String>() - defaultConfig.applicationIdSuffix?.let { - suffixes.add(it) - } - - suffixes.addAll( - productFlavorList - .asSequence() - .filterIsInstance(ApplicationProductFlavor::class.java) - .mapNotNull { it.applicationIdSuffix }) - - // then we add the build type after. - (buildTypeObj as? ApplicationBuildType)?.applicationIdSuffix?.let { - suffixes.add(it) - } - val nonEmptySuffixes = suffixes.filter { it.isNotEmpty() } - return if (nonEmptySuffixes.isNotEmpty()) { - ".${nonEmptySuffixes.joinToString(separator = ".", transform = { it.removePrefix(".") })}" - } else { - "" - } - } - - override val versionName: Provider<String?> - get() { - // This value is meaningless for tests - if (componentType.isForTesting) { - val callable: Callable<String?> = Callable { null } - return services.provider(callable) - } - - // If the version name from the flavors is null, then we read from the manifest and combine - // with suffixes, unless it's a test at which point we just return. - // If the name is not-null, we just combine it with suffixes - val versionNameFromFlavors = - productFlavorList - .asSequence() - .filterIsInstance(ApplicationProductFlavor::class.java) - .map { it.versionName } - .firstOrNull { it != null } - ?: defaultConfig.versionName - - return if (versionNameFromFlavors == null) { - // rely on manifest value - // using map will allow us to keep task dependency should the manifest be generated or - // transformed via a task. - dataProvider.manifestData.map { - if (it.versionName == null) { - it.versionName - } else { - "${it.versionName}${computeVersionNameSuffix()}" - } - } - } else { - // use value from flavors - services.provider( - Callable { "$versionNameFromFlavors${computeVersionNameSuffix()}" }) - } - } - - private fun computeVersionNameSuffix(): String { - // for the suffix we combine the suffix from all the flavors. However, we're going to - // want the higher priority one to be last. - val suffixes = mutableListOf<String>() - defaultConfig.versionNameSuffix?.let { - suffixes.add(it) - } - - suffixes.addAll( - productFlavorList - .asSequence() - .filterIsInstance(ApplicationProductFlavor::class.java) - .mapNotNull { it.versionNameSuffix }) - - // then we add the build type after. - (buildTypeObj as? ApplicationBuildType)?.versionNameSuffix?.let { - suffixes.add(it) - } - - return if (suffixes.isNotEmpty()) { - suffixes.joinToString(separator = "") - } else { - "" - } - } - - override val versionCode: Provider<Int?> - get() { - // This value is meaningless for tests - if (componentType.isForTesting) { - val callable: Callable<Int?> = Callable { null } - return services.provider(callable) - } - - // If the version code from the flavors is null, then we read from the manifest and combine - // with suffixes, unless it's a test at which point we just return. - // If the name is not-null, we just combine it with suffixes - val versionCodeFromFlavors = - productFlavorList - .asSequence() - .filterIsInstance(ApplicationProductFlavor::class.java) - .map { it.versionCode } - .firstOrNull { it != null } - ?: defaultConfig.versionCode - - return if (versionCodeFromFlavors == null) { - // rely on manifest value - // using map will allow us to keep task dependency should the manifest be generated or - // transformed via a task. - dataProvider.manifestData.map { it.versionCode } - } else { - // use value from flavors - services.provider(Callable { versionCodeFromFlavors }) - } - } - - override fun getInstrumentationRunner(dexingType: DexingType): Provider<String> { - if (!componentType.isForTesting) { - throw RuntimeException("instrumentationRunner is not available to non-test variant") - } - - // first check whether the DSL has the info - val fromFlavor = - productFlavorList.asSequence().map { it.testInstrumentationRunner } - .firstOrNull { it != null } - ?: defaultConfig.testInstrumentationRunner - - if (fromFlavor != null) { - val finalFromFlavor: String = fromFlavor - return services.provider(Callable { finalFromFlavor }) - } - - // else return the value from the Manifest - return dataProvider.manifestData.map { - it.instrumentationRunner - ?: if (dexingType.isLegacyMultiDexMode()) { - MULTIDEX_TEST_RUNNER - } else { - DEFAULT_TEST_RUNNER - } - } - } - - /** - * Returns the instrumentationRunner arguments to use to test this variant, or if the variant is - * a test, the ones to use to test the tested variant - */ - override val instrumentationRunnerArguments: Map<String, String> - get() { - val variantDslInfo: VariantDslInfoImpl = - if (componentType.isTestComponent) { - productionVariant!! - } else { - this - } - return variantDslInfo.mergedFlavor.testInstrumentationRunnerArguments - } - - override val handleProfiling: Provider<Boolean> - get() { - if (!componentType.isForTesting) { - throw RuntimeException("handleProfiling is not available to non-test variant") - } - - // first check whether the DSL has the info - val fromFlavor = - productFlavorList.asSequence().map { it.testHandleProfiling } - .firstOrNull { it != null } - ?: defaultConfig.testHandleProfiling - - if (fromFlavor != null) { - val finalFromFlavor: Boolean = fromFlavor - return services.provider(Callable { finalFromFlavor }) - } - - // else return the value from the Manifest - return dataProvider.manifestData.map { it.handleProfiling ?: DEFAULT_HANDLE_PROFILING } - } - - override val functionalTest: Provider<Boolean> - get() { - if (!componentType.isForTesting) { - throw RuntimeException("functionalTest is not available to non-test variant") - } - - // first check whether the DSL has the info - val fromFlavor = - productFlavorList.asSequence().map { it.testFunctionalTest } - .firstOrNull { it != null } - ?: defaultConfig.testFunctionalTest - - if (fromFlavor != null) { - val finalFromFlavor: Boolean = fromFlavor - return services.provider(Callable { finalFromFlavor }) - } - - // else return the value from the Manifest - return dataProvider.manifestData.map { it.functionalTest ?: DEFAULT_FUNCTIONAL_TEST } - } - - override val testLabel: Provider<String?> - get() { - if (!componentType.isForTesting) { - throw RuntimeException("handleProfiling is not available to non-test variant") - } - - // there is actually no DSL value for this. - return dataProvider.manifestData.map { it.testLabel } - } - - /** - * The minSdkVersion for this variant. - * - * This is only the version declared in the DSL, not including the value present in the Manifest. - */ - override val minSdkVersion: MutableAndroidVersion - // if there's a testedVariant, return its value, otherwise return the merged flavor - // value. If there's no value set, then the default is just the first API Level: 1 - get() = testedVariant?.minSdkVersion - ?: mergedFlavor.minSdkVersion?.let { MutableAndroidVersion(it.apiLevel, it.codename) } - ?: MutableAndroidVersion(1) - - override val maxSdkVersion: Int? - get() = mergedFlavor.maxSdkVersion - - /** - * The targetSdkVersion for this variant. - * - * This is only the version declared in the DSL, not including the value present in the Manifest. - */ - override val targetSdkVersion: MutableAndroidVersion? - // if there's a testedVariant, return its value, otherwise return the merged flavor - // value. If there's no value set, then return null - get() = testedVariant?.targetSdkVersion - ?: mergedFlavor.targetSdkVersion?.let { MutableAndroidVersion(it.apiLevel, it.codename) } - - override val renderscriptTarget: Int = mergedFlavor.renderscriptTargetApi ?: -1 - - override val isWearAppUnbundled: Boolean? - get() = mergedFlavor.wearAppUnbundled - - @Suppress("DEPRECATION") - override val missingDimensionStrategies: ImmutableMap<String, AbstractProductFlavor.DimensionRequest> - get() = ImmutableMap.copyOf(mergedFlavor.missingDimensionStrategies) - - override val resourceConfigurations: ImmutableSet<String> - get() = ImmutableSet.copyOf(mergedFlavor.resourceConfigurations) - - override val vectorDrawables: VectorDrawablesOptions - get() = mergedFlavor.vectorDrawables - - override fun getBuildConfigFields(): Map<String, BuildConfigField<out java.io.Serializable>> { - val buildConfigFieldsMap = - mutableMapOf<String, BuildConfigField<out java.io.Serializable>>() - - fun addToListIfNotAlreadyPresent(classField: ClassField, comment: String) { - if (!buildConfigFieldsMap.containsKey(classField.name)) { - buildConfigFieldsMap[classField.name] = - BuildConfigField(classField.type , classField.value, comment) - } - } - - (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).buildConfigFields.values.forEach { classField -> - addToListIfNotAlreadyPresent(classField, "Field from build type: ${buildTypeObj.name}") - } - - for (flavor in productFlavorList) { - (flavor as com.android.build.gradle.internal.dsl.ProductFlavor).buildConfigFields.values.forEach { classField -> - addToListIfNotAlreadyPresent( - classField, - "Field from product flavor: ${flavor.name}" - ) - } - } - defaultConfig.buildConfigFields.values.forEach { classField -> - addToListIfNotAlreadyPresent(classField, "Field from default config.") - } - return buildConfigFieldsMap - } - - /** - * Returns a list of generated resource values. - * - * - * Items can be either fields (instance of [com.android.builder.model.ClassField]) or - * comments (instance of String). - * - * @return a list of items. - */ - override fun getResValues(): Map<ResValue.Key, ResValue> { - val resValueFields = mutableMapOf<ResValue.Key, ResValue>() - - fun addToListIfNotAlreadyPresent(classField: ClassField, comment: String) { - val key = ResValueKeyImpl(classField.type, classField.name) - if (!resValueFields.containsKey(key)) { - resValueFields[key] = ResValue( - value = classField.value, - comment = comment - ) - } - } - - (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).resValues.values.forEach { classField -> - addToListIfNotAlreadyPresent(classField, "Value from build type: ${buildTypeObj.name}") - } - - productFlavorList.forEach { flavor -> - (flavor as com.android.build.gradle.internal.dsl.ProductFlavor).resValues.values.forEach { classField -> - addToListIfNotAlreadyPresent( - classField, - "Value from product flavor: ${flavor.name}" - ) - } - } - - defaultConfig.resValues.values.forEach { classField -> - addToListIfNotAlreadyPresent(classField, "Value from default config.") - } - - return resValueFields - } - - override val signingConfig: SigningConfig? - get() { - if (componentType.isDynamicFeature || - testedVariant?.componentType?.isDynamicFeature == true - ) { - return null - } - val dslSigningConfig = - (buildTypeObj as? ApplicationBuildType)?.signingConfig - ?: mergedFlavor.signingConfig - - signingConfigOverride?.let { - // use enableV1 and enableV2 from the DSL if the override values are null - if (it.enableV1Signing == null) { - it.enableV1Signing = dslSigningConfig?.enableV1Signing - } - if (it.enableV2Signing == null) { - it.enableV2Signing = dslSigningConfig?.enableV2Signing - } - // use enableV3 and enableV4 from the DSL because they're not injectable - it.enableV3Signing = dslSigningConfig?.enableV3Signing - it.enableV4Signing = dslSigningConfig?.enableV4Signing - return it - } - if (dslSigningConfig == null && (isProfileable || isDebuggable)) { - return extension.signingConfigs.findByName(BuilderConstants.DEBUG) as SigningConfig? - } - return dslSigningConfig as SigningConfig? - } - - override val isSigningReady: Boolean - get() { - val signingConfig = signingConfig - return signingConfig != null && signingConfig.isSigningReady - } - - override val isAndroidTestCoverageEnabled: Boolean - get() = buildTypeObj.enableAndroidTestCoverage || buildTypeObj.isTestCoverageEnabled - - override val isUnitTestCoverageEnabled: Boolean - get() = buildTypeObj.enableUnitTestCoverage || buildTypeObj.isTestCoverageEnabled - - /** - * Returns the merged manifest placeholders. All product flavors are merged first, then build - * type specific placeholders are added and potentially overrides product flavors values. - * - * @return the merged manifest placeholders for a build variant. - */ - override val manifestPlaceholders: Map<String, String> by lazy { - val mergedFlavorsPlaceholders: MutableMap<String, String> = mutableMapOf() - mergedFlavor.manifestPlaceholders.forEach { (key, value) -> - mergedFlavorsPlaceholders[key] = value.toString() - } - // so far, blindly override the build type placeholders - buildTypeObj.manifestPlaceholders.forEach { (key, value) -> - mergedFlavorsPlaceholders[key] = value.toString() - } - mergedFlavorsPlaceholders - } - - // Only require specific multidex opt-in for legacy multidex. - override val isMultiDexEnabled: Boolean? - get() { - // Only require specific multidex opt-in for legacy multidex. - return (buildTypeObj as? ApplicationBuildType)?.multiDexEnabled - ?: mergedFlavor.multiDexEnabled - } - - override val multiDexKeepFile: File? - get() { - var value = buildTypeObj.multiDexKeepFile - if (value != null) { - return value - } - value = mergedFlavor.multiDexKeepFile - return value - } - - override val multiDexKeepProguard: File? - get() { - var value = buildTypeObj.multiDexKeepProguard - if (value != null) { - return value - } - value = mergedFlavor.multiDexKeepProguard - return value - } - - // dynamic features can always be build in native multidex mode - override val dexingType: DexingType? - get() = if (componentType.isDynamicFeature) { - if ((buildTypeObj as? ApplicationBuildType)?.multiDexEnabled != null || - mergedFlavor.multiDexEnabled != null - ) { - dslServices.issueReporter - .reportWarning( - IssueReporter.Type.GENERIC, - "Native multidex is always used for dynamic features. Please " + - "remove 'multiDexEnabled true|false' from your " + - "build.gradle file." - ) - } - // dynamic features can always be build in native multidex mode - DexingType.NATIVE_MULTIDEX - } else null - - /** Returns the renderscript support mode. */ - override val renderscriptSupportModeEnabled: Boolean - get() = mergedFlavor.renderscriptSupportModeEnabled ?: false - - /** Returns the renderscript BLAS support mode. */ - override val renderscriptSupportModeBlasEnabled: Boolean - get() { - val value = mergedFlavor.renderscriptSupportModeBlasEnabled - return value ?: false - } - - /** Returns the renderscript NDK mode. */ - override val renderscriptNdkModeEnabled: Boolean - get() = mergedFlavor.renderscriptNdkModeEnabled ?: false - - /** Returns true if the variant output is a bundle. */ - override val isBundled: Boolean - get() = componentType.isAar // Consider runtime API passed from the IDE only if multi-dex is enabled and the app is debuggable. - - /** - * Returns the API to which device/emulator we're deploying via the IDE or null if not. - * Can be used to optimize some build steps when deploying via the IDE (for testing). - * - * This has no relation with targetSdkVersion from build.gradle/manifest. - */ - override val targetDeployApiFromIDE: Int? = - dslServices.projectOptions.get(IntegerOption.IDE_TARGET_DEVICE_API) - - /** - * Merge Gradle specific options from build types, product flavors and default config. - */ - private fun mergeOptions() { - computeMergedOptions( - mergedJavaCompileOptions, - { javaCompileOptions as JavaCompileOptions }, - { javaCompileOptions as JavaCompileOptions } - ) - computeMergedOptions( - mergedNdkConfig, - { ndk as CoreNdkOptions }, - { ndk as CoreNdkOptions } - ) - computeMergedOptions( - mergedExternalNativeBuildOptions, - { externalNativeBuild as CoreExternalNativeBuildOptions }, - { externalNativeBuild as CoreExternalNativeBuildOptions } - ) - if (componentType.isAar) { - computeMergedOptions( - mergedAarMetadata, - { (this as LibraryVariantDimension).aarMetadata }, - { (this as LibraryVariantDimension).aarMetadata } - ) - } - computeMergedOptions( - mergedOptimization, - { optimization as OptimizationImpl }, - { optimization as OptimizationImpl } - ) - } - - override val nativeBuildSystem: NativeBuiltType? - get() { - if (externalNativeExperimentalProperties.ninja.path != null) return NativeBuiltType.NINJA - if (extension.externalNativeBuild.ndkBuild.path != null) return NativeBuiltType.NDK_BUILD - if (extension.externalNativeBuild.cmake.path != null) return NativeBuiltType.CMAKE - return null - } - - override val ndkConfig: MergedNdkConfig - get() = mergedNdkConfig - - override val externalNativeBuildOptions: CoreExternalNativeBuildOptions - get() = mergedExternalNativeBuildOptions - - override val aarMetadata: MergedAarMetadata - get() = mergedAarMetadata - - /** - * Returns the ABI filters associated with the artifact, or empty set if there are no filters. - * - * If the list contains values, then the artifact only contains these ABIs and excludes - * others. - */ - override val supportedAbis: Set<String> - get() = if (componentType.isDynamicFeature) setOf() else mergedNdkConfig.abiFilters - - override fun getProguardFiles(into: ListProperty<RegularFile>) { - val result: MutableList<File> = ArrayList(gatherProguardFiles(ProguardFileType.EXPLICIT)) - if (result.isEmpty()) { - result.addAll(_postProcessingOptions.getDefaultProguardFiles()) - } - - val projectDir = services.projectInfo.projectDirectory - result.forEach { file -> - into.add(projectDir.file(file.absolutePath)) - } - } - - override fun gatherProguardFiles(type: ProguardFileType): Collection<File> { - val result: MutableList<File> = ArrayList(defaultConfig.getProguardFiles(type)) - for (flavor in productFlavorList) { - result.addAll((flavor as com.android.build.gradle.internal.dsl.ProductFlavor).getProguardFiles(type)) - } - result.addAll(_postProcessingOptions.getProguardFiles(type)) - return result - } - - /** - * Merge a specific option in GradleVariantConfiguration. - * - * - * It is assumed that merged option type with a method to reset and append is created for the - * option being merged. - * - * - * The order of priority is BuildType, ProductFlavors, and default config. ProductFlavor - * added earlier has higher priority than ProductFlavor added later. - * - * @param mergedOption The merged option store in the GradleVariantConfiguration. - * @param getFlavorOption A Function to return the option from a ProductFlavor. - * @param getBuildTypeOption A Function to return the option from a BuildType. - * takes priority and overwrite option in the first input argument. - * @param <CoreOptionsT> The core type of the option being merge. - * @param <MergedOptionsT> The merge option type. - </MergedOptionsT></CoreOptionsT> */ - private fun <CoreOptionsT, MergedOptionsT : MergedOptions<CoreOptionsT>> computeMergedOptions( - mergedOption: MergedOptionsT, - getFlavorOption: VariantDimension.() -> CoreOptionsT?, - getBuildTypeOption: BuildType.() -> CoreOptionsT? - ) { - mergedOption.reset() - - val defaultOption = defaultConfig.getFlavorOption() - if (defaultOption != null) { - mergedOption.append(defaultOption) - } - // reverse loop for proper order - for (i in productFlavorList.indices.reversed()) { - val flavorOption = productFlavorList[i].getFlavorOption() - if (flavorOption != null) { - mergedOption.append(flavorOption) - } - } - val buildTypeOption = buildTypeObj.getBuildTypeOption() - if (buildTypeOption != null) { - mergedOption.append(buildTypeOption) - } - } - - override val javaCompileOptions: JavaCompileOptions - get() = mergedJavaCompileOptions - - private var _postProcessingOptions: PostProcessingOptions = - if ((buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).postProcessingConfiguration == PostProcessingConfiguration.POSTPROCESSING_BLOCK) { - PostProcessingBlockOptions( - buildTypeObj.postprocessing, componentType.isTestComponent - ) - } else object : PostProcessingOptions { - override fun getProguardFiles(type: ProguardFileType): Collection<File> = - buildTypeObj.getProguardFiles(type) - - override fun getDefaultProguardFiles(): List<File> = - listOf( - ProguardFiles.getDefaultProguardFile( - ProguardFiles.ProguardFile.DONT_OPTIMIZE.fileName, - buildDirectory - ) - ) - - override fun getPostprocessingFeatures(): PostprocessingFeatures? = null - - override fun codeShrinkerEnabled() = buildTypeObj.isMinifyEnabled - - override fun resourcesShrinkingEnabled(): Boolean = buildTypeObj.isShrinkResources - - override fun hasPostProcessingConfiguration() = false - } - - override fun getPostProcessingOptions(): PostProcessingOptions = _postProcessingOptions - - // add the lower priority one, to override them with the higher priority ones. - // cant use merge flavor as it's not a prop on the base class. - // reverse loop for proper order - override val defaultGlslcArgs: List<String> - get() { - val optionMap: MutableMap<String, String> = - Maps.newHashMap() - // add the lower priority one, to override them with the higher priority ones. - for (option in defaultConfig.shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - // cant use merge flavor as it's not a prop on the base class. - // reverse loop for proper order - for (i in productFlavorList.indices.reversed()) { - for (option in productFlavorList[i].shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - } - // then the build type - for (option in buildTypeObj.shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - return Lists.newArrayList(optionMap.values) - } - - // first collect all possible keys. - override val scopedGlslcArgs: Map<String, List<String>> - get() { - val scopedArgs: MutableMap<String, List<String>> = - Maps.newHashMap() - // first collect all possible keys. - val keys = scopedGlslcKeys - for (key in keys) { // first add to a temp map to resolve overridden values - val optionMap: MutableMap<String, String> = - Maps.newHashMap() - // we're going to go from lower priority, to higher priority elements, and for each - // start with the non scoped version, and then add the scoped version. - // 1. default config, global. - for (option in defaultConfig.shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - // 1b. default config, scoped. - for (option in defaultConfig.shaders.scopedGlslcArgs[key]) { - optionMap[getKey(option)] = option - } - // 2. the flavors. - // cant use merge flavor as it's not a prop on the base class. - // reverse loop for proper order - for (i in productFlavorList.indices.reversed()) { // global - for (option in productFlavorList[i].shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - // scoped. - for (option in productFlavorList[i].shaders.scopedGlslcArgs[key]) { - optionMap[getKey(option)] = option - } - } - // 3. the build type, global - for (option in buildTypeObj.shaders.glslcArgs) { - optionMap[getKey(option)] = option - } - // 3b. the build type, scoped. - for (option in buildTypeObj.shaders.scopedGlslcArgs[key]) { - optionMap[getKey(option)] = option - } - // now add the full value list. - scopedArgs[key] = ImmutableList.copyOf(optionMap.values) - } - return scopedArgs - } - - private val scopedGlslcKeys: Set<String> - get() { - val keys: MutableSet<String> = - Sets.newHashSet() - keys.addAll(defaultConfig.shaders.scopedGlslcArgs.keySet()) - for (flavor in productFlavorList) { - keys.addAll(flavor.shaders.scopedGlslcArgs.keySet()) - } - keys.addAll(buildTypeObj.shaders.scopedGlslcArgs.keySet()) - return keys - } - - override val isDebuggable: Boolean - get() = ProfilingMode.getProfilingModeType( - services.projectOptions[StringOption.PROFILING_MODE] - ).isDebuggable - ?: (buildTypeObj as? ApplicationBuildType)?.isDebuggable - ?: false - - override val isEmbedMicroApp: Boolean - get() = (buildTypeObj as? ApplicationBuildType)?.isEmbedMicroApp ?: false - - override val isProfileable: Boolean - get() { - val fromProfilingModeOption = ProfilingMode.getProfilingModeType( - services.projectOptions[StringOption.PROFILING_MODE] - ).isProfileable - val fromBuildType = (buildTypeObj as? ApplicationBuildType)?.isProfileable - // When profileable is enabled from the profilingMode option, it ensures all profileable - // features are supported, therefore the compileSdk => 30. - val minProfileableSdk = 30 - val compileSdk = extension.compileSdk ?: minProfileableSdk - if ((fromProfilingModeOption == true || fromBuildType == true) - && compileSdk < minProfileableSdk - ) { - services.issueReporter.reportError(IssueReporter.Type.COMPILE_SDK_VERSION_TOO_LOW, - """'profileable' is enabled with compile SDK <30. - Recommended action: If possible, upgrade compileSdk from ${minSdkVersion.apiLevel} to 30.""" - .trimIndent() - ) - } - return when { - fromProfilingModeOption != null -> { - fromProfilingModeOption - } - fromBuildType == true && isDebuggable -> { - val projectName = services.projectInfo.name - val message = - ":$projectName build type '${buildTypeObj.name}' can only have debuggable or profileable enabled.\n" + - "Only one of these options can be used at a time.\n" + - "Recommended action: Only set one of debuggable=true and profileable=true.\n" - services.issueReporter.reportWarning(IssueReporter.Type.GENERIC, message) - // Disable profileable when profileable and debuggable are both enabled. - false - } - else -> { - fromBuildType == true - } - } - } - - override val isPseudoLocalesEnabled: Boolean - get() = buildTypeObj.isPseudoLocalesEnabled - - override val isCrunchPngs: Boolean? - get() { - return when (buildTypeObj) { - is ApplicationBuildType -> buildTypeObj.isCrunchPngs - is DynamicFeatureBuildType -> buildTypeObj.isCrunchPngs - else -> false - } - } - - @Suppress("OverridingDeprecatedMember", "DEPRECATION") - override val isCrunchPngsDefault: Boolean - // does not exist in the new DSL - get() = (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).isCrunchPngsDefault - - override val isRenderscriptDebuggable: Boolean - get() = buildTypeObj.isRenderscriptDebuggable - - override val renderscriptOptimLevel: Int - get() = buildTypeObj.renderscriptOptimLevel - - override val isJniDebuggable: Boolean - get() = buildTypeObj.isJniDebuggable - - override val testFixtures: TestFixtures - get() { - if (extension is TestedExtension) { - return extension.testFixtures - } - - throw RuntimeException("call to VariantDslInfo.testFixtures on wrong extension type: ${extension.javaClass.name}") - } - - override val androidResources: AndroidResources - get() = extension.androidResources - - override val packaging: PackagingOptions - get() = extension.packagingOptions - - override val compileOptions: CompileOptions - get() = extension.compileOptions - - // when we remove the old DSL (and the old Transforms API) this should be deleted as well. - override val transforms: List<Transform> - get() = oldExtension.transforms - - override val lintOptions: Lint - get() = extension.lint - - override val ignoredLibraryKeepRules: Set<String> - get() = mergedOptimization.ignoredLibraryKeepRules - - override val ignoreAllLibraryKeepRules: Boolean - get() = mergedOptimization.ignoreAllLibraryKeepRules - - override val externalNativeExperimentalProperties: Map<String, Any> - get() { - // merge global and variant properties - val mergedProperties = mutableMapOf<String, Any>() - mergedProperties.putAll(extension.externalNativeBuild.experimentalProperties) - mergedProperties.putAll( - mergedExternalNativeBuildOptions.externalNativeExperimentalProperties - ) - return mergedProperties - } - - // Only applicable for testFixtures - // TODO: Remove once we split up the implementations - override val testFixturesAndroidResourcesEnabled: Boolean - get() = productionVariant!!.testFixtures.androidResources - - companion object { - - const val DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner" - private const val MULTIDEX_TEST_RUNNER = - "com.android.test.runner.MultiDexTestRunner" - private const val DEFAULT_HANDLE_PROFILING = false - private const val DEFAULT_FUNCTIONAL_TEST = false - - private fun getKey(fullOption: String): String { - val pos = fullOption.lastIndexOf('=') - return if (pos == -1) { - fullOption - } else fullOption.substring(0, pos) - } - - private fun CommonExtension<*, *, *, *>.getDslNamespace(componentType: ComponentType): String? { - return if (componentType.isTestComponent) { - (this as TestedExtension).testNamespace - } else if (componentType.isTestFixturesComponent) { - null - } else { - namespace - } - } - - private fun CommonExtension<*, *, *, *>.testNamespaceEqualsNamespace(): Boolean = - this is TestedExtension && testNamespace != null && testNamespace == namespace - } -} - -private fun BaseConfig.getProguardFiles(type: ProguardFileType): Collection<File> = when (type) { - ProguardFileType.EXPLICIT -> this.proguardFiles - ProguardFileType.TEST -> this.testProguardFiles - ProguardFileType.CONSUMER -> this.consumerProguardFiles -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AarProducingComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AarProducingComponentDslInfo.kt index 18d6ab66ae..c5759805ff 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AarProducingComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AarProducingComponentDslInfo.kt @@ -16,13 +16,8 @@ package com.android.build.gradle.internal.core.dsl -import com.android.build.gradle.internal.core.MergedAarMetadata - /** * Contains the final dsl info computed from the DSL object model (extension, default config, * build type, flavors) that are needed by components that produces AARs. */ -interface AarProducingComponentDslInfo { - - val aarMetadata: MergedAarMetadata -} +interface AarProducingComponentDslInfo diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AndroidTestComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AndroidTestComponentDslInfo.kt index 0fe5697f5a..9221ef6e74 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AndroidTestComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/AndroidTestComponentDslInfo.kt @@ -24,7 +24,7 @@ import org.gradle.api.provider.Provider * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.AndroidTestCreationConfig] */ diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApkProducingComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApkProducingComponentDslInfo.kt index d8b294e267..e587247846 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApkProducingComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApkProducingComponentDslInfo.kt @@ -27,8 +27,6 @@ interface ApkProducingComponentDslInfo: ConsumableComponentDslInfo { val isDebuggable: Boolean - val isProfileable: Boolean - /** Holds all SigningConfig information from the DSL and/or [ProjectOptions]. */ val signingConfig: SigningConfig? diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApplicationVariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApplicationVariantDslInfo.kt index 48de74ae04..7b3c51a2cb 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApplicationVariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ApplicationVariantDslInfo.kt @@ -24,11 +24,11 @@ import org.gradle.api.provider.Provider * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.ApplicationCreationConfig] */ -interface ApplicationVariantDslInfo: VariantDslInfo, ApkProducingComponentDslInfo, PublishableVariantDslInfo, TestedComponentDslInfo { +interface ApplicationVariantDslInfo: VariantDslInfo, ApkProducingComponentDslInfo, PublishableComponentDslInfo, TestedVariantDslInfo { /** * Returns the version name for this variant. This could be specified by the product flavors, @@ -50,4 +50,6 @@ interface ApplicationVariantDslInfo: VariantDslInfo, ApkProducingComponentDslInf val isWearAppUnbundled: Boolean? val isEmbedMicroApp: Boolean + + val isProfileable: Boolean } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ComponentDslInfo.kt index 9698bc680e..0349ec1e2b 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ComponentDslInfo.kt @@ -48,8 +48,6 @@ interface ComponentDslInfo: DimensionCombination { /** The list of product flavors. Items earlier in the list override later items. */ val productFlavorList: List<ProductFlavor> - fun hasFlavors(): Boolean - val missingDimensionStrategies: ImmutableMap<String, AbstractProductFlavor.DimensionRequest> /** @@ -128,23 +126,12 @@ interface ComponentDslInfo: DimensionCombination { */ fun getResValues(): Map<ResValue.Key, ResValue> - /** - * Returns the merged manifest placeholders. All product flavors are merged first, then build - * type specific placeholders are added and potentially overrides product flavors values. - * - * @return the merged manifest placeholders for a build variant. - */ - val manifestPlaceholders: Map<String, String> - - fun getPostProcessingOptions(): PostProcessingOptions + val postProcessingOptions: PostProcessingOptions /** - * TODO: Clean this up + * TODO(b/242515559): Clean this up */ val isAndroidTestCoverageEnabled: Boolean fun gatherProguardFiles(type: ProguardFileType): Collection<File> - - // TODO: Move to VariantDslInfo - val experimentalProperties: Map<String, Any> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ConsumableComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ConsumableComponentDslInfo.kt index 5d9da953b5..bae52ffbb2 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ConsumableComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/ConsumableComponentDslInfo.kt @@ -78,4 +78,12 @@ interface ConsumableComponentDslInfo: ComponentDslInfo { * @return a list of items. */ fun getBuildConfigFields(): Map<String, BuildConfigField<out Serializable>> + + /** + * Returns the merged manifest placeholders. All product flavors are merged first, then build + * type specific placeholders are added and potentially overrides product flavors values. + * + * @return the merged manifest placeholders for a build variant. + */ + val manifestPlaceholders: Map<String, String> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/DynamicFeatureVariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/DynamicFeatureVariantDslInfo.kt index 6759364f3a..bbd20ad14e 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/DynamicFeatureVariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/DynamicFeatureVariantDslInfo.kt @@ -16,19 +16,19 @@ package com.android.build.gradle.internal.core.dsl -import com.android.builder.dexing.DexingType - /** * Represents the dsl info for a dynamic feature variant, initialized from the DSL object model * (extension, default config, build type, flavors) * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.DynamicFeatureCreationConfig] */ -interface DynamicFeatureVariantDslInfo: VariantDslInfo, ApkProducingComponentDslInfo, TestedComponentDslInfo { - // dynamic features can always be build in native multidex mode - val dexingType: DexingType? +interface DynamicFeatureVariantDslInfo: + VariantDslInfo, + ApkProducingComponentDslInfo, + TestedVariantDslInfo { + val isMultiDexSetFromDsl: Boolean } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/InstrumentedTestComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/InstrumentedTestComponentDslInfo.kt index 282b2dd21e..43f4ff2b37 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/InstrumentedTestComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/InstrumentedTestComponentDslInfo.kt @@ -32,14 +32,12 @@ interface InstrumentedTestComponentDslInfo { * @param dexingType the selected dexing type for this variant. * @return the instrumentation test runner name */ - // DO NOT USE, Use CreationConfig and subtypes methods. fun getInstrumentationRunner(dexingType: DexingType): Provider<String> /** * Returns the instrumentationRunner arguments to use to test this variant, or if the variant is * a test, the ones to use to test the tested variant */ - // DO NOT USE, Use CreationConfig and subtypes methods. val instrumentationRunnerArguments: Map<String, String> /** @@ -48,7 +46,6 @@ interface InstrumentedTestComponentDslInfo { * * @return the handleProfiling value */ - // DO NOT USE, Use CreationConfig and subtypes methods. val handleProfiling: Provider<Boolean> /** @@ -57,10 +54,8 @@ interface InstrumentedTestComponentDslInfo { * * @return the functionalTest value */ - // DO NOT USE, Use CreationConfig and subtypes methods. val functionalTest: Provider<Boolean> /** Gets the test label for this variant */ - // DO NOT USE, Use CreationConfig and subtypes methods. val testLabel: Provider<String?> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/LibraryVariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/LibraryVariantDslInfo.kt index fef5fdcb60..87cb3b2078 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/LibraryVariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/LibraryVariantDslInfo.kt @@ -16,19 +16,21 @@ package com.android.build.gradle.internal.core.dsl +import com.android.build.gradle.internal.core.MergedAarMetadata + /** * Represents the dsl info for a library variant, initialized from the DSL object model * (extension, default config, build type, flavors) * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.LibraryCreationConfig] */ -interface LibraryVariantDslInfo: VariantDslInfo, AarProducingComponentDslInfo, PublishableVariantDslInfo, TestedComponentDslInfo { +interface LibraryVariantDslInfo: VariantDslInfo, AarProducingComponentDslInfo, PublishableComponentDslInfo, TestedVariantDslInfo { + val aarMetadata: MergedAarMetadata // TODO: Clean this up val isDebuggable: Boolean - val isProfileable: Boolean } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/PublishableVariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/PublishableComponentDslInfo.kt index 31c7e070b1..defe4181ca 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/PublishableVariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/PublishableComponentDslInfo.kt @@ -22,7 +22,6 @@ import com.android.build.gradle.internal.publishing.VariantPublishingInfo * Contains the final dsl info computed from the DSL object model (extension, default config, * build type, flavors) that are needed by publishable components. */ -interface PublishableVariantDslInfo { - // TODO: Remove nullability when implementation is split up - val publishInfo: VariantPublishingInfo? +interface PublishableComponentDslInfo { + val publishInfo: VariantPublishingInfo } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestComponentDslInfo.kt index 8071949d4e..599d5e6a28 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestComponentDslInfo.kt @@ -28,6 +28,5 @@ interface TestComponentDslInfo: ComponentDslInfo { * * @see ComponentType.isTestComponent */ - // TODO: remove nullability when implementation is split up - val testedVariant: TestedComponentDslInfo? + val testedVariantDslInfo: TestedVariantDslInfo } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestFixturesComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestFixturesComponentDslInfo.kt index a5de5c482b..e7f27364e6 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestFixturesComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestFixturesComponentDslInfo.kt @@ -22,10 +22,11 @@ package com.android.build.gradle.internal.core.dsl * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.TestFixturesCreationConfig] */ -interface TestFixturesComponentDslInfo: VariantDslInfo, AarProducingComponentDslInfo { +interface TestFixturesComponentDslInfo + : ComponentDslInfo, AarProducingComponentDslInfo, PublishableComponentDslInfo { val testFixturesAndroidResourcesEnabled: Boolean } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestProjectVariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestProjectVariantDslInfo.kt index 30f1e6378e..53e13d7048 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestProjectVariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestProjectVariantDslInfo.kt @@ -22,7 +22,7 @@ package com.android.build.gradle.internal.core.dsl * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.TestVariantCreationConfig] */ diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestedComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestedVariantDslInfo.kt index 7cb4fd01ef..73cc522e2a 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestedComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/TestedVariantDslInfo.kt @@ -22,6 +22,8 @@ import com.android.build.api.dsl.TestFixtures * Contains the final dsl info computed from the DSL object model (extension, default config, * build type, flavors) that are needed by tested components. */ -interface TestedComponentDslInfo: VariantDslInfo { +interface TestedVariantDslInfo: VariantDslInfo { val testFixtures: TestFixtures + + val testInstrumentationRunnerArguments: Map<String, String> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/UnitTestComponentDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/UnitTestComponentDslInfo.kt index 9af92d7b80..7dd346379a 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/UnitTestComponentDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/UnitTestComponentDslInfo.kt @@ -22,7 +22,7 @@ package com.android.build.gradle.internal.core.dsl * * This class allows querying for the values set via the DSL model. * - * Use [VariantDslInfoBuilder] to instantiate. + * Use [DslInfoBuilder] to instantiate. * * @see [com.android.build.gradle.internal.component.UnitTestCreationConfig] */ diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/VariantDslInfo.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/VariantDslInfo.kt index 63f054e195..12e6799190 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/VariantDslInfo.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/VariantDslInfo.kt @@ -17,7 +17,6 @@ package com.android.build.gradle.internal.core.dsl import com.android.build.api.dsl.Lint import com.android.build.api.dsl.PackagingOptions -import com.android.build.api.variant.ResValue import com.android.build.gradle.internal.core.MergedNdkConfig import com.android.build.gradle.internal.core.NativeBuiltType import com.android.build.gradle.internal.dsl.CoreExternalNativeBuildOptions @@ -30,9 +29,6 @@ import org.gradle.api.provider.ListProperty */ interface VariantDslInfo: ComponentDslInfo, ConsumableComponentDslInfo { - /** Returns true if the variant output is a bundle. */ - val isBundled: Boolean - val nativeBuildSystem: NativeBuiltType? val ndkConfig: MergedNdkConfig @@ -49,18 +45,13 @@ interface VariantDslInfo: ComponentDslInfo, ConsumableComponentDslInfo { fun getProguardFiles(into: ListProperty<RegularFile>) - val isRenderscriptDebuggable: Boolean - val isJniDebuggable: Boolean val lintOptions: Lint val packaging: PackagingOptions - //////////////////////////////////////////////////////////////////////////////////////// - // APIs below should only be used at CreationConfig/Variant instantiation time // - // DO NOT USE THOSE IN TASKS // - //////////////////////////////////////////////////////////////////////////////////////// + val experimentalProperties: Map<String, Any> val externalNativeExperimentalProperties: Map<String, Any> } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/AndroidTestComponentDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/AndroidTestComponentDslInfoImpl.kt new file mode 100644 index 0000000000..854a6cd57b --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/AndroidTestComponentDslInfoImpl.kt @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.api.variant.impl.MutableAndroidVersion +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo +import com.android.build.gradle.internal.core.dsl.DynamicFeatureVariantDslInfo +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalTestedExtension +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.profile.ProfilingMode +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.StringOption +import com.android.builder.core.ComponentType +import com.android.builder.dexing.DexingType +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider + +internal class AndroidTestComponentDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + override val testedVariantDslInfo: TestedVariantDslInfo, + /** + * Whether there are inconsistent applicationId in the test. + * This trigger a mode where the namespaceForR just returns the same as namespace. + */ + private val inconsistentTestAppId: Boolean, + private val signingConfigOverride: SigningConfig?, + oldExtension: BaseExtension?, + extension: InternalTestedExtension<*, *, *, *> +) : ConsumableComponentDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + services, + buildDirectory, + oldExtension, + extension +), AndroidTestComponentDslInfo { + override val namespace: Provider<String> by lazy { + getTestComponentNamespace(extension, services, dataProvider) + } + + override val applicationId: Property<String> = + services.newPropertyBackingDeprecatedApi( + String::class.java, + initTestApplicationId(defaultConfig, services) + ) + + override val minSdkVersion: MutableAndroidVersion + get() = testedVariantDslInfo.minSdkVersion + override val maxSdkVersion: Int? + get() = testedVariantDslInfo.maxSdkVersion + override val targetSdkVersion: MutableAndroidVersion? + get() = testedVariantDslInfo.targetSdkVersion + + override val namespaceForR: Provider<String> by lazy { + if (inconsistentTestAppId) { + namespace + } else { + // For legacy reason, this code does the following: + // - If testNamespace is set, use it. + // - If android.namespace is set, use it with .test added + // - else, use the variant applicationId. + // TODO(b/176931684) Remove this and use [namespace] directly everywhere. + extension.testNamespace?.let { services.provider { it } } + ?: extension.namespace?.let { services.provider { it }.map { "$it.test" } } + ?: applicationId + } + } + + // TODO: Android Test doesn't have isDebuggable dsl in the build type, we should move to using + // the value from the tested type + override val isDebuggable: Boolean + get() = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isDebuggable + ?: (buildTypeObj as? ApplicationBuildType)?.isDebuggable + ?: false + + override val signingConfig: SigningConfig? by lazy { + if (testedVariantDslInfo is DynamicFeatureVariantDslInfo) { + null + } else { + getSigningConfig( + buildTypeObj, + mergedFlavor, + signingConfigOverride, + extension, + services + ) + } + } + + override val isSigningReady: Boolean + get() = signingConfig?.isSigningReady == true + + private val instrumentedTestDelegate by lazy { + InstrumentedTestDslInfoImpl( + productFlavorList, + defaultConfig, + dataProvider, + services, + testedVariantDslInfo.testInstrumentationRunnerArguments + ) + } + + override fun getInstrumentationRunner(dexingType: DexingType): Provider<String> { + return instrumentedTestDelegate.getInstrumentationRunner(dexingType) + } + + override val instrumentationRunnerArguments: Map<String, String> + get() = instrumentedTestDelegate.instrumentationRunnerArguments + override val handleProfiling: Provider<Boolean> + get() = instrumentedTestDelegate.handleProfiling + override val functionalTest: Provider<Boolean> + get() = instrumentedTestDelegate.functionalTest + override val testLabel: Provider<String?> + get() = instrumentedTestDelegate.testLabel +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ApplicationVariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ApplicationVariantDslInfoImpl.kt new file mode 100644 index 0000000000..e7c19e7496 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ApplicationVariantDslInfoImpl.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.ApplicationProductFlavor +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalApplicationExtension +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.profile.ProfilingMode +import com.android.build.gradle.internal.publishing.VariantPublishingInfo +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.StringOption +import com.android.builder.core.ComponentType +import com.android.builder.errors.IssueReporter +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Provider + +internal class ApplicationVariantDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + override val publishInfo: VariantPublishingInfo, + private val signingConfigOverride: SigningConfig?, + oldExtension: BaseExtension?, + extension: InternalApplicationExtension +) : TestedVariantDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + dataProvider, + services, + buildDirectory, + oldExtension, + extension +), ApplicationVariantDslInfo { + + private val applicationBuildType = buildTypeObj as ApplicationBuildType + + override val isDebuggable: Boolean + get() = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isDebuggable ?: applicationBuildType.isDebuggable + + override val isProfileable: Boolean + get() { + val fromProfilingModeOption = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isProfileable + // When profileable is enabled from the profilingMode option, it ensures all profileable + // features are supported, therefore the compileSdk => 30. + val minProfileableSdk = 30 + val compileSdk = extension.compileSdk ?: minProfileableSdk + if ((fromProfilingModeOption == true || applicationBuildType.isProfileable) && + compileSdk < minProfileableSdk + ) { + services.issueReporter.reportError( + IssueReporter.Type.COMPILE_SDK_VERSION_TOO_LOW, + """'profileable' is enabled with compile SDK <30. + Recommended action: If possible, upgrade compileSdk from ${minSdkVersion.apiLevel} to 30.""" + .trimIndent() + ) + } + return when { + fromProfilingModeOption != null -> { + fromProfilingModeOption + } + + applicationBuildType.isProfileable && isDebuggable -> { + val projectName = services.projectInfo.name + val message = + ":$projectName build type '${buildType}' can only have debuggable or profileable enabled.\n" + + "Only one of these options can be used at a time.\n" + + "Recommended action: Only set one of debuggable=true and profileable=true.\n" + services.issueReporter.reportWarning(IssueReporter.Type.GENERIC, message) + // Disable profileable when profileable and debuggable are both enabled. + false + } + else -> applicationBuildType.isProfileable + } + } + + override val signingConfig: SigningConfig? by lazy { + getSigningConfig( + buildTypeObj, + mergedFlavor, + signingConfigOverride, + extension, + services + ) + } + + override val isSigningReady: Boolean + get() = signingConfig?.isSigningReady == true + + override val versionName: Provider<String?> by lazy { + // If the version name from the flavors is null, then we read from the manifest and combine + // with suffixes, unless it's a test at which point we just return. + // If the name is not-null, we just combine it with suffixes + val versionNameFromFlavors = + productFlavorList + .asSequence() + .filterIsInstance(ApplicationProductFlavor::class.java) + .map { it.versionName } + .firstOrNull { it != null } + ?: defaultConfig.versionName + + if (versionNameFromFlavors == null) { + // rely on manifest value + // using map will allow us to keep task dependency should the manifest be generated or + // transformed via a task. + dataProvider.manifestData.map { + it.versionName?.let { versionName -> + "$versionName${computeVersionNameSuffix()}" + } + } + } else { + // use value from flavors + services.provider { "$versionNameFromFlavors${computeVersionNameSuffix()}" } + } + } + override val versionCode: Provider<Int?> by lazy { + // If the version code from the flavors is null, then we read from the manifest and combine + // with suffixes, unless it's a test at which point we just return. + // If the name is not-null, we just combine it with suffixes + val versionCodeFromFlavors = + productFlavorList + .asSequence() + .filterIsInstance(ApplicationProductFlavor::class.java) + .map { it.versionCode } + .firstOrNull { it != null } + ?: defaultConfig.versionCode + + if (versionCodeFromFlavors == null) { + // rely on manifest value + // using map will allow us to keep task dependency should the manifest be generated or + // transformed via a task. + dataProvider.manifestData.map { it.versionCode } + } else { + // use value from flavors + services.provider { versionCodeFromFlavors } + } + } + override val isWearAppUnbundled: Boolean? + get() = mergedFlavor.wearAppUnbundled + override val isEmbedMicroApp: Boolean + get() = applicationBuildType.isEmbedMicroApp + + private fun computeVersionNameSuffix(): String { + // for the suffix we combine the suffix from all the flavors. However, we're going to + // want the higher priority one to be last. + val suffixes = mutableListOf<String>() + defaultConfig.versionNameSuffix?.let { + suffixes.add(it) + } + + suffixes.addAll( + productFlavorList + .asSequence() + .filterIsInstance(ApplicationProductFlavor::class.java) + .mapNotNull { it.versionNameSuffix }) + + // then we add the build type after. + applicationBuildType.versionNameSuffix?.let { + suffixes.add(it) + } + + return if (suffixes.isNotEmpty()) { + suffixes.joinToString(separator = "") + } else { + "" + } + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ComponentDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ComponentDslInfoImpl.kt new file mode 100644 index 0000000000..92e22006e3 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ComponentDslInfoImpl.kt @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.AndroidResources +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.ApplicationProductFlavor +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.CompileOptions +import com.android.build.api.dsl.DynamicFeatureBuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.dsl.VariantDimension +import com.android.build.api.transform.Transform +import com.android.build.api.variant.ComponentIdentity +import com.android.build.api.variant.ResValue +import com.android.build.api.variant.impl.ResValueKeyImpl +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.ProguardFiles +import com.android.build.gradle.api.JavaCompileOptions +import com.android.build.gradle.internal.PostprocessingFeatures +import com.android.build.gradle.internal.ProguardFileType +import com.android.build.gradle.internal.core.MergedFlavor +import com.android.build.gradle.internal.core.MergedJavaCompileOptions +import com.android.build.gradle.internal.core.MergedOptions +import com.android.build.gradle.internal.core.PostProcessingBlockOptions +import com.android.build.gradle.internal.core.PostProcessingOptions +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.services.VariantServices +import com.android.builder.core.AbstractProductFlavor +import com.android.builder.core.ComponentType +import com.android.builder.model.BaseConfig +import com.android.builder.model.ClassField +import com.android.builder.model.VectorDrawablesOptions +import com.google.common.collect.ImmutableMap +import com.google.common.collect.ImmutableSet +import org.gradle.api.file.DirectoryProperty +import java.io.File + +internal abstract class ComponentDslInfoImpl internal constructor( + override val componentIdentity: ComponentIdentity, + final override val componentType: ComponentType, + protected val defaultConfig: DefaultConfig, + /** + * Public because this is needed by the old Variant API. Nothing else should touch this. + */ + val buildTypeObj: BuildType, + override val productFlavorList: List<ProductFlavor>, + protected val services: VariantServices, + private val buildDirectory: DirectoryProperty, + @Deprecated("use extension") private val oldExtension: BaseExtension?, + protected val extension: CommonExtension<*, *, *, *> +): ComponentDslInfo { + + override val buildType: String? + get() = componentIdentity.buildType + override val productFlavors: List<Pair<String, String>> + get() = componentIdentity.productFlavors + + /** + * This should be mostly private and not used outside this class, but is still public for legacy + * variant API and model v1 support. + * + * At some point we should remove this and rely on each property to combine dsl values in the + * manner that it is meaningful for the property. Take a look at + * [VariantDslInfoImpl.initApplicationId] for guidance on how will that look like. + * + * DO NOT USE. You should mostly use the interfaces which does not give access to this. + */ + val mergedFlavor: MergedFlavor by lazy { + MergedFlavor.mergeFlavors( + defaultConfig, + productFlavorList.map { it as com.android.build.gradle.internal.dsl.ProductFlavor }, + applicationId, + services + ) + } + + final override val javaCompileOptions = MergedJavaCompileOptions() + + init { + computeMergedOptions( + javaCompileOptions, + { javaCompileOptions as JavaCompileOptions }, + { javaCompileOptions as JavaCompileOptions } + ) + } + + // merged flavor delegates + + override val missingDimensionStrategies: ImmutableMap<String, AbstractProductFlavor.DimensionRequest> + get() = ImmutableMap.copyOf(mergedFlavor.missingDimensionStrategies) + + override val resourceConfigurations: ImmutableSet<String> + get() = ImmutableSet.copyOf(mergedFlavor.resourceConfigurations) + + override val vectorDrawables: VectorDrawablesOptions + get() = mergedFlavor.vectorDrawables + + // extension delegates + + override val compileOptions: CompileOptions + get() = extension.compileOptions + override val androidResources: AndroidResources + get() = extension.androidResources + override val transforms: List<Transform> + get() = oldExtension?.transforms ?: emptyList() + + // build type delegates + + override val isPseudoLocalesEnabled: Boolean + get() = buildTypeObj.isPseudoLocalesEnabled + + override val isAndroidTestCoverageEnabled: Boolean + get() = buildTypeObj.enableAndroidTestCoverage || buildTypeObj.isTestCoverageEnabled + + override val isCrunchPngs: Boolean? + get() { + return when (buildTypeObj) { + is ApplicationBuildType -> buildTypeObj.isCrunchPngs + is DynamicFeatureBuildType -> buildTypeObj.isCrunchPngs + else -> false + } + } + + override val postProcessingOptions: PostProcessingOptions by lazy { + if ((buildTypeObj as com.android.build.gradle.internal.dsl.BuildType) + .postProcessingConfiguration == + com.android.build.gradle.internal.dsl.BuildType.PostProcessingConfiguration.POSTPROCESSING_BLOCK + ) { + PostProcessingBlockOptions( + buildTypeObj.postprocessing, componentType.isTestComponent + ) + } else object : PostProcessingOptions { + override fun getProguardFiles(type: ProguardFileType): Collection<File> = + buildTypeObj.getProguardFiles(type) + + override fun getDefaultProguardFiles(): List<File> = + listOf( + ProguardFiles.getDefaultProguardFile( + ProguardFiles.ProguardFile.DONT_OPTIMIZE.fileName, + buildDirectory + ) + ) + + override fun getPostprocessingFeatures(): PostprocessingFeatures? = null + + override fun codeShrinkerEnabled() = buildTypeObj.isMinifyEnabled + + override fun resourcesShrinkingEnabled(): Boolean = buildTypeObj.isShrinkResources + + override fun hasPostProcessingConfiguration() = false + } + } + + override fun gatherProguardFiles(type: ProguardFileType): Collection<File> { + val result: MutableList<File> = ArrayList(defaultConfig.getProguardFiles(type)) + for (flavor in productFlavorList) { + result.addAll((flavor as com.android.build.gradle.internal.dsl.ProductFlavor).getProguardFiles(type)) + } + result.addAll(postProcessingOptions.getProguardFiles(type)) + return result + } + + override val isCrunchPngsDefault: Boolean + // does not exist in the new DSL + get() = (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).isCrunchPngsDefault + + // helper methods + + override fun getResValues(): Map<ResValue.Key, ResValue> { + val resValueFields = mutableMapOf<ResValue.Key, ResValue>() + + fun addToListIfNotAlreadyPresent(classField: ClassField, comment: String) { + val key = ResValueKeyImpl(classField.type, classField.name) + if (!resValueFields.containsKey(key)) { + resValueFields[key] = ResValue( + value = classField.value, + comment = comment + ) + } + } + + (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).resValues.values.forEach { classField -> + addToListIfNotAlreadyPresent(classField, "Value from build type: ${buildTypeObj.name}") + } + + productFlavorList.forEach { flavor -> + (flavor as com.android.build.gradle.internal.dsl.ProductFlavor).resValues.values.forEach { classField -> + addToListIfNotAlreadyPresent( + classField, + "Value from product flavor: ${flavor.name}" + ) + } + } + + defaultConfig.resValues.values.forEach { classField -> + addToListIfNotAlreadyPresent(classField, "Value from default config.") + } + + return resValueFields + } + + + /** + * Merge a specific option in GradleVariantConfiguration. + * + * + * It is assumed that merged option type with a method to reset and append is created for the + * option being merged. + * + * + * The order of priority is BuildType, ProductFlavors, and default config. ProductFlavor + * added earlier has higher priority than ProductFlavor added later. + * + * @param mergedOption The merged option store in the GradleVariantConfiguration. + * @param getFlavorOption A Function to return the option from a ProductFlavor. + * @param getBuildTypeOption A Function to return the option from a BuildType. + * takes priority and overwrite option in the first input argument. + * @param <CoreOptionsT> The core type of the option being merge. + * @param <MergedOptionsT> The merge option type. + </MergedOptionsT></CoreOptionsT> */ + protected fun <CoreOptionsT, MergedOptionsT : MergedOptions<CoreOptionsT>> computeMergedOptions( + mergedOption: MergedOptionsT, + getFlavorOption: VariantDimension.() -> CoreOptionsT?, + getBuildTypeOption: BuildType.() -> CoreOptionsT? + ) { + mergedOption.reset() + + val defaultOption = defaultConfig.getFlavorOption() + if (defaultOption != null) { + mergedOption.append(defaultOption) + } + // reverse loop for proper order + for (i in productFlavorList.indices.reversed()) { + val flavorOption = productFlavorList[i].getFlavorOption() + if (flavorOption != null) { + mergedOption.append(flavorOption) + } + } + val buildTypeOption = buildTypeObj.getBuildTypeOption() + if (buildTypeOption != null) { + mergedOption.append(buildTypeOption) + } + } + + private fun BaseConfig.getProguardFiles(type: ProguardFileType): Collection<File> = when (type) { + ProguardFileType.EXPLICIT -> this.proguardFiles + ProguardFileType.TEST -> this.testProguardFiles + ProguardFileType.CONSUMER -> this.consumerProguardFiles + } + + /** + * Combines all the appId suffixes into a single one. + * + * The suffixes are separated by '.' whether their first char is a '.' or not. + */ + protected fun computeApplicationIdSuffix(): String { + // for the suffix we combine the suffix from all the flavors. However, we're going to + // want the higher priority one to be last. + val suffixes = mutableListOf<String>() + defaultConfig.applicationIdSuffix?.let { + suffixes.add(it) + } + + suffixes.addAll( + productFlavorList + .asSequence() + .filterIsInstance(ApplicationProductFlavor::class.java) + .mapNotNull { it.applicationIdSuffix }) + + // then we add the build type after. + (buildTypeObj as? ApplicationBuildType)?.applicationIdSuffix?.let { + suffixes.add(it) + } + val nonEmptySuffixes = suffixes.filter { it.isNotEmpty() } + return if (nonEmptySuffixes.isNotEmpty()) { + ".${nonEmptySuffixes.joinToString(separator = ".", transform = { it.removePrefix(".") })}" + } else { + "" + } + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ConsumableComponentDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ConsumableComponentDslInfoImpl.kt new file mode 100644 index 0000000000..a45fc69beb --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/ConsumableComponentDslInfoImpl.kt @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.BuildConfigField +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.MergedOptimization +import com.android.build.gradle.internal.core.dsl.ConsumableComponentDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.OptimizationImpl +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.IntegerOption +import com.android.builder.core.ComponentType +import com.android.builder.model.ClassField +import com.google.common.collect.ImmutableList +import com.google.common.collect.Lists +import com.google.common.collect.Maps +import com.google.common.collect.Sets +import org.gradle.api.file.DirectoryProperty +import java.io.File + +internal abstract class ConsumableComponentDslInfoImpl internal constructor( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + services: VariantServices, + buildDirectory: DirectoryProperty, + oldExtension: BaseExtension?, + extension: CommonExtension<*, *, *, *> +) : ComponentDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + services, + buildDirectory, + oldExtension, + extension +), ConsumableComponentDslInfo { + + // merged options + + private val mergedOptimization = MergedOptimization() + + init { + mergeOptions() + } + + private fun mergeOptions() { + computeMergedOptions( + mergedOptimization, + { optimization as OptimizationImpl }, + { optimization as OptimizationImpl } + ) + } + + override val ignoredLibraryKeepRules: Set<String> + get() = mergedOptimization.ignoredLibraryKeepRules + + override val ignoreAllLibraryKeepRules: Boolean + get() = mergedOptimization.ignoreAllLibraryKeepRules + + // merged flavor delegates + + override val renderscriptTarget: Int + get() = mergedFlavor.renderscriptTargetApi ?: -1 + override val renderscriptSupportModeEnabled: Boolean + get() = mergedFlavor.renderscriptSupportModeEnabled ?: false + override val renderscriptSupportModeBlasEnabled: Boolean + get() { + val value = mergedFlavor.renderscriptSupportModeBlasEnabled + return value ?: false + } + override val renderscriptNdkModeEnabled: Boolean + get() = mergedFlavor.renderscriptNdkModeEnabled ?: false + + override val manifestPlaceholders: Map<String, String> by lazy { + val mergedFlavorsPlaceholders: MutableMap<String, String> = mutableMapOf() + mergedFlavor.manifestPlaceholders.forEach { (key, value) -> + mergedFlavorsPlaceholders[key] = value.toString() + } + // so far, blindly override the build type placeholders + buildTypeObj.manifestPlaceholders.forEach { (key, value) -> + mergedFlavorsPlaceholders[key] = value.toString() + } + mergedFlavorsPlaceholders + } + + // build type delegates + + // Only require specific multidex opt-in for legacy multidex. + override val isMultiDexEnabled: Boolean? + get() { + // Only require specific multidex opt-in for legacy multidex. + return (buildTypeObj as? ApplicationBuildType)?.multiDexEnabled + ?: mergedFlavor.multiDexEnabled + } + override val multiDexKeepProguard: File? + get() { + var value = buildTypeObj.multiDexKeepProguard + if (value != null) { + return value + } + value = mergedFlavor.multiDexKeepProguard + return value + } + override val multiDexKeepFile: File? + get() { + var value = buildTypeObj.multiDexKeepFile + if (value != null) { + return value + } + value = mergedFlavor.multiDexKeepFile + return value + } + + override val renderscriptOptimLevel: Int + get() = buildTypeObj.renderscriptOptimLevel + + // add the lower priority one, to override them with the higher priority ones. + // can't use merge flavor as it's not a prop on the base class. + // reverse loop for proper order + override val defaultGlslcArgs: List<String> + get() { + val optionMap: MutableMap<String, String> = + Maps.newHashMap() + // add the lower priority one, to override them with the higher priority ones. + for (option in defaultConfig.shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + // can't use merge flavor as it's not a prop on the base class. + // reverse loop for proper order + for (i in productFlavorList.indices.reversed()) { + for (option in productFlavorList[i].shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + } + // then the build type + for (option in buildTypeObj.shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + return Lists.newArrayList(optionMap.values) + } + + // first collect all possible keys. + override val scopedGlslcArgs: Map<String, List<String>> + get() { + val scopedArgs: MutableMap<String, List<String>> = + Maps.newHashMap() + // first collect all possible keys. + val keys = scopedGlslcKeys + for (key in keys) { // first add to a temp map to resolve overridden values + val optionMap: MutableMap<String, String> = + Maps.newHashMap() + // we're going to go from lower priority, to higher priority elements, and for each + // start with the non scoped version, and then add the scoped version. + // 1. default config, global. + for (option in defaultConfig.shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + // 1b. default config, scoped. + for (option in defaultConfig.shaders.scopedGlslcArgs[key]) { + optionMap[getKey(option)] = option + } + // 2. the flavors. + // can't use merge flavor as it's not a prop on the base class. + // reverse loop for proper order + for (i in productFlavorList.indices.reversed()) { // global + for (option in productFlavorList[i].shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + // scoped. + for (option in productFlavorList[i].shaders.scopedGlslcArgs[key]) { + optionMap[getKey(option)] = option + } + } + // 3. the build type, global + for (option in buildTypeObj.shaders.glslcArgs) { + optionMap[getKey(option)] = option + } + // 3b. the build type, scoped. + for (option in buildTypeObj.shaders.scopedGlslcArgs[key]) { + optionMap[getKey(option)] = option + } + // now add the full value list. + scopedArgs[key] = ImmutableList.copyOf(optionMap.values) + } + return scopedArgs + } + + // helper methods + + // TODO: move to global scope + override val targetDeployApiFromIDE: Int? = + services.projectOptions.get(IntegerOption.IDE_TARGET_DEVICE_API) + + override fun getBuildConfigFields(): Map<String, BuildConfigField<out java.io.Serializable>> { + val buildConfigFieldsMap = + mutableMapOf<String, BuildConfigField<out java.io.Serializable>>() + + fun addToListIfNotAlreadyPresent(classField: ClassField, comment: String) { + if (!buildConfigFieldsMap.containsKey(classField.name)) { + buildConfigFieldsMap[classField.name] = + BuildConfigField(classField.type , classField.value, comment) + } + } + + (buildTypeObj as com.android.build.gradle.internal.dsl.BuildType).buildConfigFields.values.forEach { classField -> + addToListIfNotAlreadyPresent(classField, "Field from build type: ${buildTypeObj.name}") + } + + for (flavor in productFlavorList) { + (flavor as com.android.build.gradle.internal.dsl.ProductFlavor).buildConfigFields.values.forEach { classField -> + addToListIfNotAlreadyPresent( + classField, + "Field from product flavor: ${flavor.name}" + ) + } + } + defaultConfig.buildConfigFields.values.forEach { classField -> + addToListIfNotAlreadyPresent(classField, "Field from default config.") + } + return buildConfigFieldsMap + } + + private val scopedGlslcKeys: Set<String> + get() { + val keys: MutableSet<String> = + Sets.newHashSet() + keys.addAll(defaultConfig.shaders.scopedGlslcArgs.keySet()) + for (flavor in productFlavorList) { + keys.addAll(flavor.shaders.scopedGlslcArgs.keySet()) + } + keys.addAll(buildTypeObj.shaders.scopedGlslcArgs.keySet()) + return keys + } + + private fun getKey(fullOption: String): String { + val pos = fullOption.lastIndexOf('=') + return if (pos == -1) { + fullOption + } else fullOption.substring(0, pos) + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoBuilder.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoBuilder.kt new file mode 100644 index 0000000000..32401db825 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoBuilder.kt @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.component.impl.ComponentIdentityImpl +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.api.DefaultAndroidSourceSet +import com.android.build.gradle.internal.core.VariantSources +import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo +import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.core.dsl.DynamicFeatureVariantDslInfo +import com.android.build.gradle.internal.core.dsl.LibraryVariantDslInfo +import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo +import com.android.build.gradle.internal.core.dsl.TestProjectVariantDslInfo +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo +import com.android.build.gradle.internal.core.dsl.UnitTestComponentDslInfo +import com.android.build.gradle.internal.dsl.ApplicationPublishingImpl +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalApplicationExtension +import com.android.build.gradle.internal.dsl.InternalDynamicFeatureExtension +import com.android.build.gradle.internal.dsl.InternalLibraryExtension +import com.android.build.gradle.internal.dsl.InternalTestExtension +import com.android.build.gradle.internal.dsl.InternalTestedExtension +import com.android.build.gradle.internal.dsl.LibraryPublishingImpl +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.DslServices +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.internal.utils.createPublishingInfoForApp +import com.android.build.gradle.internal.utils.createPublishingInfoForLibrary +import com.android.build.gradle.internal.utils.toImmutableList +import com.android.build.gradle.internal.variant.DimensionCombination +import com.android.builder.core.ComponentType +import com.android.builder.core.ComponentTypeImpl +import com.android.builder.model.SourceProvider +import org.gradle.api.file.DirectoryProperty + +/** Builder for dsl info classes. + * + * This allows setting all temporary items on the builder before actually + * instantiating the configuration, in order to keep it immutable. + * + * Use [getBuilder] as an entry point. + */ +class DslInfoBuilder<CommonExtensionT: CommonExtension<*, *, *, *>, DslInfoT: ComponentDslInfo> private constructor( + private val dimensionCombination: DimensionCombination, + val componentType: ComponentType, + private val defaultConfig: DefaultConfig, + private val defaultSourceProvider: SourceProvider, + private val buildType: BuildType, + private val buildTypeSourceProvider: SourceProvider?, + private val signingConfigOverride: SigningConfig?, + private val manifestDataProvider: ManifestDataProvider, + private val variantServices: VariantServices, + private val oldExtension: BaseExtension?, + private val extension: CommonExtensionT, + private val buildDirectory: DirectoryProperty, +) { + + companion object { + /** + * Returns a new builder + */ + @JvmStatic + fun <CommonExtensionT: CommonExtension<*, *, *, *>, DslInfoT: ComponentDslInfo> getBuilder( + dimensionCombination: DimensionCombination, + componentType: ComponentType, + defaultConfig: DefaultConfig, + defaultSourceSet: SourceProvider, + buildType: BuildType, + buildTypeSourceSet: SourceProvider?, + signingConfigOverride: SigningConfig?, + manifestDataProvider: ManifestDataProvider, + variantServices: VariantServices, + oldExtension: BaseExtension?, + extension: CommonExtensionT, + buildDirectory: DirectoryProperty, + dslServices: DslServices + ): DslInfoBuilder<CommonExtensionT, DslInfoT> { + return DslInfoBuilder( + dimensionCombination, + componentType, + defaultConfig, + defaultSourceSet, + buildType, + buildTypeSourceSet, + signingConfigOverride?.let { signingOverride -> + dslServices.newDecoratedInstance( + SigningConfig::class.java, + signingOverride.name, + dslServices + ).also { + it.initWith(signingOverride) + } + }, + manifestDataProvider, + variantServices, + oldExtension, + extension, + buildDirectory, + ) + } + } + + private lateinit var variantName: String + private lateinit var multiFlavorName: String + + val name: String + get() { + if (!::variantName.isInitialized) { + computeNames() + } + + return variantName + } + + val flavorName: String + get() { + if (!::multiFlavorName.isInitialized) { + computeNames() + } + return multiFlavorName + + } + + private val flavors = mutableListOf<Pair<ProductFlavor, SourceProvider>>() + + var variantSourceProvider: DefaultAndroidSourceSet? = null + var multiFlavorSourceProvider: DefaultAndroidSourceSet? = null + var productionVariant: TestedVariantDslInfo? = null + var inconsistentTestAppId: Boolean = false + + fun addProductFlavor( + productFlavor: ProductFlavor, + sourceProvider: SourceProvider + ) { + if (::variantName.isInitialized) { + throw RuntimeException("call to getName() before calling all addProductFlavor") + } + flavors.add(Pair(productFlavor, sourceProvider)) + } + + private fun createComponentIdentity(): ComponentIdentity = ComponentIdentityImpl( + name, + flavorName, + dimensionCombination.buildType, + dimensionCombination.productFlavors + ) + + private fun createApplicationVariantDslInfo(): ApplicationVariantDslInfo { + return ApplicationVariantDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + publishInfo = createPublishingInfoForApp( + (extension as InternalApplicationExtension).publishing as ApplicationPublishingImpl, + variantServices.projectOptions, + name, + extension.dynamicFeatures.isNotEmpty(), + variantServices.issueReporter + ), + signingConfigOverride = signingConfigOverride, + oldExtension = oldExtension, + extension = extension + ) + } + + private fun createLibraryVariantDslInfo(): LibraryVariantDslInfo { + return LibraryVariantDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + publishInfo = createPublishingInfoForLibrary( + (extension as InternalLibraryExtension).publishing as LibraryPublishingImpl, + variantServices.projectOptions, + name, + buildType, + flavors.map { it.first }, + extension.buildTypes, + extension.productFlavors, + variantServices.issueReporter + ), + oldExtension = oldExtension, + extension = extension + ) + } + + private fun createDynamicFeatureVariantDslInfo(): DynamicFeatureVariantDslInfo { + return DynamicFeatureVariantDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + oldExtension = oldExtension, + extension = extension as InternalDynamicFeatureExtension + ) + } + + private fun createTestProjectVariantDslInfo(): TestProjectVariantDslInfo { + return TestProjectVariantDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + signingConfigOverride = signingConfigOverride, + oldExtension = oldExtension, + extension = extension as InternalTestExtension + ) + } + + private fun createTestFixturesComponentDslInfo(): TestFixturesComponentDslInfo { + return TestFixturesDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + mainVariantDslInfo = productionVariant!!, + services = variantServices, + buildDirectory = buildDirectory, + oldExtension = oldExtension, + extension = extension + ) + } + + private fun createUnitTestComponentDslInfo(): UnitTestComponentDslInfo { + return UnitTestComponentDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + testedVariantDslInfo = productionVariant!!, + oldExtension = oldExtension, + extension = extension as InternalTestedExtension<*, *, *, *> + ) + } + + private fun createAndroidTestComponentDslInfo(): AndroidTestComponentDslInfo { + return AndroidTestComponentDslInfoImpl( + componentIdentity = createComponentIdentity(), + componentType = componentType, + defaultConfig = defaultConfig, + buildTypeObj = buildType, + productFlavorList = flavors.map { it.first }, + dataProvider = manifestDataProvider, + services = variantServices, + buildDirectory = buildDirectory, + testedVariantDslInfo = productionVariant!!, + inconsistentTestAppId = inconsistentTestAppId, + signingConfigOverride = signingConfigOverride, + oldExtension = oldExtension, + extension = extension as InternalTestedExtension<*, *, *, *> + ) + } + + fun createDslInfo(): DslInfoT { + return when (componentType) { + ComponentTypeImpl.BASE_APK -> createApplicationVariantDslInfo() + ComponentTypeImpl.LIBRARY -> createLibraryVariantDslInfo() + ComponentTypeImpl.OPTIONAL_APK -> createDynamicFeatureVariantDslInfo() + ComponentTypeImpl.TEST_APK -> createTestProjectVariantDslInfo() + ComponentTypeImpl.TEST_FIXTURES -> createTestFixturesComponentDslInfo() + ComponentTypeImpl.UNIT_TEST -> createUnitTestComponentDslInfo() + ComponentTypeImpl.ANDROID_TEST -> createAndroidTestComponentDslInfo() + else -> { + throw RuntimeException("Unknown component type ${componentType.name}") + } + } as DslInfoT + } + + fun createVariantSources(): VariantSources { + return VariantSources( + name, + componentType, + defaultSourceProvider, + buildTypeSourceProvider, + flavors.map { it.second }.toImmutableList(), + multiFlavorSourceProvider, + variantSourceProvider + ) + } + + /** + * computes the name for the variant and the multi-flavor combination + */ + private fun computeNames() { + variantName = computeName(dimensionCombination, componentType) { + multiFlavorName = it + } + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoCommon.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoCommon.kt new file mode 100644 index 0000000000..08250b9c3a --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoCommon.kt @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.gradle.internal.core.MergedFlavor +import com.android.build.gradle.internal.core.dsl.ApkProducingComponentDslInfo +import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.core.dsl.TestComponentDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalTestedExtension +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.BooleanOption +import com.android.builder.core.BuilderConstants +import com.android.builder.errors.IssueReporter +import org.gradle.api.provider.Provider + +internal fun TestComponentDslInfo.getTestComponentNamespace( + extension: InternalTestedExtension<*, *, *, *>, + services: VariantServices, + dataProvider: ManifestDataProvider +): Provider<String> { + return extension.testNamespace?.let { + services.provider { + if (extension.testNamespace == extension.namespace) { + services.issueReporter + .reportError( + IssueReporter.Type.GENERIC, + "namespace and testNamespace have the same value (\"$it\"), which is not allowed." + ) + } + it + } + } ?: extension.namespace?.let { services.provider {"$it.test" } } + ?: testedVariantDslInfo.namespace.flatMap { testedVariantNamespace -> + dataProvider.manifestData.map { manifestData -> + manifestData.packageName ?: "$testedVariantNamespace.test" + } + } +} + +// Special case for test components and separate test sub-projects +internal fun ComponentDslInfo.initTestApplicationId( + defaultConfig: DefaultConfig, + services: VariantServices, +): Provider<String> { + // get first non null testAppId from flavors/default config + val testAppIdFromFlavors = + productFlavorList.asSequence().map { it.testApplicationId } + .firstOrNull { it != null } + ?: defaultConfig.testApplicationId + + return if (testAppIdFromFlavors != null) { + services.provider { testAppIdFromFlavors } + } else if (this is TestComponentDslInfo) { + (this.testedVariantDslInfo as? ApkProducingComponentDslInfo)?.applicationId?.map { + "$it.test" + } ?: namespace + } else { + namespace + } +} + +internal fun ApkProducingComponentDslInfo.getSigningConfig( + buildTypeObj: BuildType, + mergedFlavor: MergedFlavor, + signingConfigOverride: SigningConfig?, + extension: CommonExtension<*, *, *, *>, + services: VariantServices +): SigningConfig? { + val dslSigningConfig = + (buildTypeObj as? ApplicationBuildType)?.signingConfig + ?: mergedFlavor.signingConfig + + signingConfigOverride?.let { + // use enableV1 and enableV2 from the DSL if the override values are null + if (it.enableV1Signing == null) { + it.enableV1Signing = dslSigningConfig?.enableV1Signing + } + if (it.enableV2Signing == null) { + it.enableV2Signing = dslSigningConfig?.enableV2Signing + } + // use enableV3 and enableV4 from the DSL because they're not injectable + it.enableV3Signing = dslSigningConfig?.enableV3Signing + it.enableV4Signing = dslSigningConfig?.enableV4Signing + return it + } + if (services.projectOptions[BooleanOption.ENABLE_DEFAULT_DEBUG_SIGNING_CONFIG] && + dslSigningConfig == null && + ((this as? ApplicationVariantDslInfo)?.isProfileable == true || isDebuggable)) { + return extension.signingConfigs.findByName(BuilderConstants.DEBUG) as SigningConfig? + } + return dslSigningConfig as SigningConfig? +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoUtils.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoUtils.kt new file mode 100644 index 0000000000..0088c05fda --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DslInfoUtils.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.gradle.internal.variant.DimensionCombination +import com.android.builder.core.ComponentType +import com.android.utils.appendCapitalized +import com.android.utils.combineAsCamelCase + +internal const val DEFAULT_TEST_RUNNER = "android.test.InstrumentationTestRunner" +internal const val MULTIDEX_TEST_RUNNER = + "com.android.test.runner.MultiDexTestRunner" +internal const val DEFAULT_HANDLE_PROFILING = false +internal const val DEFAULT_FUNCTIONAL_TEST = false + +/** + * Returns the full, unique name of the variant in camel case (starting with a lower case), + * including BuildType, Flavors and Test (if applicable). + * + * This is to be used for the normal variant name. In case of Feature plugin, the library + * side will be called the same as for library plugins, while the feature side will add + * 'feature' to the name. + * + * Also computes the flavor name if applicable + */ +@JvmOverloads +fun computeName( + dimensionCombination: DimensionCombination, + componentType: ComponentType, + flavorNameCallback: ((String) -> Unit)? = null +): String { + // compute the flavor name + val flavorName = if (dimensionCombination.productFlavors.isEmpty()) { + "" + } else { + combineAsCamelCase(dimensionCombination.productFlavors, Pair<String,String>::second) + } + flavorNameCallback?.let { it(flavorName) } + + val sb = StringBuilder() + val buildType = dimensionCombination.buildType + if (buildType == null) { + if (flavorName.isNotEmpty()) { + sb.append(flavorName) + } else if (!componentType.isTestComponent && !componentType.isTestFixturesComponent) { + sb.append("main") + } + } else { + if (flavorName.isNotEmpty()) { + sb.append(flavorName) + sb.appendCapitalized(buildType) + } else { + sb.append(buildType) + } + } + if (componentType.isNestedComponent) { + if (sb.isEmpty()) { + // need the lower case version + sb.append(componentType.prefix) + } else { + sb.append(componentType.suffix) + } + } + return sb.toString() +} + +/** + * Turns a string into a valid source set name for the given [ComponentType], e.g. + * "fooBarUnitTest" becomes "testFooBar". + */ +fun computeSourceSetName( + baseName: String, + componentType: ComponentType +): String { + var name = baseName + if (name.endsWith(componentType.suffix)) { + name = name.substring(0, name.length - componentType.suffix.length) + } + if (componentType.prefix.isNotEmpty()) { + name = componentType.prefix.appendCapitalized(name) + } + return name +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DynamicFeatureVariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DynamicFeatureVariantDslInfoImpl.kt new file mode 100644 index 0000000000..482a78a90b --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/DynamicFeatureVariantDslInfoImpl.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.DynamicFeatureVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalDynamicFeatureExtension +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.profile.ProfilingMode +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.StringOption +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty + +internal class DynamicFeatureVariantDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + oldExtension: BaseExtension?, + extension: InternalDynamicFeatureExtension +) : TestedVariantDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + dataProvider, + services, + buildDirectory, + oldExtension, + extension +), DynamicFeatureVariantDslInfo { + + // TODO: Dynamic feature variant doesn't have isDebuggable dsl in the build type, we should only + // have `debug` variants be debuggable + override val isDebuggable: Boolean + get() = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isDebuggable + ?: (buildTypeObj as? ApplicationBuildType)?.isDebuggable + ?: false + + override val signingConfig: SigningConfig? = null + override val isSigningReady: Boolean = false + override val isMultiDexSetFromDsl: Boolean + get() = (buildTypeObj as? ApplicationBuildType)?.multiDexEnabled != null +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/InstrumentedTestDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/InstrumentedTestDslInfoImpl.kt new file mode 100644 index 0000000000..1d901f42c8 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/InstrumentedTestDslInfoImpl.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ProductFlavor +import com.android.build.gradle.internal.core.dsl.InstrumentedTestComponentDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.VariantServices +import com.android.builder.dexing.DexingType +import com.android.builder.dexing.isLegacyMultiDexMode +import org.gradle.api.provider.Provider + +internal class InstrumentedTestDslInfoImpl( + private val productFlavorList: List<ProductFlavor>, + private val defaultConfig: DefaultConfig, + private val dataProvider: ManifestDataProvider, + private val services: VariantServices, + override val instrumentationRunnerArguments: Map<String, String> +): InstrumentedTestComponentDslInfo { + override fun getInstrumentationRunner(dexingType: DexingType): Provider<String> { + // first check whether the DSL has the info + val fromFlavor = + productFlavorList.asSequence().map { it.testInstrumentationRunner } + .firstOrNull { it != null } + ?: defaultConfig.testInstrumentationRunner + + if (fromFlavor != null) { + val finalFromFlavor: String = fromFlavor + return services.provider{ finalFromFlavor } + } + + // else return the value from the Manifest + return dataProvider.manifestData.map { + it.instrumentationRunner + ?: if (dexingType.isLegacyMultiDexMode()) { + MULTIDEX_TEST_RUNNER + } else { + DEFAULT_TEST_RUNNER + } + } + } + + override val handleProfiling: Provider<Boolean> + get() { + // first check whether the DSL has the info + val fromFlavor = + productFlavorList.asSequence().map { it.testHandleProfiling } + .firstOrNull { it != null } + ?: defaultConfig.testHandleProfiling + + if (fromFlavor != null) { + val finalFromFlavor: Boolean = fromFlavor + return services.provider { finalFromFlavor } + } + + // else return the value from the Manifest + return dataProvider.manifestData.map { it.handleProfiling ?: DEFAULT_HANDLE_PROFILING } + } + override val functionalTest: Provider<Boolean> + get() { + // first check whether the DSL has the info + val fromFlavor = + productFlavorList.asSequence().map { it.testFunctionalTest } + .firstOrNull { it != null } + ?: defaultConfig.testFunctionalTest + + if (fromFlavor != null) { + val finalFromFlavor: Boolean = fromFlavor + return services.provider { finalFromFlavor } + } + + // else return the value from the Manifest + return dataProvider.manifestData.map { it.functionalTest ?: DEFAULT_FUNCTIONAL_TEST } + } + override val testLabel: Provider<String?> + get() { + // there is actually no DSL value for this. + return dataProvider.manifestData.map { it.testLabel } + } +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/LibraryVariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/LibraryVariantDslInfoImpl.kt new file mode 100644 index 0000000000..2e015c0529 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/LibraryVariantDslInfoImpl.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.LibraryVariantDimension +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.MergedAarMetadata +import com.android.build.gradle.internal.core.dsl.LibraryVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalLibraryExtension +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.profile.ProfilingMode +import com.android.build.gradle.internal.publishing.VariantPublishingInfo +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.StringOption +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty + +internal class LibraryVariantDslInfoImpl internal constructor( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + override val publishInfo: VariantPublishingInfo, + oldExtension: BaseExtension?, + extension: InternalLibraryExtension +) : TestedVariantDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + dataProvider, + services, + buildDirectory, + oldExtension, + extension +), LibraryVariantDslInfo { + + override val aarMetadata = MergedAarMetadata() + + init { + mergeOptions() + } + + private fun mergeOptions() { + computeMergedOptions( + aarMetadata, + { (this as LibraryVariantDimension).aarMetadata }, + { (this as LibraryVariantDimension).aarMetadata } + ) + } + + // TODO: Library variant doesn't have isDebuggable dsl in the build type, we should only have + // `debug` variants be debuggable + override val isDebuggable: Boolean + get() = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isDebuggable + ?: (buildTypeObj as? com.android.build.gradle.internal.dsl.BuildType)?.isDebuggable + ?: false +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestFixturesDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestFixturesDslInfoImpl.kt new file mode 100644 index 0000000000..91aabdf73a --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestFixturesDslInfoImpl.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.api.variant.impl.MutableAndroidVersion +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.PublishableComponentDslInfo +import com.android.build.gradle.internal.core.dsl.TestFixturesComponentDslInfo +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.publishing.VariantPublishingInfo +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.internal.testFixtures.testFixturesFeatureName +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider + +internal class TestFixturesDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + private val mainVariantDslInfo: TestedVariantDslInfo, + services: VariantServices, + buildDirectory: DirectoryProperty, + oldExtension: BaseExtension?, + extension: CommonExtension<*, *, *, *> +) : ComponentDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + services, + buildDirectory, + oldExtension, + extension +), TestFixturesComponentDslInfo { + override val testFixturesAndroidResourcesEnabled: Boolean + get() = mainVariantDslInfo.testFixtures.androidResources + + // for test fixtures, these values are always derived from the main variant + + override val namespace: Provider<String> = + mainVariantDslInfo.namespace.map { "$it.$testFixturesFeatureName" } + override val applicationId: Property<String> = services.newPropertyBackingDeprecatedApi( + String::class.java, + namespace.map { "$it${computeApplicationIdSuffix()}" } + ) + override val minSdkVersion: MutableAndroidVersion + get() = mainVariantDslInfo.minSdkVersion + override val maxSdkVersion: Int? + get() = mainVariantDslInfo.maxSdkVersion + override val targetSdkVersion: MutableAndroidVersion? + get() = mainVariantDslInfo.targetSdkVersion + + override val publishInfo: VariantPublishingInfo + get() = (mainVariantDslInfo as PublishableComponentDslInfo).publishInfo +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestProjectVariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestProjectVariantDslInfoImpl.kt new file mode 100644 index 0000000000..083b94e0f9 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestProjectVariantDslInfoImpl.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationBuildType +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.TestProjectVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalTestExtension +import com.android.build.gradle.internal.dsl.SigningConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.profile.ProfilingMode +import com.android.build.gradle.internal.services.VariantServices +import com.android.build.gradle.options.StringOption +import com.android.build.gradle.options.Version +import com.android.builder.core.ComponentType +import com.android.builder.dexing.DexingType +import com.android.builder.errors.IssueReporter +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider + +internal class TestProjectVariantDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + private val signingConfigOverride: SigningConfig?, + oldExtension: BaseExtension?, + extension: InternalTestExtension +) : VariantDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + dataProvider, + services, + buildDirectory, + oldExtension, + extension +), TestProjectVariantDslInfo { + + override val namespace: Provider<String> by lazy { + // ------------- + // Special case for separate test sub-projects + // If there is no namespace from the DSL or package attribute in the manifest, we use + // testApplicationId, if present. This allows the test project to not have a manifest if + // all is declared in the DSL. + // TODO(b/170945282, b/172361895) Remove this special case - users should use namespace + // DSL instead of testApplicationId DSL for this... currently a warning + if (extension.namespace != null) { + services.provider { extension.namespace!! } + } else { + val testAppIdFromFlavors = + productFlavorList.asSequence().map { it.testApplicationId } + .firstOrNull { it != null } + ?: defaultConfig.testApplicationId + + dataProvider.manifestData.map { + it.packageName + ?: testAppIdFromFlavors?.also { + val message = + "Namespace not specified. Please specify a namespace for " + + "the generated R and BuildConfig classes via " + + "android.namespace in the test module's " + + "build.gradle file. Currently, this test module " + + "uses the testApplicationId " + + "($testAppIdFromFlavors) as its namespace, but " + + "version ${Version.VERSION_8_0} of the Android " + + "Gradle Plugin will require that a namespace be " + + "specified explicitly like so:\n\n" + + "android {\n" + + " namespace '$testAppIdFromFlavors'\n" + + "}\n\n" + services.issueReporter + .reportWarning(IssueReporter.Type.GENERIC, message) + } + ?: throw RuntimeException( + getMissingPackageNameErrorMessage(dataProvider.manifestLocation) + ) + } + } + } + + override val applicationId: Property<String> = + services.newPropertyBackingDeprecatedApi( + String::class.java, + initTestApplicationId(defaultConfig, services) + ) + + // TODO: Test project doesn't have isDebuggable dsl in the build type, we should only have + // `debug` variants be debuggable + override val isDebuggable: Boolean + get() = ProfilingMode.getProfilingModeType( + services.projectOptions[StringOption.PROFILING_MODE] + ).isDebuggable + ?: (buildTypeObj as? ApplicationBuildType)?.isDebuggable + ?: false + + override val signingConfig: SigningConfig? by lazy { + getSigningConfig( + buildTypeObj, + mergedFlavor, + signingConfigOverride, + extension, + services + ) + } + + override val isSigningReady: Boolean + get() = signingConfig?.isSigningReady == true + + private val instrumentedTestDelegate by lazy { + InstrumentedTestDslInfoImpl( + productFlavorList, + defaultConfig, + dataProvider, + services, + mergedFlavor.testInstrumentationRunnerArguments + ) + } + + override fun getInstrumentationRunner(dexingType: DexingType): Provider<String> { + return instrumentedTestDelegate.getInstrumentationRunner(dexingType) + } + + override val instrumentationRunnerArguments: Map<String, String> + get() = instrumentedTestDelegate.instrumentationRunnerArguments + override val handleProfiling: Provider<Boolean> + get() = instrumentedTestDelegate.handleProfiling + override val functionalTest: Provider<Boolean> + get() = instrumentedTestDelegate.functionalTest + override val testLabel: Provider<String?> + get() = instrumentedTestDelegate.testLabel +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestedVariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestedVariantDslInfoImpl.kt new file mode 100644 index 0000000000..7eab99c2f4 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/TestedVariantDslInfoImpl.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.dsl.TestFixtures +import com.android.build.api.variant.ComponentIdentity +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalTestedExtension +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.VariantServices +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty + +internal abstract class TestedVariantDslInfoImpl internal constructor( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + oldExtension: BaseExtension?, + extension: InternalTestedExtension<*, *, *, *> +) : VariantDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + dataProvider, + services, + buildDirectory, + oldExtension, + extension +), TestedVariantDslInfo { + + override val testFixtures: TestFixtures = extension.testFixtures + + override val testInstrumentationRunnerArguments: Map<String, String> + get() = mergedFlavor.testInstrumentationRunnerArguments +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/UnitTestComponentDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/UnitTestComponentDslInfoImpl.kt new file mode 100644 index 0000000000..020b3a1b68 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/UnitTestComponentDslInfoImpl.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.api.variant.impl.MutableAndroidVersion +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.core.dsl.TestedVariantDslInfo +import com.android.build.gradle.internal.core.dsl.UnitTestComponentDslInfo +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalTestedExtension +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.VariantServices +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider + +internal class UnitTestComponentDslInfoImpl( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + override val testedVariantDslInfo: TestedVariantDslInfo, + oldExtension: BaseExtension?, + extension: InternalTestedExtension<*, *, *, *> +) : ComponentDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + services, + buildDirectory, + oldExtension, + extension +), UnitTestComponentDslInfo { + + override val namespace: Provider<String> by lazy { + getTestComponentNamespace(extension, services, dataProvider) + } + + override val applicationId: Property<String> = + services.newPropertyBackingDeprecatedApi( + String::class.java, + initTestApplicationId(defaultConfig, services) + ) + + override val minSdkVersion: MutableAndroidVersion + get() = testedVariantDslInfo.minSdkVersion + override val maxSdkVersion: Int? + get() = testedVariantDslInfo.maxSdkVersion + override val targetSdkVersion: MutableAndroidVersion? + get() = testedVariantDslInfo.targetSdkVersion + + override val isUnitTestCoverageEnabled: Boolean + get() = buildTypeObj.enableUnitTestCoverage || buildTypeObj.isTestCoverageEnabled +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/VariantDslInfoImpl.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/VariantDslInfoImpl.kt new file mode 100644 index 0000000000..54a74c1055 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/core/dsl/impl/VariantDslInfoImpl.kt @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2022 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.core.dsl.impl + +import com.android.build.api.dsl.ApplicationProductFlavor +import com.android.build.api.dsl.BuildType +import com.android.build.api.dsl.CommonExtension +import com.android.build.api.dsl.Lint +import com.android.build.api.dsl.PackagingOptions +import com.android.build.api.dsl.ProductFlavor +import com.android.build.api.variant.ComponentIdentity +import com.android.build.api.variant.impl.MutableAndroidVersion +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.internal.ProguardFileType +import com.android.build.gradle.internal.core.MergedExternalNativeBuildOptions +import com.android.build.gradle.internal.core.MergedNdkConfig +import com.android.build.gradle.internal.core.NativeBuiltType +import com.android.build.gradle.internal.core.dsl.VariantDslInfo +import com.android.build.gradle.internal.cxx.configure.ninja +import com.android.build.gradle.internal.dsl.CoreExternalNativeBuildOptions +import com.android.build.gradle.internal.dsl.CoreNdkOptions +import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.services.VariantServices +import com.android.builder.core.ComponentType +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import java.io.File + +internal abstract class VariantDslInfoImpl internal constructor( + componentIdentity: ComponentIdentity, + componentType: ComponentType, + defaultConfig: DefaultConfig, + buildTypeObj: BuildType, + productFlavorList: List<ProductFlavor>, + protected val dataProvider: ManifestDataProvider, + services: VariantServices, + buildDirectory: DirectoryProperty, + oldExtension: BaseExtension?, + extension: CommonExtension<*, *, *, *> +) : ConsumableComponentDslInfoImpl( + componentIdentity, + componentType, + defaultConfig, + buildTypeObj, + productFlavorList, + services, + buildDirectory, + oldExtension, + extension +), VariantDslInfo { + + // merged options + + override val ndkConfig: MergedNdkConfig = MergedNdkConfig() + override val externalNativeBuildOptions = MergedExternalNativeBuildOptions() + + override val externalNativeExperimentalProperties: Map<String, Any> + get() { + // merge global and variant properties + val mergedProperties = mutableMapOf<String, Any>() + mergedProperties.putAll(extension.externalNativeBuild.experimentalProperties) + mergedProperties.putAll( + externalNativeBuildOptions.externalNativeExperimentalProperties + ) + return mergedProperties + } + + init { + mergeOptions() + } + + private fun mergeOptions() { + computeMergedOptions( + ndkConfig, + { ndk as CoreNdkOptions }, + { ndk as CoreNdkOptions } + ) + computeMergedOptions( + externalNativeBuildOptions, + { externalNativeBuild as CoreExternalNativeBuildOptions }, + { externalNativeBuild as CoreExternalNativeBuildOptions } + ) + } + + // merged flavor delegates + + override val minSdkVersion: MutableAndroidVersion + // if there's a testedVariant, return its value, otherwise return the merged flavor + // value. If there's no value set, then the default is just the first API Level: 1 + get() = mergedFlavor.minSdkVersion?.let { MutableAndroidVersion(it.apiLevel, it.codename) } + ?: MutableAndroidVersion(1) + override val maxSdkVersion: Int? + get() = mergedFlavor.maxSdkVersion + override val targetSdkVersion: MutableAndroidVersion? + // if there's a testedVariant, return its value, otherwise return the merged flavor + // value. If there's no value set, then return null + get() = mergedFlavor.targetSdkVersion?.let { MutableAndroidVersion(it.apiLevel, it.codename) } + + // build type delegates + + override val isJniDebuggable: Boolean + get() = buildTypeObj.isJniDebuggable + + // extension delegates + + // For main variants we get the namespace from the DSL or read it from the manifest. + override val namespace: Provider<String> by lazy { + extension.namespace?.let { services.provider { it } } + ?: dataProvider.manifestData.map { + it.packageName + ?: throw RuntimeException( + getMissingPackageNameErrorMessage(dataProvider.manifestLocation) + ) + } + } + + override val applicationId: Property<String> by lazy { + services.newPropertyBackingDeprecatedApi( + String::class.java, + initApplicationId() + ) + } + + override val nativeBuildSystem: NativeBuiltType? + get() { + if (externalNativeExperimentalProperties.ninja.path != null) return NativeBuiltType.NINJA + if (extension.externalNativeBuild.ndkBuild.path != null) return NativeBuiltType.NDK_BUILD + if (extension.externalNativeBuild.cmake.path != null) return NativeBuiltType.CMAKE + return null + } + + override val supportedAbis: Set<String> + get() = if (componentType.isDynamicFeature) setOf() else ndkConfig.abiFilters + + override fun getProguardFiles(into: ListProperty<RegularFile>) { + val result: MutableList<File> = ArrayList(gatherProguardFiles(ProguardFileType.EXPLICIT)) + if (result.isEmpty()) { + result.addAll(postProcessingOptions.getDefaultProguardFiles()) + } + + val projectDir = services.projectInfo.projectDirectory + result.forEach { file -> + into.add(projectDir.file(file.absolutePath)) + } + } + + + override val lintOptions: Lint + get() = extension.lint + override val packaging: PackagingOptions + get() = extension.packagingOptions + override val experimentalProperties: Map<String, Any> + get() = extension.experimentalProperties + + // helper methods + + private fun initApplicationId(): Provider<String> { + // get first non null appId from flavors/default config + val appIdFromFlavors = + productFlavorList + .asSequence() + .filterIsInstance(ApplicationProductFlavor::class.java) + .map { it.applicationId } + .firstOrNull { it != null } + ?: defaultConfig.applicationId + + return if (appIdFromFlavors == null) { + // No appId value set from DSL; use the namespace value from the DSL or manifest. + // using map will allow us to keep task dependency should the manifest be generated + // or transformed via a task. + namespace.map { "$it${computeApplicationIdSuffix()}" } + } else { + // use value from flavors/defaultConfig + // needed to make nullability work in kotlinc + val finalAppIdFromFlavors: String = appIdFromFlavors + services.provider { "$finalAppIdFromFlavors${computeApplicationIdSuffix()}" } + } + } + + protected fun getMissingPackageNameErrorMessage(manifestLocation: String): String = + "Package Name not found in $manifestLocation, and namespace not specified. Please " + + "specify a namespace for the generated R and BuildConfig classes via " + + "android.namespace in the module's build.gradle file like so:\n\n" + + "android {\n" + + " namespace 'com.example.namespace'\n" + + "}\n\n" +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/coverage/JacocoPropertiesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/coverage/JacocoPropertiesTask.kt index a12f867bfb..b38398e926 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/coverage/JacocoPropertiesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/coverage/JacocoPropertiesTask.kt @@ -19,10 +19,12 @@ import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.component.ConsumableCreationConfig import com.android.build.gradle.internal.pipeline.OriginalStream import com.android.build.gradle.internal.scope.InternalArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges import com.android.builder.utils.zipEntry +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskProvider @@ -43,6 +45,7 @@ import java.util.jar.JarOutputStream * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.TEST]) abstract class JacocoPropertiesTask : NonIncrementalTask() { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/ExperimentalPropertyExtensions.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/ExperimentalPropertyExtensions.kt index 696e515ba3..2783c47390 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/ExperimentalPropertyExtensions.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/configure/ExperimentalPropertyExtensions.kt @@ -121,9 +121,42 @@ private fun Map<String, Any>.propertyAsSet(name : String) : Set<String> { */ private fun Map<String, Any>.propertyAsList(name : String) : List<String> { val value = get(name) ?: return listOf() + return propertyValueAsList(value) +} + +/** + * Convert [Any] from Gradle DSL to a List<String>. + */ +private fun propertyValueAsList(value : Any) : List<String> { return when (value) { is List<*> -> value.map { "$it" } is Set<*> -> value.map { "$it" } - else -> error("${value.javaClass}") + else -> error("Could not convert from ${value.javaClass} to List<String>") + } +} + +/** + * This is the experimental flag analog of [com.android.build.api.dsl.PrefabPackagingOptions]. + */ +data class PrefabExperimentalPackagingOptions( + /** + * export_libraries may specify either literal arguments to be used as-is, intra-package + * references, or inter-package references. This field is optional. + */ + val exportLibraries : List<String>? +) + +/** + * Retrieve user's experimental settings for an individual Prefab publishing module. + */ +fun VariantCreationConfig.getPrefabExperimentalPackagingOptions(module : String) + : PrefabExperimentalPackagingOptions { + var exportLibraries : List<String>? = null + for((key, value) in externalNativeExperimentalProperties) { + if (key != "prefab.${module}.exportLibraries") continue + exportLibraries = propertyValueAsList(value) } + return PrefabExperimentalPackagingOptions( + exportLibraries = exportLibraries + ) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModel.kt index 2f90297992..4a2d77bddc 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModel.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CreateCxxAbiModel.kt @@ -88,6 +88,7 @@ fun createCxxAbiModel( }, buildSettings = createBuildSettingsFromFile(module.buildSettingsFile), fullConfigurationHash = configurationHash, + fullConfigurationHashKey = "", configurationArguments = listOf(), isActiveAbi = validAbiList.contains(abi), prefabFolder = join(variantCxxBuildFolder, "prefab", abi.tag), diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CxxAbiModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CxxAbiModel.kt index fda7ba770b..73b4f2415a 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CxxAbiModel.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/CxxAbiModel.kt @@ -99,6 +99,11 @@ data class CxxAbiModel( val fullConfigurationHash: String, /** + * The string value used to calculate [fullConfigurationHash] + */ + val fullConfigurationHashKey: String, + + /** * The inputs used to compute [fullConfigurationHash] */ val configurationArguments: List<String>, @@ -440,6 +445,13 @@ val CxxAbiModel.platformCode } ?: "" /** + * File that holds the key for the hashed subfolder. + * ex, $moduleRootFolder/.cxx/Debug/{hashcode}/hash_key.txt + */ +val CxxAbiModel.cxxBuildHashKeyFile : File get() = + cxxBuildFolder.parentFile.resolve("hash_key.txt") + +/** * Construct a ninja command-line with [args] at the end. */ fun CxxAbiModel.createNinjaCommand(args: List<String>) : List<String> { diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/JsonUtil.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/JsonUtil.kt index 77787f90d5..2513402358 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/JsonUtil.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/model/JsonUtil.kt @@ -16,7 +16,9 @@ package com.android.build.gradle.internal.cxx.model +import com.android.build.gradle.internal.cxx.io.writeTextIfDifferent import com.android.build.gradle.internal.cxx.json.PlainFileGsonTypeAdaptor +import com.android.build.gradle.internal.cxx.json.jsonStringOf import com.android.repository.Revision import com.google.gson.GsonBuilder import com.google.gson.TypeAdapter @@ -83,6 +85,8 @@ fun createCxxAbiModelFromJson(json: String): CxxAbiModel { fun CxxAbiModel.writeJsonToFile() { modelOutputFile.parentFile.mkdirs() modelOutputFile.writeText(toJsonString()) + cxxBuildHashKeyFile.parentFile.mkdirs() + cxxBuildHashKeyFile.writeTextIfDifferent(fullConfigurationHashKey) } /** diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/CreatePublicationModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/CreatePublicationModel.kt index 9230edb2fc..4dda257ecf 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/CreatePublicationModel.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/CreatePublicationModel.kt @@ -17,6 +17,7 @@ package com.android.build.gradle.internal.cxx.prefab import com.android.build.gradle.internal.component.LibraryCreationConfig +import com.android.build.gradle.internal.cxx.configure.getPrefabExperimentalPackagingOptions import com.android.build.gradle.internal.cxx.gradle.generator.CxxConfigurationModel import com.android.build.gradle.internal.cxx.logging.errorln import com.android.build.gradle.internal.cxx.model.jsonFile @@ -37,6 +38,7 @@ fun createPrefabPublication( configurationModel: CxxConfigurationModel, libraryVariant : LibraryCreationConfig ) : PrefabPublication { + val abis = configurationModel.activeAbis.map { abi -> PrefabAbiPublication( abiName = abi.abi.tag, @@ -48,12 +50,15 @@ fun createPrefabPublication( ) } val modules = libraryVariant.global.prefab.map { options -> + val experimentalSettings = libraryVariant.getPrefabExperimentalPackagingOptions(options.name) + PrefabModulePublication( moduleName = options.name, moduleLibraryName = options.libraryName, moduleHeaders = options.headers?.let { headers -> libraryVariant.services.projectInfo.projectDirectory.dir(headers).asFile.absoluteFile }, + moduleExportLibraries = experimentalSettings.exportLibraries ?: listOf(), abis = abis ) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PackageBuilder.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PackageBuilder.kt index c3d79f9d37..98acb5a911 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PackageBuilder.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PackageBuilder.kt @@ -141,7 +141,7 @@ private class PrefabPackageBuilder( writeJsonFileIfDifferent( moduleDir.resolve("module.json"), ModuleMetadataV1( - exportLibraries = emptyList(), + exportLibraries = module.moduleExportLibraries, libraryName = module.moduleLibraryName ) ) diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PublicationModel.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PublicationModel.kt index d3055f4d5a..bc21b41dd7 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PublicationModel.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/prefab/PublicationModel.kt @@ -68,6 +68,9 @@ data class PrefabModulePublication( val moduleHeaders : File?, @get:Input @get:Optional + val moduleExportLibraries : List<String>, + @get:Input + @get:Optional val moduleLibraryName : String?, @get:Nested val abis : List<PrefabAbiPublication> diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/settings/CxxAbiModelSettingsRewriter.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/settings/CxxAbiModelSettingsRewriter.kt index 6c8b0b60fd..3c2791941d 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/settings/CxxAbiModelSettingsRewriter.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/cxx/settings/CxxAbiModelSettingsRewriter.kt @@ -90,6 +90,7 @@ import com.google.common.collect.Lists import org.gradle.api.file.ProjectLayout import org.gradle.api.provider.ProviderFactory import java.io.File +import com.android.Version /** * Rewrite the CxxAbiModel in three phases: @@ -189,27 +190,78 @@ private fun CxxAbiModel.supportNdkR14AndEarlier() : CxxAbiModel { } /** - * Calculate hash and plug it into the model. + * Calculate hash and plug it into the model. Return the new model along with the text that + * was hashed. + * + * The user can pass arbitrary parameters to CMake (or ndk-build) so we can't guard against every + * case that could make the hash local-machine-specific. This is best effort, works in the default + * case, and we provide the hash_key.txt file (written later) to be able to diagnose problems. + * The consequence of a non-portable paths is that hypothetical caching tech (ccache, reclient, + * gomacc, etc) may not be able to share results. However, build results will still be accurate. */ -private fun CxxAbiModel.calculateConfigurationHash() = - copy(fullConfigurationHash = sha256Of(configurationArguments)) +private fun CxxAbiModel.calculateConfigurationHash() : CxxAbiModel { + var header = + """ + # Values used to calculate the hash in this folder name. + # Should not depend on the absolute path of the project itself. + # - AGP: ${Version.ANDROID_GRADLE_PLUGIN_VERSION}. + # - ${'$'}NDK is the path to NDK ${variant.module.ndkVersion}. + # - ${'$'}PROJECT is the path to the parent folder of the root Gradle build file. + # - ${'$'}ABI is the ABI to be built with. The specific value doesn't contribute to the value of the hash. + # - ${'$'}HASH is the hash value computed from this text. + + """.trimIndent() + + var arguments = configurationArguments.joinToString("\n") + .replace(variant.module.ndkFolder.path, "\$NDK") + .replace(variant.module.project.rootBuildGradleFolder.path, "\$PROJECT") + .replace(NDK_ABI.ref, "\$ABI") + .replace(NDK_CONFIGURATION_HASH.ref, "\$HASH") + + if (variant.module.cmake != null) { + header += """ + # - ${'$'}CMAKE is the path to CMake ${variant.module.cmake.minimumCmakeVersion}. + + """.trimIndent() + arguments = arguments.replace(variant.module.cmake.cmakeExe!!.path, "\$CMAKE") + + } + + if (variant.module.ninjaExe != null) { + header += """ + # - ${'$'}NINJA is the path to Ninja. + + """.trimIndent() + arguments = arguments.replace(variant.module.ninjaExe.path, "\$NINJA") + } + + val hashKey = header + arguments.replace("\\", "/") + + return copy( + fullConfigurationHash = sha256Of(hashKey, includeGradleVersionInHash = false), + fullConfigurationHashKey = hashKey + ) +} /** * Finally, expand all of the post-hash macros. */ -private fun CxxAbiModel.expandConfigurationHashMacros() = rewrite { _, value -> - reifyString(value) { tokenMacro -> - when(tokenMacro) { - NDK_ABI.qualifiedName, - NDK_CONFIGURATION_HASH.qualifiedName, - NDK_FULL_CONFIGURATION_HASH.qualifiedName -> { - val macro = Macro.lookup(tokenMacro) ?: error("Unrecognized macro: $tokenMacro") - resolveMacroValue(macro) +private fun CxxAbiModel.expandConfigurationHashMacros() : CxxAbiModel { + val result = rewrite { _, value -> + reifyString(value) { tokenMacro -> + when(tokenMacro) { + NDK_ABI.qualifiedName, + NDK_CONFIGURATION_HASH.qualifiedName, + NDK_FULL_CONFIGURATION_HASH.qualifiedName -> { + val macro = Macro.lookup(tokenMacro) ?: error("Unrecognized macro: $tokenMacro") + resolveMacroValue(macro) + } + else -> + error(tokenMacro) } - else -> - error(tokenMacro) } } + return result } /** diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/VariantDependenciesBuilder.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/VariantDependenciesBuilder.java index 4a89d11469..95969820ed 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/VariantDependenciesBuilder.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/VariantDependenciesBuilder.java @@ -44,7 +44,8 @@ import com.android.build.gradle.internal.api.DefaultAndroidSourceSet; import com.android.build.gradle.internal.attributes.VariantAttr; import com.android.build.gradle.internal.component.VariantCreationConfig; import com.android.build.gradle.internal.core.dsl.ComponentDslInfo; -import com.android.build.gradle.internal.core.dsl.PublishableVariantDslInfo; +import com.android.build.gradle.internal.core.dsl.PublishableComponentDslInfo; +import com.android.build.gradle.internal.core.dsl.VariantDslInfo; import com.android.build.gradle.internal.dsl.AbstractPublishing; import com.android.build.gradle.internal.dsl.ModulePropertyKeys; import com.android.build.gradle.internal.publishing.AndroidArtifacts; @@ -63,6 +64,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -424,182 +426,177 @@ public class VariantDependenciesBuilder { if (componentType.getPublishToRepository()) { VariantPublishingInfo variantPublish = - ((PublishableVariantDslInfo) dslInfo).getPublishInfo(); - if (variantPublish != null) { - // if the variant is a library, we need to make both a runtime and an API - // configurations, and they both must contain transitive dependencies - if (componentType.isAar()) { - LibraryElements aar = - factory.named( - LibraryElements.class, - AndroidArtifacts.ArtifactType.AAR.getType()); - LibraryElements jar = factory.named(LibraryElements.class, LibraryElements.JAR); - Bundling bundling = factory.named(Bundling.class, EXTERNAL); - Category library = factory.named(Category.class, Category.LIBRARY); - Category documentation = factory.named(Category.class, Category.DOCUMENTATION); - DocsType sources = factory.named(DocsType.class, DocsType.SOURCES); - DocsType javaDoc = factory.named(DocsType.class, DocsType.JAVADOC); - - for (ComponentPublishingInfo component : variantPublish.getComponents()) { - - String buildTypeAttribute = null; - Map<Attribute<ProductFlavorAttr>, ProductFlavorAttr> flavorAttributes = - Maps.newHashMap(); - if (component.getAttributesConfig() != null) { - buildTypeAttribute = component.getAttributesConfig().getBuildType(); - for (String dimensionName : - component.getAttributesConfig().getFlavorDimensions()) { - Attribute<ProductFlavorAttr> attribute = - ProductFlavorAttr.of(dimensionName); - flavorAttributes.put( - attribute, - requireNonNull(publicationFlavorMap.get(attribute))); - } + ((PublishableComponentDslInfo) dslInfo).getPublishInfo(); + // if the variant is a library, we need to make both a runtime and an API + // configurations, and they both must contain transitive dependencies + if (componentType.isAar()) { + LibraryElements aar = + factory.named( + LibraryElements.class, AndroidArtifacts.ArtifactType.AAR.getType()); + LibraryElements jar = factory.named(LibraryElements.class, LibraryElements.JAR); + Bundling bundling = factory.named(Bundling.class, EXTERNAL); + Category library = factory.named(Category.class, Category.LIBRARY); + Category documentation = factory.named(Category.class, Category.DOCUMENTATION); + DocsType sources = factory.named(DocsType.class, DocsType.SOURCES); + DocsType javaDoc = factory.named(DocsType.class, DocsType.JAVADOC); + + for (ComponentPublishingInfo component : variantPublish.getComponents()) { + + String buildTypeAttribute = null; + Map<Attribute<ProductFlavorAttr>, ProductFlavorAttr> flavorAttributes = + Maps.newHashMap(); + if (component.getAttributesConfig() != null) { + buildTypeAttribute = component.getAttributesConfig().getBuildType(); + for (String dimensionName : + component.getAttributesConfig().getFlavorDimensions()) { + Attribute<ProductFlavorAttr> attribute = + ProductFlavorAttr.of(dimensionName); + flavorAttributes.put( + attribute, requireNonNull(publicationFlavorMap.get(attribute))); } + } - String capitalizedComponentName = - StringHelper.usLocaleCapitalize(component.getComponentName()); - - Configuration apiPublication = + String capitalizedComponentName = + StringHelper.usLocaleCapitalize(component.getComponentName()); + + Configuration apiPublication = + createLibraryPublishingConfiguration( + configurations, + variantName + + "Variant" + + capitalizedComponentName + + "ApiPublication", + capitalizedComponentName + + "component API publication for " + + variantName, + apiUsage, + aar, + bundling, + library, + null, + buildTypeAttribute, + flavorAttributes); + apiPublication.setExtendsFrom(apiClasspaths); + elements.put( + new PublishedConfigSpec(API_PUBLICATION, component), apiPublication); + + Configuration runtimePublication = + createLibraryPublishingConfiguration( + configurations, + variantName + + "Variant" + + capitalizedComponentName + + "RuntimePublication", + capitalizedComponentName + + "Runtime publication for " + + variantName, + runtimeUsage, + aar, + bundling, + library, + null, + buildTypeAttribute, + flavorAttributes); + runtimePublication.extendsFrom(runtimeClasspath); + elements.put( + new PublishedConfigSpec(RUNTIME_PUBLICATION, component), + runtimePublication); + + if (component.getWithSourcesJar()) { + Configuration sourcePublication = createLibraryPublishingConfiguration( configurations, variantName + "Variant" + capitalizedComponentName - + "ApiPublication", + + "SourcePublication", capitalizedComponentName - + "component API publication for " + + "Source publication for" + variantName, - apiUsage, - aar, + runtimeUsage, + jar, bundling, - library, - null, + documentation, + sources, buildTypeAttribute, flavorAttributes); - apiPublication.setExtendsFrom(apiClasspaths); + elements.put( - new PublishedConfigSpec(API_PUBLICATION, component), - apiPublication); + new PublishedConfigSpec(SOURCE_PUBLICATION, component), + sourcePublication); + } - Configuration runtimePublication = + if (component.getWithJavadocJar()) { + Configuration javaDocPublication = createLibraryPublishingConfiguration( configurations, variantName + "Variant" + capitalizedComponentName - + "RuntimePublication", + + "JavaDocPublication", capitalizedComponentName - + "Runtime publication for " + + "JavaDoc publication for" + variantName, runtimeUsage, - aar, + jar, bundling, - library, - null, + documentation, + javaDoc, buildTypeAttribute, flavorAttributes); - runtimePublication.extendsFrom(runtimeClasspath); elements.put( - new PublishedConfigSpec(RUNTIME_PUBLICATION, component), - runtimePublication); - - if (component.getWithSourcesJar()) { - Configuration sourcePublication = - createLibraryPublishingConfiguration( - configurations, - variantName - + "Variant" - + capitalizedComponentName - + "SourcePublication", - capitalizedComponentName - + "Source publication for" - + variantName, - runtimeUsage, - jar, - bundling, - documentation, - sources, - buildTypeAttribute, - flavorAttributes); - - elements.put( - new PublishedConfigSpec(SOURCE_PUBLICATION, component), - sourcePublication); - } - - if (component.getWithJavadocJar()) { - Configuration javaDocPublication = - createLibraryPublishingConfiguration( - configurations, - variantName - + "Variant" - + capitalizedComponentName - + "JavaDocPublication", - capitalizedComponentName - + "JavaDoc publication for" - + variantName, - runtimeUsage, - jar, - bundling, - documentation, - javaDoc, - buildTypeAttribute, - flavorAttributes); - elements.put( - new PublishedConfigSpec(JAVA_DOC_PUBLICATION, component), - javaDocPublication); - } + new PublishedConfigSpec(JAVA_DOC_PUBLICATION, component), + javaDocPublication); } - } else { - // For APK, no transitive dependencies, and no api vs runtime configs. - // However we have 2 publications, one for bundle, one for Apk - for (ComponentPublishingInfo component : variantPublish.getComponents()) { - if (component.getType() == AbstractPublishing.Type.APK) { - Configuration apkPublication = - createPublishingConfig( - configurations, - variantName + "ApkPublication", - "APK publication for " + variantName, - buildType, - publicationFlavorMap, - null /*variantNameAttr*/, - null /*Usage*/, - factory.named( - LibraryElements.class, - AndroidArtifacts.ArtifactType.APK.getType()), - null); - elements.put( - new PublishedConfigSpec( - APK_PUBLICATION, component.getComponentName(), false), - apkPublication); - apkPublication.setVisible(false); - apkPublication.setCanBeConsumed(false); - } else { - assert component.getType() == AbstractPublishing.Type.AAB - : "Publication artifact type for this application project " - + "is not APK or AAB."; - - Configuration aabPublication = - createPublishingConfig( - configurations, - variantName + "AabPublication", - "Bundle Publication for " + variantName, - buildType, - publicationFlavorMap, - null /*variantNameAttr*/, - null /*Usage*/, - factory.named( - LibraryElements.class, - AndroidArtifacts.ArtifactType.BUNDLE.getType()), - null); - elements.put( - new PublishedConfigSpec( - AAB_PUBLICATION, component.getComponentName(), false), - aabPublication); - aabPublication.setVisible(false); - aabPublication.setCanBeConsumed(false); - } + } + } else { + // For APK, no transitive dependencies, and no api vs runtime configs. + // However we have 2 publications, one for bundle, one for Apk + for (ComponentPublishingInfo component : variantPublish.getComponents()) { + if (component.getType() == AbstractPublishing.Type.APK) { + Configuration apkPublication = + createPublishingConfig( + configurations, + variantName + "ApkPublication", + "APK publication for " + variantName, + buildType, + publicationFlavorMap, + null /*variantNameAttr*/, + null /*Usage*/, + factory.named( + LibraryElements.class, + AndroidArtifacts.ArtifactType.APK.getType()), + null); + elements.put( + new PublishedConfigSpec( + APK_PUBLICATION, component.getComponentName(), false), + apkPublication); + apkPublication.setVisible(false); + apkPublication.setCanBeConsumed(false); + } else { + assert component.getType() == AbstractPublishing.Type.AAB + : "Publication artifact type for this application project " + + "is not APK or AAB."; + + Configuration aabPublication = + createPublishingConfig( + configurations, + variantName + "AabPublication", + "Bundle Publication for " + variantName, + buildType, + publicationFlavorMap, + null /*variantNameAttr*/, + null /*Usage*/, + factory.named( + LibraryElements.class, + AndroidArtifacts.ArtifactType.BUNDLE.getType()), + null); + elements.put( + new PublishedConfigSpec( + AAB_PUBLICATION, component.getComponentName(), false), + aabPublication); + aabPublication.setVisible(false); + aabPublication.setCanBeConsumed(false); } } } @@ -674,9 +671,16 @@ public class VariantDependenciesBuilder { configuration.getOutgoing().capability(capability)); } + Map<String, Object> experimentalProperties; + + if (dslInfo instanceof VariantDslInfo) { + experimentalProperties = ((VariantDslInfo) dslInfo).getExperimentalProperties(); + } else { + experimentalProperties = Collections.emptyMap(); + } + boolean isSelfInstrumenting = - ModulePropertyKeys.SELF_INSTRUMENTING.getValueAsBoolean( - dslInfo.getExperimentalProperties()); + ModulePropertyKeys.SELF_INSTRUMENTING.getValueAsBoolean(experimentalProperties); return new VariantDependencies( variantName, dslInfo.getComponentType(), diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalApplicationExtension.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalApplicationExtension.kt index cb5a22ecd2..49d8d1c237 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalApplicationExtension.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalApplicationExtension.kt @@ -29,8 +29,7 @@ import org.gradle.api.Action /** See [InternalCommonExtension] */ interface InternalApplicationExtension : ApplicationExtension, - InternalTestedExtension, - InternalCommonExtension< + InternalTestedExtension< ApplicationBuildFeatures, ApplicationBuildType, ApplicationDefaultConfig, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalDynamicFeatureExtension.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalDynamicFeatureExtension.kt index 12ada143b2..ac038f2380 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalDynamicFeatureExtension.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalDynamicFeatureExtension.kt @@ -25,8 +25,7 @@ import com.android.build.api.dsl.DynamicFeatureProductFlavor /** See [InternalCommonExtension] */ interface InternalDynamicFeatureExtension : DynamicFeatureExtension, - InternalTestedExtension, - InternalCommonExtension< + InternalTestedExtension< DynamicFeatureBuildFeatures, DynamicFeatureBuildType, DynamicFeatureDefaultConfig, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalLibraryExtension.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalLibraryExtension.kt index 38f7bbe2b9..e4a04de779 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalLibraryExtension.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalLibraryExtension.kt @@ -27,8 +27,7 @@ import org.gradle.api.Action /** See [InternalCommonExtension] */ interface InternalLibraryExtension : LibraryExtension, - InternalTestedExtension, - InternalCommonExtension< + InternalTestedExtension< LibraryBuildFeatures, LibraryBuildType, LibraryDefaultConfig, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalTestedExtension.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalTestedExtension.kt index a63005a365..1c8ea263b2 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalTestedExtension.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dsl/InternalTestedExtension.kt @@ -21,6 +21,11 @@ import com.android.build.api.dsl.TestedExtension import org.gradle.api.Action /** See [InternalCommonExtension] */ -interface InternalTestedExtension: TestedExtension { +interface InternalTestedExtension<BuildFeaturesT : com.android.build.api.dsl.BuildFeatures, + BuildTypeT : com.android.build.api.dsl.BuildType, + DefaultConfigT : com.android.build.api.dsl.DefaultConfig, + ProductFlavorT : com.android.build.api.dsl.ProductFlavor> + : TestedExtension, + InternalCommonExtension<BuildFeaturesT, BuildTypeT, DefaultConfigT, ProductFlavorT> { fun testFixtures(action: Action<TestFixtures>) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt index 7dd0a54551..d0b2db1889 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/feature/BundleAllClasses.kt @@ -24,9 +24,11 @@ import com.android.build.gradle.internal.packaging.JarCreatorType import com.android.build.gradle.internal.profile.ProfileAwareWorkAction import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.utils.fromDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileVisitDetails import org.gradle.api.file.RegularFileProperty @@ -54,6 +56,7 @@ import java.util.zip.Deflater * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class BundleAllClasses : NonIncrementalTask() { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt new file mode 100644 index 0000000000..c7d5659334 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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.fusedlibrary + +import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl +import com.android.build.api.attributes.BuildTypeAttr +import com.android.build.gradle.internal.DependencyConfigurator +import com.android.build.gradle.internal.SdkComponentsBuildService +import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.services.DslServices +import com.android.build.gradle.internal.services.DslServicesImpl +import com.android.build.gradle.internal.services.ProjectServices +import com.android.build.gradle.internal.tasks.factory.TaskCreationAction +import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.component.ComponentIdentifier +import org.gradle.api.attributes.Usage +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.Provider +import org.gradle.api.specs.Spec + +fun createTasks( + project: Project, + artifacts: ArtifactsImpl, + artifactForPublication: Artifact.Single<RegularFile>, + tasksCreationActions: List<TaskCreationAction<out DefaultTask>> +) { + val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> + tasksCreationActions.map { creationAction -> + taskFactory.register(creationAction) + } + } + + // create anchor tasks + project.tasks.register("assemble") { assembleTask -> + artifactForPublication?.let { artifactTypeForPublication -> + assembleTask.dependsOn(artifacts.get(artifactTypeForPublication)) + } ?: taskProviders.forEach { assembleTask.dependsOn(it) } + } +} + +fun configureTransforms(project: Project, projectServices: ProjectServices) { + DependencyConfigurator(project, projectServices) + .configureGeneralTransforms(namespacedAndroidResources = false) +} + +fun getDslServices(project: Project, projectServices: ProjectServices): DslServices { + val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = + SdkComponentsBuildService.RegistrationAction( + project, + projectServices.projectOptions + ).execute() + + return DslServicesImpl(projectServices, sdkComponentsBuildService) +} + diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/SourceProviderImpl.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/SourceProviderImpl.java index f9a7e593ec..2d6bb94aa3 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/SourceProviderImpl.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/SourceProviderImpl.java @@ -87,7 +87,7 @@ final class SourceProviderImpl implements SourceProvider, Serializable { this.manifestFile = sourceProvider.getManifestFile(); this.javaDirs = getSourcesForIdeModel(variantSources.getJava()); this.kotlinDirs = getSourcesForIdeModel(variantSources.getKotlin()); - this.resourcesDirs = sourceProvider.getResourcesDirectories(); + this.resourcesDirs = getSourcesForIdeModel(variantSources.getResources()); this.aidlDirs = sourceProvider.getAidlDirectories(); this.rsDirs = sourceProvider.getRenderscriptDirectories(); this.resDirs = diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/Converters.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/Converters.kt index 5831ad78d4..37b6726884 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/Converters.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/ide/v2/Converters.kt @@ -213,7 +213,7 @@ internal fun DefaultAndroidSourceSet.convert( manifestFile = manifestFile, javaDirectories = variantSourcesForModel(sources.java), kotlinDirectories = variantSourcesForModel(sources.kotlin), - resourcesDirectories = resourcesDirectories, + resourcesDirectories = variantSourcesForModel(sources.resources), aidlDirectories = if (features.aidl) aidlDirectories else null, renderscriptDirectories = if (features.renderScript) renderscriptDirectories else null, resDirectories = if (features.androidResources) variantSourcesForModel(sources.res) else null, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintAnalysisTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintAnalysisTask.kt index 2c530bb721..c52445c2ad 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintAnalysisTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintAnalysisTask.kt @@ -26,6 +26,7 @@ import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.services.TaskCreationServices import com.android.build.gradle.internal.services.getBuildService +import com.android.build.gradle.internal.services.getLintParallelBuildService import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction @@ -354,6 +355,9 @@ abstract class AndroidLintAnalysisTask : NonIncrementalTask() { } systemPropertyInputs.initialize(project.providers, LintMode.ANALYSIS) environmentVariableInputs.initialize(project.providers, LintMode.ANALYSIS) + this.usesService( + services.buildServiceRegistry.getLintParallelBuildService(services.projectOptions) + ) } fun configureForStandalone( diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt index 7fc3007e13..e2d9cb5ec4 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/lint/AndroidLintInputs.kt @@ -42,6 +42,7 @@ import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.scope.ProjectInfo import com.android.build.gradle.internal.services.LintClassLoaderBuildService +import com.android.build.gradle.internal.services.LintParallelBuildService import com.android.build.gradle.internal.services.TaskCreationServices import com.android.build.gradle.internal.services.getBuildService import com.android.build.gradle.internal.utils.fromDisallowChanges @@ -255,7 +256,10 @@ abstract class LintTool { // Default to using the main Gradle daemon heap size to smooth the transition // for build authors. it.forkOptions.maxHeapSize = - workerHeapSize.orNull ?: "${Runtime.getRuntime().maxMemory() / 1024 / 1024}m" + LintParallelBuildService.calculateLintHeapSize( + workerHeapSize.orNull, + Runtime.getRuntime().maxMemory() + ) } } workQueue.submit(AndroidLintWorkAction::class.java) { parameters -> diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt deleted file mode 100644 index 88a62d7070..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2022 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.plugins - -import com.android.build.api.artifact.Artifact -import com.android.build.api.attributes.BuildTypeAttr -import com.android.build.gradle.internal.DependencyConfigurator -import com.android.build.gradle.internal.SdkComponentsBuildService -import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope -import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler -import com.android.build.gradle.internal.publishing.AndroidArtifacts -import com.android.build.gradle.internal.services.Aapt2DaemonBuildService -import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService -import com.android.build.gradle.internal.services.DslServicesImpl -import com.android.build.gradle.internal.tasks.factory.TaskCreationAction -import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl -import com.google.wireless.android.sdk.stats.GradleBuildProfileSpan -import groovy.namespace.QName -import groovy.util.Node -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.component.LibraryBinaryIdentifier -import org.gradle.api.artifacts.component.ModuleComponentIdentifier -import org.gradle.api.artifacts.component.ProjectComponentIdentifier -import org.gradle.api.attributes.Usage -import org.gradle.api.component.SoftwareComponentFactory -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider -import org.gradle.api.publish.maven.MavenPom -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.build.event.BuildEventsListenerRegistry -import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier - -abstract class AbstractFusedLibraryPlugin ( - protected val softwareComponentFactory: SoftwareComponentFactory, - listenerRegistry: BuildEventsListenerRegistry, -): AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - - val dslServices by lazy { - withProject("dslServices") { project -> - val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = - SdkComponentsBuildService.RegistrationAction( - project, - projectServices.projectOptions - ).execute() - - DslServicesImpl( - projectServices, - sdkComponentsBuildService - ) - } - } - - abstract val variantScope: FusedLibraryVariantScope - - internal fun createTasks( - project: Project, - variantScope: FusedLibraryVariantScope, - tasksCreationActions: List<TaskCreationAction<out DefaultTask>>, - ) { - configureTransforms(project) - val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> - tasksCreationActions.map { creationAction -> - taskFactory.register(creationAction) - } - } - - // create anchor tasks - project.tasks.register("assemble") { assembleTask -> - artifactForPublication?.let { artifactTypeForPublication -> - assembleTask.dependsOn(variantScope.artifacts.get(artifactTypeForPublication)) - } ?: taskProviders.forEach { assembleTask.dependsOn(it) } - } - } - - /** - * Returns the artifact type that will be used for maven publication or null if nothing is to - * be published to maven. - */ - abstract val artifactForPublication: Artifact.Single<RegularFile>? - - abstract val artifactTypeForPublication: AndroidArtifacts.ArtifactType - - override fun apply(project: Project) { - super.basePluginApply(project) - - // so far by default, we consume and publish only 'debug' variant - - // 'include' is the configuration that users will use to indicate which dependencies should - // be fused. - val includeConfigurations = project.configurations.create("include").also { - it.isCanBeConsumed = false - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive - // dependencies that are implementation() scoped will not be included. - val includeApiClasspath = project.configurations.create("includeApiClasspath").also { - it.isCanBeConsumed = false - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeApiClasspath) - - // This is the configuration that will contain all the JAVA_API dependencies that are not - // fused in the resulting aar library. - val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { - it.isCanBeConsumed = true - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeApiClasspath, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive - // dependencies that are implementation() scoped will be included. - val includeRuntimeClasspath = project.configurations.create("includeRuntimeClasspath").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeRuntimeClasspath) - - // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are - // not fused in the resulting aar library. - val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeConfigurations, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // we are only interested in the last provider in the chain of transformers for this bundle. - // Obviously, this is theoretical at this point since there is no variant API to replace - // artifacts, there is always only one. - val bundleTaskProvider = artifactForPublication?.let { - variantScope - .artifacts - .getArtifactContainer(it) - .getTaskProviders() - .last() - } - - // this is the outgoing configuration for JAVA_API scoped declarations, it will contain - // this module and all transitive non merged dependencies - - fun configureApiRuntimeElements(elements: Configuration) { - elements.isCanBeResolved = false - elements.isCanBeConsumed = true - elements.isTransitive = true - - if (bundleTaskProvider != null) { - elements.outgoing.variants { variants -> - variants.create(artifactTypeForPublication.type) {variant -> - variant.artifact(bundleTaskProvider) { artifact -> - artifact.type = artifactTypeForPublication.type - } - } - } - } - } - - val includeApiElements = project.configurations.create("apiElements") { apiElements -> - configureApiRuntimeElements(apiElements) - apiElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - apiElements.extendsFrom(includedApiUnmerged) - } - - // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain - // this module and all transitive non merged dependencies - val includeRuntimeElements = project.configurations.create("runtimeElements") { runtimeElements -> - configureApiRuntimeElements(runtimeElements) - runtimeElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - runtimeElements.extendsFrom(includeRuntimeUnmerged) - } - - maybePublishToMaven( - project, - includeApiElements, - includeRuntimeElements, - includeRuntimeUnmerged - ) - } - - override fun configureProject(project: Project) { - val projectOptions = projectServices.projectOptions - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() - } - - protected abstract fun maybePublishToMaven( - project: Project, - includeApiElements: Configuration, - includeRuntimeElements: Configuration, - includeRuntimeUnmerged: Configuration - ) - - fun component( - publication: MavenPublication, - unmergedArtifacts: ArtifactCollection, - ) { - - publication.pom { pom: MavenPom -> - pom.withXml { xml -> - val dependenciesNode = xml.asNode().let { - it.children().firstOrNull { node -> - ((node as Node).name() as QName).qualifiedName == "dependencies" - } ?: it.appendNode("dependencies") - } as Node - - unmergedArtifacts.forEach { artifact -> - if (artifact.id is ModuleComponentArtifactIdentifier) { - when (val moduleIdentifier = artifact.id.componentIdentifier) { - is ModuleComponentIdentifier -> { - val dependencyNode = dependenciesNode.appendNode("dependency") - dependencyNode.appendNode("groupId", moduleIdentifier.group) - dependencyNode.appendNode("artifactId", moduleIdentifier.module) - dependencyNode.appendNode("version", moduleIdentifier.version) - dependencyNode.appendNode("scope", "runtime") - } - is ProjectComponentIdentifier -> println("Project : ${moduleIdentifier.projectPath}") - is LibraryBinaryIdentifier -> println("Library : ${moduleIdentifier.projectPath}") - else -> println("Unknown dependency ${moduleIdentifier.javaClass} : $artifact") - } - } else { - println("Unknown module ${artifact.id.javaClass} : ${artifact.id}") - } - } - } - } - } - - fun configureTransforms(project: Project) { - configuratorService.recordBlock( - GradleBuildProfileSpan.ExecutionType.ARTIFACT_TRANSFORM, - project.path, - null - ) { - DependencyConfigurator(project, projectServices) - .configureGeneralTransforms(namespacedAndroidResources = false) - } - } -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt deleted file mode 100644 index eb252ab2d4..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2022 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.plugins - -import com.android.build.api.artifact.Artifact -import com.android.build.api.attributes.BuildTypeAttr -import com.android.build.gradle.internal.DependencyConfigurator -import com.android.build.gradle.internal.SdkComponentsBuildService -import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope -import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler -import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope -import com.android.build.gradle.internal.publishing.AndroidArtifacts -import com.android.build.gradle.internal.services.Aapt2DaemonBuildService -import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService -import com.android.build.gradle.internal.services.DslServicesImpl -import com.android.build.gradle.internal.tasks.factory.TaskCreationAction -import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl -import com.google.wireless.android.sdk.stats.GradleBuildProfileSpan -import groovy.namespace.QName -import groovy.util.Node -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.component.LibraryBinaryIdentifier -import org.gradle.api.artifacts.component.ModuleComponentIdentifier -import org.gradle.api.artifacts.component.ProjectComponentIdentifier -import org.gradle.api.attributes.Usage -import org.gradle.api.component.SoftwareComponentFactory -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider -import org.gradle.api.publish.maven.MavenPom -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.build.event.BuildEventsListenerRegistry -import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier - -abstract class AbstractPrivacySandboxPlugin( - listenerRegistry: BuildEventsListenerRegistry, -): AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - - val dslServices by lazy { - withProject("dslServices") { project -> - val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = - SdkComponentsBuildService.RegistrationAction( - project, - projectServices.projectOptions - ).execute() - - DslServicesImpl( - projectServices, - sdkComponentsBuildService - ) - } - } - - abstract val variantScope: PrivacySandboxSdkVariantScope - - internal fun createTasks( - project: Project, - variantScope: PrivacySandboxSdkVariantScope, - tasksCreationActions: List<TaskCreationAction<out DefaultTask>>, - ) { - configureTransforms(project) - val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> - tasksCreationActions.map { creationAction -> - taskFactory.register(creationAction) - } - } - - // create anchor tasks - project.tasks.register("assemble") { assembleTask -> - artifactForPublication?.let { artifactTypeForPublication -> - assembleTask.dependsOn(variantScope.artifacts.get(artifactTypeForPublication)) - } ?: taskProviders.forEach { assembleTask.dependsOn(it) } - } - } - - /** - * Returns the artifact type that will be used for maven publication or null if nothing is to - * be published to maven. - */ - internal abstract val artifactForPublication: Artifact.Single<RegularFile>? - - internal abstract val artifactTypeForPublication: AndroidArtifacts.ArtifactType - - override fun apply(project: Project) { - super.basePluginApply(project) - - // so far by default, we consume and publish only 'debug' variant - - // 'include' is the configuration that users will use to indicate which dependencies should - // be fused. - val includeConfigurations = project.configurations.create("include").also { - it.isCanBeConsumed = false - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive - // dependencies that are implementation() scoped will not be included. - val includeApiClasspath = project.configurations.create("includeApiClasspath").also { - it.isCanBeConsumed = false - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeApiClasspath) - - // This is the configuration that will contain all the JAVA_API dependencies that are not - // fused in the resulting aar library. - val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { - it.isCanBeConsumed = true - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeApiClasspath, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive - // dependencies that are implementation() scoped will be included. - val includeRuntimeClasspath = project.configurations.create("includeRuntimeClasspath").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeRuntimeClasspath) - - // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are - // not fused in the resulting aar library. - val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeConfigurations, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // we are only interested in the last provider in the chain of transformers for this bundle. - // Obviously, this is theoretical at this point since there is no variant API to replace - // artifacts, there is always only one. - val bundleTaskProvider = artifactForPublication?.let { - variantScope - .artifacts - .getArtifactContainer(it) - .getTaskProviders() - .last() - } - - // this is the outgoing configuration for JAVA_API scoped declarations, it will contain - // this module and all transitive non merged dependencies - - fun configureApiRuntimeElements(elements: Configuration) { - elements.isCanBeResolved = false - elements.isCanBeConsumed = true - elements.isTransitive = true - - if (bundleTaskProvider != null) { - elements.outgoing.variants { variants -> - variants.create(artifactTypeForPublication.type) {variant -> - variant.artifact(bundleTaskProvider) { artifact -> - artifact.type = artifactTypeForPublication.type - } - } - } - } - } - - val includeApiElements = project.configurations.create("apiElements") { apiElements -> - configureApiRuntimeElements(apiElements) - apiElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - } - - // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain - // this module and all transitive non merged dependencies - val includeRuntimeElements = project.configurations.create("runtimeElements") { runtimeElements -> - configureApiRuntimeElements(runtimeElements) - runtimeElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - } - } - - override fun configureProject(project: Project) { - val projectOptions = projectServices.projectOptions - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() - } - - private fun configureTransforms(project: Project) { - configuratorService.recordBlock( - GradleBuildProfileSpan.ExecutionType.ARTIFACT_TRANSFORM, - project.path, - null - ) { - DependencyConfigurator(project, projectServices) - .configureGeneralTransforms(namespacedAndroidResources = false) - } - } -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt index 560172ad3e..a98dc55c71 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt @@ -17,23 +17,37 @@ package com.android.build.gradle.internal.plugins import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl import com.android.build.api.attributes.BuildTypeAttr import com.android.build.api.dsl.FusedLibraryExtension import com.android.build.gradle.internal.dsl.FusedLibraryExtensionImpl import com.android.build.gradle.internal.fusedlibrary.FusedLibraryInternalArtifactType +import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScopeImpl +import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler +import com.android.build.gradle.internal.fusedlibrary.configureTransforms +import com.android.build.gradle.internal.fusedlibrary.createTasks +import com.android.build.gradle.internal.fusedlibrary.getDslServices import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.internal.tasks.MergeJavaResourceTask import com.android.build.gradle.tasks.FusedLibraryBundleAar import com.android.build.gradle.tasks.FusedLibraryBundleClasses -import com.android.build.gradle.tasks.FusedLibraryMergeClasses import com.android.build.gradle.tasks.FusedLibraryClassesRewriteTask import com.android.build.gradle.tasks.FusedLibraryManifestMergerTask import com.android.build.gradle.tasks.FusedLibraryMergeArtifactTask +import com.android.build.gradle.tasks.FusedLibraryMergeClasses import com.android.build.gradle.tasks.FusedLibraryMergeResourcesTask import com.google.wireless.android.sdk.stats.GradleBuildProject +import groovy.namespace.QName +import groovy.util.Node +import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.ArtifactCollection import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.component.LibraryBinaryIdentifier +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.attributes.Bundling import org.gradle.api.attributes.Category import org.gradle.api.attributes.LibraryElements @@ -41,18 +55,25 @@ import org.gradle.api.attributes.Usage import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.file.RegularFile import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPom import org.gradle.api.publish.maven.MavenPublication import org.gradle.build.event.BuildEventsListenerRegistry +import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier import javax.inject.Inject @Suppress("UnstableApiUsage") class FusedLibraryPlugin @Inject constructor( - softwareComponentFactory: SoftwareComponentFactory, - listenerRegistry: BuildEventsListenerRegistry, -): AbstractFusedLibraryPlugin(softwareComponentFactory, listenerRegistry) { + private val softwareComponentFactory: SoftwareComponentFactory, + listenerRegistry: BuildEventsListenerRegistry, +) : AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { + + val dslServices: DslServices by lazy(LazyThreadSafetyMode.NONE) { + withProject("dslServices") { project -> + getDslServices(project, projectServices) + } + } - // so far, there is only one variant. - override val variantScope by lazy { + private val variantScope: FusedLibraryVariantScope by lazy(LazyThreadSafetyMode.NONE) { withProject("variantScope") { project -> FusedLibraryVariantScopeImpl( project @@ -60,45 +81,48 @@ class FusedLibraryPlugin @Inject constructor( } } - private val extension: FusedLibraryExtension by lazy { + private val extension: FusedLibraryExtension by lazy(LazyThreadSafetyMode.NONE) { withProject("extension") { project -> instantiateExtension(project) } } + override fun configureProject(project: Project) { + } + override fun configureExtension(project: Project) { extension } private fun instantiateExtension(project: Project): FusedLibraryExtension { - val fusedLibraryExtensionImpl= dslServices.newDecoratedInstance( - FusedLibraryExtensionImpl::class.java, - dslServices, + val fusedLibraryExtensionImpl = dslServices.newDecoratedInstance( + FusedLibraryExtensionImpl::class.java, + dslServices, ) abstract class Extension( - val publicExtensionImpl: FusedLibraryExtensionImpl, + val publicExtensionImpl: FusedLibraryExtensionImpl, ): FusedLibraryExtension by publicExtensionImpl return project.extensions.create( - FusedLibraryExtension::class.java, - "android", - Extension::class.java, - fusedLibraryExtensionImpl + FusedLibraryExtension::class.java, + "android", + Extension::class.java, + fusedLibraryExtensionImpl ) } - override fun maybePublishToMaven( - project: Project, - includeApiElements: Configuration, - includeRuntimeElements: Configuration, - includeRuntimeUnmerged: Configuration + private fun maybePublishToMaven( + project: Project, + includeApiElements: Configuration, + includeRuntimeElements: Configuration, + includeRuntimeUnmerged: Configuration ) { val bundleTaskProvider = variantScope .artifacts - .getArtifactContainer(artifactForPublication) + .getArtifactContainer(FusedLibraryInternalArtifactType.BUNDLED_LIBRARY) .getTaskProviders() .last() @@ -107,27 +131,27 @@ class FusedLibraryPlugin @Inject constructor( it.isCanBeResolved = false it.isVisible = false it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) ) it.attributes.attribute( - Bundling.BUNDLING_ATTRIBUTE, - project.objects.named(Bundling::class.java, Bundling.EXTERNAL) + Bundling.BUNDLING_ATTRIBUTE, + project.objects.named(Bundling::class.java, Bundling.EXTERNAL) ) it.attributes.attribute( - Category.CATEGORY_ATTRIBUTE, - project.objects.named(Category::class.java, Category.LIBRARY) + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category::class.java, Category.LIBRARY) ) it.attributes.attribute( - LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - project.objects.named( - LibraryElements::class.java, - AndroidArtifacts.ArtifactType.AAR.type - ) + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + project.objects.named( + LibraryElements::class.java, + AndroidArtifacts.ArtifactType.AAR.type + ) ) it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - project.objects.named(BuildTypeAttr::class.java, "debug") + BuildTypeAttr.ATTRIBUTE, + project.objects.named(BuildTypeAttr::class.java, "debug") ) it.extendsFrom(includeApiElements) variantScope.outgoingConfigurations.addConfiguration(it) @@ -141,27 +165,27 @@ class FusedLibraryPlugin @Inject constructor( it.isCanBeResolved = false it.isVisible = false it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) ) it.attributes.attribute( - Bundling.BUNDLING_ATTRIBUTE, - project.objects.named(Bundling::class.java, Bundling.EXTERNAL) + Bundling.BUNDLING_ATTRIBUTE, + project.objects.named(Bundling::class.java, Bundling.EXTERNAL) ) it.attributes.attribute( - Category.CATEGORY_ATTRIBUTE, - project.objects.named(Category::class.java, Category.LIBRARY) + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category::class.java, Category.LIBRARY) ) it.attributes.attribute( - LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - project.objects.named( - LibraryElements::class.java, - AndroidArtifacts.ArtifactType.AAR.type - ) + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + project.objects.named( + LibraryElements::class.java, + AndroidArtifacts.ArtifactType.AAR.type + ) ) it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - project.objects.named(BuildTypeAttr::class.java, "debug") + BuildTypeAttr.ATTRIBUTE, + project.objects.named(BuildTypeAttr::class.java, "debug") ) it.extendsFrom(includeRuntimeElements) variantScope.outgoingConfigurations.addConfiguration(it) @@ -185,19 +209,52 @@ class FusedLibraryPlugin @Inject constructor( project.afterEvaluate { project.extensions.findByType(PublishingExtension::class.java)?.also { component( - it.publications.create("maven", MavenPublication::class.java) - .also { mavenPublication -> - mavenPublication.from(adhocComponent) - }, includeRuntimeUnmerged.incoming.artifacts + it.publications.create("maven", MavenPublication::class.java) + .also { mavenPublication -> + mavenPublication.from(adhocComponent) + }, includeRuntimeUnmerged.incoming.artifacts ) } } } + fun component(publication: MavenPublication, unmergedArtifacts: ArtifactCollection) { + publication.pom { pom: MavenPom -> + pom.withXml { xml -> + val dependenciesNode = xml.asNode().let { + it.children().firstOrNull { node -> + ((node as Node).name() as QName).qualifiedName == "dependencies" + } ?: it.appendNode("dependencies") + } as Node + + unmergedArtifacts.forEach { artifact -> + if (artifact.id is ModuleComponentArtifactIdentifier) { + when (val moduleIdentifier = artifact.id.componentIdentifier) { + is ModuleComponentIdentifier -> { + val dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", moduleIdentifier.group) + dependencyNode.appendNode("artifactId", moduleIdentifier.module) + dependencyNode.appendNode("version", moduleIdentifier.version) + dependencyNode.appendNode("scope", "runtime") + } + is ProjectComponentIdentifier -> println("Project : ${moduleIdentifier.projectPath}") + is LibraryBinaryIdentifier -> println("Library : ${moduleIdentifier.projectPath}") + else -> println("Unknown dependency ${moduleIdentifier.javaClass} : $artifact") + } + } else { + println("Unknown module ${artifact.id.javaClass} : ${artifact.id}") + } + } + } + } + } + override fun createTasks(project: Project) { + configureTransforms(project, projectServices) createTasks( project, - variantScope, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, listOf( FusedLibraryClassesRewriteTask.CreationAction(variantScope), FusedLibraryManifestMergerTask.CreationAction(variantScope), @@ -210,12 +267,157 @@ class FusedLibraryPlugin @Inject constructor( ) } - override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = - GradleBuildProject.PluginType.FUSED_LIBRARIES + override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = + GradleBuildProject.PluginType.FUSED_LIBRARIES + + override fun apply(project: Project) { + super.basePluginApply(project) + + // so far by default, we consume and publish only 'debug' variant + + // 'include' is the configuration that users will use to indicate which dependencies should + // be fused. + val includeConfigurations = project.configurations.create("include").also { + it.isCanBeConsumed = false + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive + // dependencies that are implementation() scoped will not be included. + val includeApiClasspath = project.configurations.create("includeApiClasspath").also { + it.isCanBeConsumed = false + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) + ) + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_API dependencies that are not + // fused in the resulting aar library. + val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { + it.isCanBeConsumed = true + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeApiClasspath, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive + // dependencies that are implementation() scoped will be included. + val includeRuntimeClasspath = + project.configurations.create("includeRuntimeClasspath").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + ) + val buildType: BuildTypeAttr = + project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are + // not fused in the resulting aar library. + val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeConfigurations, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // this is the outgoing configuration for JAVA_API scoped declarations, it will contain + // this module and all transitive non merged dependencies + fun configureElements( + elements: Configuration, + usage: String, + artifacts: ArtifactsImpl, + publicationArtifact: Artifact.Single<RegularFile>, + publicationArtifactType: AndroidArtifacts.ArtifactType + ) { + // we are only interested in the last provider in the chain of transformers for this bundle. + // Obviously, this is theoretical at this point since there is no variant API to replace + // artifacts, there is always only one. + val bundleTaskProvider = publicationArtifact.let { + artifacts + .getArtifactContainer(it) + .getTaskProviders() + .last() + } + elements.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, usage) + ) + elements.isCanBeResolved = false + elements.isCanBeConsumed = true + elements.isTransitive = true + + elements.outgoing.variants { variants -> + variants.create(publicationArtifactType.type) { variant -> + variant.artifact(bundleTaskProvider) { artifact -> + artifact.type = publicationArtifactType.type + } + } + } + } - override val artifactForPublication: Artifact.Single<RegularFile> - get() = FusedLibraryInternalArtifactType.BUNDLED_LIBRARY + val includeApiElements = + project.configurations.create("apiElements") { apiElements -> + configureElements( + apiElements, + Usage.JAVA_API, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, + AndroidArtifacts.ArtifactType.AAR) - override val artifactTypeForPublication: AndroidArtifacts.ArtifactType - get() = AndroidArtifacts.ArtifactType.AAR + apiElements.extendsFrom(includedApiUnmerged) + } + // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain + // this module and all transitive non merged dependencies + val includeRuntimeElements = + project.configurations.create("runtimeElements") { runtimeElements -> + configureElements( + runtimeElements, + Usage.JAVA_RUNTIME, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, + AndroidArtifacts.ArtifactType.AAR) + runtimeElements.extendsFrom(includeRuntimeUnmerged) + } + + val configurationsToAdd = listOf(includeApiClasspath, includeRuntimeClasspath) + configurationsToAdd.forEach { configuration -> + variantScope.incomingConfigurations.addConfiguration(configuration) + } + maybePublishToMaven( + project, + includeApiElements, + includeRuntimeElements, + includeRuntimeUnmerged + ) + } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt index 762746fb79..07bab17956 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt @@ -17,9 +17,15 @@ package com.android.build.gradle.internal.plugins import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl +import com.android.build.api.attributes.BuildTypeAttr import com.android.build.api.dsl.PrivacySandboxSdkExtension import com.android.build.gradle.internal.dsl.InternalPrivacySandboxSdkExtension import com.android.build.gradle.internal.dsl.PrivacySandboxSdkExtensionImpl +import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler +import com.android.build.gradle.internal.fusedlibrary.configureTransforms +import com.android.build.gradle.internal.fusedlibrary.createTasks +import com.android.build.gradle.internal.fusedlibrary.getDslServices import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkInternalArtifactType import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScopeImpl @@ -27,6 +33,7 @@ import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.res.PrivacySandboxSdkLinkAndroidResourcesTask import com.android.build.gradle.internal.services.Aapt2DaemonBuildService import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService +import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.internal.services.TaskCreationServicesImpl import com.android.build.gradle.internal.services.VersionedSdkLoaderService import com.android.build.gradle.internal.tasks.AppMetadataTask @@ -47,99 +54,250 @@ import com.android.build.gradle.tasks.PrivacySandboxSdkMergeResourcesTask import com.android.repository.Revision import com.google.wireless.android.sdk.stats.GradleBuildProject import org.gradle.api.GradleException +import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Usage import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.file.RegularFile import org.gradle.build.event.BuildEventsListenerRegistry import javax.inject.Inject class PrivacySandboxSdkPlugin @Inject constructor( - listenerRegistry: BuildEventsListenerRegistry, -): AbstractPrivacySandboxPlugin(listenerRegistry) { + val softwareComponentFactory: SoftwareComponentFactory, + listenerRegistry: BuildEventsListenerRegistry, +) : AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - private val versionedSdkLoaderService: VersionedSdkLoaderService by lazy { + val dslServices: DslServices by lazy(LazyThreadSafetyMode.NONE) { + withProject("dslServices") { project -> + getDslServices(project, projectServices) + } + } + + private val versionedSdkLoaderService: VersionedSdkLoaderService by lazy(LazyThreadSafetyMode.NONE) { withProject("versionedSdkLoaderService") { project -> VersionedSdkLoaderService( - dslServices, - project, - { - variantScope.compileSdkVersion - }, - { - Revision.parseRevision(extension.buildToolsVersion, Revision.Precision.MICRO) - }, + dslServices, + project, + { variantScope.compileSdkVersion }, + { + Revision.parseRevision(extension.buildToolsVersion, + Revision.Precision.MICRO) + }, ) } } // so far, there is only one variant. - override val variantScope: PrivacySandboxSdkVariantScope by lazy { + private val variantScope: PrivacySandboxSdkVariantScope by lazy { withProject("variantScope") { project -> PrivacySandboxSdkVariantScopeImpl( - project, - TaskCreationServicesImpl(projectServices), - { extension }, - { - BootClasspathConfigImpl( + project, + TaskCreationServicesImpl(projectServices), + { extension }, + ) { + BootClasspathConfigImpl( project, projectServices, versionedSdkLoaderService, null, false - ) - } - ) + ) + } } } - private val extension: PrivacySandboxSdkExtension by lazy { + private val extension: PrivacySandboxSdkExtension by lazy(LazyThreadSafetyMode.NONE) + { withProject("extension") { project -> instantiateExtension(project) } } + override fun configureProject(project: Project) { + val projectOptions = projectServices.projectOptions + Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() + Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() + } + override fun configureExtension(project: Project) { extension } override fun apply(project: Project) { - super.apply(project) + super.basePluginApply(project) if (!projectServices.projectOptions[BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT]) { throw GradleException( "Privacy Sandbox SDK support is experimental, and must be explicitly enabled.\n" + - "To enable support, add\n" + - " ${BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT.propertyName}=true\n" + - "to your project's gradle.properties file." + "To enable support, add\n" + + " ${BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT.propertyName}=true\n" + + "to your project's gradle.properties file." + ) + } + + // so far by default, we consume and publish only 'debug' variant + + // 'include' is the configuration that users will use to indicate which dependencies should + // be fused. + val includeConfigurations = project.configurations.create("include").also { + it.isCanBeConsumed = false + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive + // dependencies that are implementation() scoped will not be included. + val includeApiClasspath = project.configurations.create("includeApiClasspath").also { + it.isCanBeConsumed = false + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) + ) + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_API dependencies that are not + // fused in the resulting aar library. + val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { + it.isCanBeConsumed = true + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeApiClasspath, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive + // dependencies that are implementation() scoped will be included. + val includeRuntimeClasspath = + project.configurations.create("includeRuntimeClasspath").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + ) + val buildType: BuildTypeAttr = + project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are + // not fused in the resulting aar library. + val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeConfigurations, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // this is the outgoing configuration for JAVA_API scoped declarations, it will contain + // this module and all transitive non merged dependencies + fun configureElements( + elements: Configuration, + usage: String, + artifacts: ArtifactsImpl, + publicationArtifact: Artifact.Single<RegularFile>, + publicationArtifactType: AndroidArtifacts.ArtifactType + ) { + // we are only interested in the last provider in the chain of transformers for this bundle. + // Obviously, this is theoretical at this point since there is no variant API to replace + // artifacts, there is always only one. + val bundleTaskProvider = publicationArtifact.let { + artifacts + .getArtifactContainer(it) + .getTaskProviders() + .last() + } + elements.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, usage) ) + elements.isCanBeResolved = false + elements.isCanBeConsumed = true + elements.isTransitive = true + + elements.outgoing.variants { variants -> + variants.create(publicationArtifactType.type) { variant -> + variant.artifact(bundleTaskProvider) { artifact -> + artifact.type = publicationArtifactType.type + } + } + } + } + project.configurations.create("apiElements") { apiElements -> + configureElements( + apiElements, + Usage.JAVA_API, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, + AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE) + + apiElements.extendsFrom(includedApiUnmerged) + } + // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain + // this module and all transitive non merged dependencies + project.configurations.create("runtimeElements") { runtimeElements -> + configureElements( + runtimeElements, + Usage.JAVA_RUNTIME, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, + AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE) + runtimeElements.extendsFrom(includeRuntimeUnmerged) + } + val configurationsToAdd = listOf(includeApiClasspath, includeRuntimeClasspath) + configurationsToAdd.forEach { configuration -> + variantScope.incomingConfigurations.addConfiguration(configuration) } - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectServices.projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectServices.projectOptions).execute() } private fun instantiateExtension(project: Project): PrivacySandboxSdkExtension { - val sdkLibraryExtensionImpl= dslServices.newDecoratedInstance( - PrivacySandboxSdkExtensionImpl::class.java, - dslServices, + val sdkLibraryExtensionImpl = dslServices.newDecoratedInstance( + PrivacySandboxSdkExtensionImpl::class.java, + dslServices, ) abstract class Extension( - val publicExtensionImpl: PrivacySandboxSdkExtensionImpl, + val publicExtensionImpl: PrivacySandboxSdkExtensionImpl, ): InternalPrivacySandboxSdkExtension by publicExtensionImpl return project.extensions.create( - PrivacySandboxSdkExtension::class.java, - "android", - Extension::class.java, - sdkLibraryExtensionImpl + PrivacySandboxSdkExtension::class.java, + "android", + Extension::class.java, + sdkLibraryExtensionImpl ) } override fun createTasks(project: Project) { + configureTransforms(project, projectServices) createTasks( project, - variantScope, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, listOf( AppMetadataTask.PrivacySandboxSdkCreationAction(variantScope), FusedLibraryMergeClasses.PrivacySandboxSdkCreationAction(variantScope), @@ -154,18 +312,10 @@ class PrivacySandboxSdkPlugin @Inject constructor( PerModuleBundleTask.PrivacySandboxSdkCreationAction(variantScope), PackagePrivacySandboxSdkBundle.CreationAction(variantScope), ValidateSigningTask.PrivacySandboxSdkCreationAction(variantScope), - ) + FusedLibraryMergeArtifactTask.getCreationActions(variantScope), + ) + FusedLibraryMergeArtifactTask.getCreationActions(variantScope) ) } - override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = - GradleBuildProject.PluginType.PRIVACY_SANDBOX_SDK - - /** - * ASB only get published to Play Store, not maven - */ - override val artifactForPublication: Artifact.Single<RegularFile> = PrivacySandboxSdkInternalArtifactType.ASAR - - override val artifactTypeForPublication: AndroidArtifacts.ArtifactType - get() = AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE + override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = + GradleBuildProject.PluginType.PRIVACY_SANDBOX_SDK } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkAndroidResForBundleTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkAndroidResForBundleTask.kt index 3cb9c5ec11..dcfbfa01f5 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkAndroidResForBundleTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkAndroidResForBundleTask.kt @@ -74,7 +74,7 @@ import java.io.IOException * Task to link app resources into a proto format so that it can be consumed by the bundle tool. */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.LINKING]) abstract class LinkAndroidResForBundleTask : NonIncrementalTask() { @get:Input abstract val debuggable: Property<Boolean> diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkApplicationAndroidResourcesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkApplicationAndroidResourcesTask.kt index af1e42bb11..9e562613ab 100755 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkApplicationAndroidResourcesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/LinkApplicationAndroidResourcesTask.kt @@ -105,7 +105,7 @@ import java.nio.file.Files import javax.inject.Inject @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.LINKING]) abstract class LinkApplicationAndroidResourcesTask @Inject constructor(objects: ObjectFactory) : ProcessAndroidResources() { diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/PrivacySandboxSdkLinkAndroidResourcesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/PrivacySandboxSdkLinkAndroidResourcesTask.kt index 69211e4eae..8ecc9d10d3 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/PrivacySandboxSdkLinkAndroidResourcesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/PrivacySandboxSdkLinkAndroidResourcesTask.kt @@ -61,7 +61,7 @@ import java.io.File * Invokes AAPT2 link on the merged resources of all library dependencies into the .ap_ format. */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.LINKING]) abstract class PrivacySandboxSdkLinkAndroidResourcesTask : NonIncrementalTask() { @get:Input diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/namespaced/LinkLibraryAndroidResourcesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/namespaced/LinkLibraryAndroidResourcesTask.kt index 1fad278e07..1019b7983e 100755 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/namespaced/LinkLibraryAndroidResourcesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/res/namespaced/LinkLibraryAndroidResourcesTask.kt @@ -56,7 +56,7 @@ import java.io.File * Task to link the resources in a library project into an AAPT2 static library. */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.LINKING]) abstract class LinkLibraryAndroidResourcesTask : NonIncrementalTask() { @get:InputFiles diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/LintParallelBuildService.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/LintParallelBuildService.kt new file mode 100644 index 0000000000..512da2e1b9 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/services/LintParallelBuildService.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2022 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.services + +import com.android.build.gradle.options.BooleanOption +import com.android.build.gradle.options.ProjectOptions +import com.android.build.gradle.options.StringOption.LINT_HEAP_SIZE +import com.sun.management.OperatingSystemMXBean +import org.gradle.api.logging.Logging +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.services.BuildServiceRegistry +import java.lang.management.ManagementFactory +import java.util.Locale + +/** + * [LintParallelBuildService] limits the number of lint workers to avoid running out of memory. + */ +abstract class LintParallelBuildService : BuildService<BuildServiceParameters.None> { + + companion object { + fun calculateMaxParallelUsages( + projectOptions: ProjectOptions, + maxRuntimeMemory: Long, + totalPhysicalMemory: Long? + ): Int? { + return if (projectOptions.get(BooleanOption.RUN_LINT_IN_PROCESS)) { + calculateMaxParallelUsagesInProcess(maxRuntimeMemory) + } else { + calculateMaxParallelUsagesOutOfProcess( + projectOptions, + maxRuntimeMemory, + totalPhysicalMemory ?: return null + ) + } + } + + private fun calculateMaxParallelUsagesInProcess(maxRuntimeMemory: Long): Int { + // We assume lint will use about 512 megabytes per analysis task. + val memoryPerLintTask = 512 * 1024 * 1024 + // Multiply maxRuntimeMemory by 0.75 to save memory for other things too + val maxLintMemory = (maxRuntimeMemory * 0.75).toLong() + return Math.floorDiv(maxLintMemory, memoryPerLintTask).coerceAtLeast(1).toInt() + } + + private fun calculateMaxParallelUsagesOutOfProcess( + projectOptions: ProjectOptions, + maxRuntimeMemory: Long, + totalPhysicalMemory: Long + ): Int { + val maxParallelUsage = + Math.floorDiv( + totalPhysicalMemory, + parseLintHeapSize( + calculateLintHeapSize(projectOptions.get(LINT_HEAP_SIZE), maxRuntimeMemory) + ) + ) + // Leave space for at least the gradle daemon and the kotlin daemon + return (maxParallelUsage - 2).coerceAtLeast(1).toInt() + } + + // Default to using the main Gradle daemon heap size if no lint heap size is specified + fun calculateLintHeapSize( + userSpecifiedLintHeapSize: String?, + maxRuntimeMemory: Long + ): String = userSpecifiedLintHeapSize ?: "${maxRuntimeMemory / 1024 / 1024}m" + + private fun parseLintHeapSize(lintHeapSize: String): Long { + val value = lintHeapSize.lowercase(Locale.US) + val longOrNull = when { + value.toLongOrNull() != null -> value.toLongOrNull() + value.endsWith("k") -> { + value.substring(0, value.length-1).toLongOrNull()?.let { it * 1024 } + } + value.endsWith("m") -> { + value.substring(0, value.length-1).toLongOrNull()?.let { it * 1024 * 1024 } + } + value.endsWith("g") -> { + value.substring(0, value.length-1) + .toLongOrNull() + ?.let { it * 1024 * 1024 * 1024 } + } + else -> { + null + } + } + return longOrNull + ?: throw RuntimeException( + "Failed to parse ${LINT_HEAP_SIZE.propertyName} \"$lintHeapSize\"." + ) + } + } +} + +/** + * Returns a Provider of the [LintParallelBuildService]. + * + * Use this function instead of [getBuildService] to get the [LintParallelBuildService] because we + * don't want an instance of the [LintParallelBuildService] per class loader. + * + * This function uses registerIfAbsent in order to ensure locking when accessing build services. + */ +fun BuildServiceRegistry.getLintParallelBuildService(projectOptions: ProjectOptions) = + registerIfAbsent("LintParallelBuildService", LintParallelBuildService::class.java) { spec -> + spec.maxParallelUsages + .set( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + Runtime.getRuntime().maxMemory(), + getTotalPhysicalMemory() + ) + ) + } + +private fun getTotalPhysicalMemory() = try { + (ManagementFactory.getOperatingSystemMXBean() as OperatingSystemMXBean).totalPhysicalMemorySize +} catch (t: Throwable) { + Logging.getLogger(LintParallelBuildService::class.java) + .info("Failed to read total available memory", t) + null +} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleIdeModelProducerTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleIdeModelProducerTask.kt index eed0be8b18..5c2738599d 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleIdeModelProducerTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleIdeModelProducerTask.kt @@ -23,6 +23,7 @@ import com.android.build.gradle.internal.component.ApkCreationConfig import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* @@ -35,6 +36,7 @@ import org.gradle.work.DisableCachingByDefault * could outweigh its benefit. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.SYNC]) abstract class BundleIdeModelProducerTask : NonIncrementalTask() { @get:InputFile @get:PathSensitive(PathSensitivity.NAME_ONLY) diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryClasses.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryClasses.kt index 9388a4c0d5..301c40e600 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryClasses.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryClasses.kt @@ -38,6 +38,7 @@ import com.android.build.gradle.options.BooleanOption import com.android.build.gradle.tasks.toSerializable import com.android.builder.dexing.isJarFile import com.android.builder.files.SerializableFileChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.FileUtils import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty @@ -136,6 +137,7 @@ private fun BundleLibraryClassesInputs.configureWorkerActionParams( * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class BundleLibraryClassesDir: NewIncrementalTask(), BundleLibraryClassesInputs { @get:OutputDirectory @@ -200,6 +202,7 @@ abstract class BundleLibraryClassesDir: NewIncrementalTask(), BundleLibraryClass * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class BundleLibraryClassesJar : NonIncrementalTask(), BundleLibraryClassesInputs { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryJavaRes.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryJavaRes.kt index dfe88b8fdc..abd95af8be 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryJavaRes.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/BundleLibraryJavaRes.kt @@ -48,7 +48,7 @@ import java.util.zip.Deflater * simply executing the task. */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.JAVA_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.JAVA_RESOURCES, TaskCategoryLabel.ZIPPING]) abstract class BundleLibraryJavaRes : NonIncrementalTask() { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt index 9a583186a5..402e24ab3f 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt @@ -108,7 +108,7 @@ import kotlin.math.min * the impacted buckets (those containing changed input dex files). */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING, TaskCategoryLabel.MERGING]) abstract class DexMergingTask : NewIncrementalTask() { /** diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/FeatureDexMergeTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/FeatureDexMergeTask.kt index 3f088a1f34..bec34a3aab 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/FeatureDexMergeTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/FeatureDexMergeTask.kt @@ -35,7 +35,7 @@ import org.gradle.work.DisableCachingByDefault * A task merging dex files in dynamic feature modules into a single artifact type. */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING, TaskCategoryLabel.MERGING]) abstract class FeatureDexMergeTask : NonIncrementalTask() { @get:InputFiles diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LibraryAarJarsTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LibraryAarJarsTask.kt index 7cc05aa9bb..189131d094 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LibraryAarJarsTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LibraryAarJarsTask.kt @@ -28,6 +28,7 @@ import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges import com.android.builder.packaging.JarCreator import com.android.builder.packaging.JarMerger +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.tools.lint.typedefs.TypedefRemover import com.android.utils.FileUtils import org.gradle.api.file.ConfigurableFileCollection @@ -64,6 +65,7 @@ import java.util.zip.Deflater // TODO(b/132975663): add workers @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class LibraryAarJarsTask : NonIncrementalTask() { @get:Nested @get:Optional diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LinkManifestForAssetPackTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LinkManifestForAssetPackTask.kt index bf57a7ede2..50d6ab4f44 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LinkManifestForAssetPackTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/LinkManifestForAssetPackTask.kt @@ -50,7 +50,7 @@ import java.io.File * producing a linked manifest file suitable for packaging in the Android App Bundle. */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST, TaskCategoryLabel.LINKING]) abstract class LinkManifestForAssetPackTask : NonIncrementalTask() { /** diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceCleanTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceCleanTask.kt index 999b8214ff..e4d3e749e8 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceCleanTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceCleanTask.kt @@ -24,6 +24,7 @@ import com.android.build.gradle.internal.services.getBuildService import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationAction import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.google.common.annotations.VisibleForTesting import org.gradle.api.logging.Logging import org.gradle.api.provider.ListProperty @@ -37,6 +38,7 @@ import org.gradle.work.DisableCachingByDefault * Task for clearing the gradle avd folder of avd devices. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.TEST]) abstract class ManagedDeviceCleanTask: NonIncrementalGlobalTask() { @get: Internal abstract val avdService: Property<AvdComponentsBuildService> diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceSetupTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceSetupTask.kt index de238d91ed..c419c5a640 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceSetupTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ManagedDeviceSetupTask.kt @@ -31,6 +31,7 @@ import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationAction import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig import com.android.build.gradle.internal.testing.utp.ManagedDeviceImageSuggestionGenerator import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.repository.Revision import com.android.testing.utils.computeSystemImageHashFromDsl import com.android.testing.utils.isWearTvOrAutoDevice @@ -61,6 +62,7 @@ private val loggerWrapper = LoggerWrapper.getLogger(ManagedDeviceSetupTask::clas * device. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.TEST]) abstract class ManagedDeviceSetupTask: NonIncrementalGlobalTask() { @get: Internal diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeArtProfileTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeArtProfileTask.kt index e3d8aa4a96..df092b8b57 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeArtProfileTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeArtProfileTask.kt @@ -33,7 +33,7 @@ import org.gradle.api.tasks.TaskProvider import org.gradle.work.DisableCachingByDefault @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ART_PROFILE]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ART_PROFILE, TaskCategoryLabel.MERGING]) abstract class MergeArtProfileTask: MergeFileTask() { @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)] diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeClassesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeClassesTask.kt index 6f3405b1f3..2ae9012ebd 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeClassesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeClassesTask.kt @@ -27,6 +27,7 @@ import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.utils.fromDisallowChanges import com.android.builder.dexing.ClassFileInput.CLASS_MATCHER +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property @@ -45,6 +46,7 @@ import java.util.zip.Deflater * classes to the correct APKs via the Dex Splitter. */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING]) abstract class MergeClassesTask : NonIncrementalTask() { @get:Classpath diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeConsumerProguardFilesTask.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeConsumerProguardFilesTask.java index 74e0462393..bcbf3eee51 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeConsumerProguardFilesTask.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeConsumerProguardFilesTask.java @@ -46,7 +46,7 @@ import org.gradle.work.DisableCachingByDefault; * @see MergeFileTask */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = {TaskCategoryLabel.OPTIMIZATION}) +@BuildAnalyzer(taskCategoryLabels = {TaskCategoryLabel.OPTIMIZATION, TaskCategoryLabel.MERGING}) public abstract class MergeConsumerProguardFilesTask extends MergeFileTask { private boolean isDynamicFeature; diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeFileTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeFileTask.kt index 81d6d1a44f..a453c72717 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeFileTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeFileTask.kt @@ -15,6 +15,7 @@ */ package com.android.build.gradle.internal.tasks +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.FileUtils import com.google.common.base.Charsets import com.google.common.io.Files @@ -37,6 +38,7 @@ import java.io.IOException * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING]) abstract class MergeFileTask : NonIncrementalTask() { @get:InputFiles diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeJavaResourceTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeJavaResourceTask.kt index b1ddc416b3..89452ea375 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeJavaResourceTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeJavaResourceTask.kt @@ -68,7 +68,7 @@ import javax.inject.Inject * Task to merge java resources from multiple modules */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.JAVA_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.JAVA_RESOURCES, TaskCategoryLabel.MERGING]) abstract class MergeJavaResourceTask @Inject constructor(objects: ObjectFactory) : NewIncrementalTask() { diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeDebugMetadataTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeDebugMetadataTask.kt index f5703b97c7..ac0a3fdf8f 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeDebugMetadataTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeDebugMetadataTask.kt @@ -53,7 +53,7 @@ import java.io.File * simply executing the task. */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.NATIVE, TaskCategoryLabel.METADATA]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.NATIVE, TaskCategoryLabel.METADATA, TaskCategoryLabel.MERGING]) abstract class MergeNativeDebugMetadataTask : NonIncrementalTask() { @get:SkipWhenEmpty diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeLibsTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeLibsTask.kt index bf47ae0d72..2e13c845fc 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeLibsTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/MergeNativeLibsTask.kt @@ -69,7 +69,7 @@ import org.gradle.work.DisableCachingByDefault * Task to merge native libs from a project and possibly its dependencies */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.NATIVE]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.NATIVE, TaskCategoryLabel.MERGING]) abstract class MergeNativeLibsTask : NonIncrementalTask() { @get:InputFiles diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/NdkTask.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/NdkTask.java index 4fa2b13791..2b15d06093 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/NdkTask.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/NdkTask.java @@ -20,6 +20,8 @@ import com.android.annotations.Nullable; import com.android.build.gradle.internal.dsl.CoreNdkOptions; import java.util.List; import java.util.Set; + +import com.android.ide.common.attribution.TaskCategoryLabel; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Optional; @@ -27,6 +29,7 @@ import org.gradle.work.DisableCachingByDefault; /** Base task for tasks that require an NdkConfig */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = {TaskCategoryLabel.NATIVE}) public abstract class NdkTask extends NonIncrementalTask { @Nullable diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/PackageRenderscriptTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/PackageRenderscriptTask.kt index 091f7988f2..a27a83ae24 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/PackageRenderscriptTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/PackageRenderscriptTask.kt @@ -30,7 +30,7 @@ import java.io.File /** task packaging the rs headers */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.RENDERSCRIPT]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.RENDERSCRIPT, TaskCategoryLabel.ZIPPING]) abstract class PackageRenderscriptTask : Sync(), VariantAwareTask { @get:OutputDirectory diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ProcessJavaResTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ProcessJavaResTask.kt index 28aa26b7d0..a47c93a8a8 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ProcessJavaResTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ProcessJavaResTask.kt @@ -15,7 +15,6 @@ */ package com.android.build.gradle.internal.tasks -import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction @@ -75,9 +74,7 @@ abstract class ProcessJavaResTask : Sync(), VariantAwareTask { ) { super.configure(task) - for (sourceProvider in creationConfig.variantSources.sortedSourceProviders) { - task.from((sourceProvider as AndroidSourceSet).resources.getSourceFiles()) - } + task.from(creationConfig.sources.resources.getAsFileTrees()) task.duplicatesStrategy = DuplicatesStrategy.INCLUDE } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/DataBindingMergeDependencyArtifactsTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/DataBindingMergeDependencyArtifactsTask.kt index 3543501291..177bc75384 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/DataBindingMergeDependencyArtifactsTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/DataBindingMergeDependencyArtifactsTask.kt @@ -48,7 +48,7 @@ import java.io.File * simply executing the task. */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DATA_BINDING]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DATA_BINDING, TaskCategoryLabel.MERGING]) abstract class DataBindingMergeDependencyArtifactsTask : NonIncrementalTask() { /** * Classes available at Runtime. We extract BR files from there so that even if there is no diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/MergeRFilesForDataBindingTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/MergeRFilesForDataBindingTask.kt index d837c6432c..d6905573b4 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/MergeRFilesForDataBindingTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/databinding/MergeRFilesForDataBindingTask.kt @@ -19,8 +19,10 @@ package com.android.build.gradle.internal.tasks.databinding import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.file.FileCollection import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.Classpath @@ -38,6 +40,7 @@ import org.gradle.work.DisableCachingByDefault * simply executing the task. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.ANDROID_RESOURCES]) abstract class MergeRFilesForDataBindingTask : NonIncrementalTask() { private val NEW_LINE = "\n".toByteArray() diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/featuresplit/PackagedDependenciesWriterTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/featuresplit/PackagedDependenciesWriterTask.kt index ab80a6dff3..de3249b1d1 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/featuresplit/PackagedDependenciesWriterTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/featuresplit/PackagedDependenciesWriterTask.kt @@ -54,7 +54,7 @@ private val aarOrJarType = Action { container: AttributeContainer -> /** Task to write the list of transitive dependencies. */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.HELP]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.METADATA]) abstract class PackagedDependenciesWriterTask : NonIncrementalTask() { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/PublishingUtil.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/PublishingUtil.kt index 25f4df9075..396480c618 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/PublishingUtil.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/utils/PublishingUtil.kt @@ -40,17 +40,14 @@ fun createPublishingInfoForLibrary( flavorList: List<ProductFlavor>, buildTypes: NamedDomainObjectContainer<out BuildType>, productFlavors: NamedDomainObjectContainer<out ProductFlavor>, - testFixtureMainVariantName: String?, issueReporter: IssueReporter ): VariantPublishingInfo { val optIn = publishingFeatureOptIn(publishing as AbstractPublishing<SingleVariant>, projectOptions) val components = mutableListOf<ComponentPublishingInfo>() - // attach the testFixtures variants to the main variant component - val variantBasedComponentName = testFixtureMainVariantName ?: variantName if (!optIn) { components.add(ComponentPublishingInfo( - variantBasedComponentName, + variantName, AbstractPublishing.Type.AAR)) components.add(ComponentPublishingInfo( @@ -66,15 +63,11 @@ fun createPublishingInfoForLibrary( ensureComponentNameUniqueness(publishing, issueReporter) val singleVariant = publishing.singleVariants.find { - if (testFixtureMainVariantName != null) { - it.variantName == testFixtureMainVariantName - } else { it.variantName == variantName - } } if (singleVariant != null) { components.add(ComponentPublishingInfo( - variantBasedComponentName, + variantName, AbstractPublishing.Type.AAR, withSourcesJar = singleVariant.withSourcesJar, withJavadocJar = singleVariant.withJavadocJar diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/AbstractVariantInputManager.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/AbstractVariantInputManager.kt index 848203779f..650232fd88 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/AbstractVariantInputManager.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/AbstractVariantInputManager.kt @@ -18,16 +18,15 @@ package com.android.build.gradle.internal.variant import com.android.build.gradle.internal.BuildTypeData import com.android.build.gradle.internal.ProductFlavorData import com.android.build.gradle.internal.api.DefaultAndroidSourceSet -import com.android.build.gradle.internal.core.VariantDslInfoBuilder.Companion.computeSourceSetName import com.android.build.gradle.internal.dependency.SourceSetManager import com.android.build.gradle.internal.dsl.BuildType import com.android.build.gradle.internal.dsl.SigningConfig import com.android.build.gradle.internal.plugins.DslContainerProvider import com.android.build.gradle.internal.services.DslServices -import com.android.build.gradle.options.BooleanOption import com.android.builder.core.BuilderConstants import com.android.builder.core.ComponentType import com.android.builder.core.ComponentTypeImpl +import com.android.utils.appendCapitalized /** * Abstract Class responsible for handling the DSL containers of flavors/build types and processing @@ -174,6 +173,24 @@ abstract class AbstractVariantInputManager< } companion object { + /** + * Turns a string into a valid source set name for the given [ComponentType], e.g. + * "fooBarUnitTest" becomes "testFooBar". + */ + private fun computeSourceSetName( + baseName: String, + componentType: ComponentType + ): String { + var name = baseName + if (name.endsWith(componentType.suffix)) { + name = name.substring(0, name.length - componentType.suffix.length) + } + if (!componentType.prefix.isEmpty()) { + name = componentType.prefix.appendCapitalized(name) + } + return name + } + private fun checkName(name: String, displayName: String) { checkPrefix( name, diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt index b5001e39b8..82c063c3d2 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/variant/VariantPathHelper.kt @@ -18,8 +18,7 @@ package com.android.build.gradle.internal.variant import com.android.SdkConstants import com.android.build.api.dsl.ProductFlavor -import com.android.build.gradle.internal.core.VariantDslInfoBuilder -import com.android.build.gradle.internal.core.VariantDslInfoImpl +import com.android.build.api.variant.ComponentIdentity import com.android.build.gradle.internal.core.dsl.ApkProducingComponentDslInfo import com.android.build.gradle.internal.core.dsl.ComponentDslInfo import com.android.build.gradle.internal.services.DslServices @@ -27,6 +26,7 @@ import com.android.build.gradle.options.IntegerOption import com.android.build.gradle.options.StringOption import com.android.builder.core.BuilderConstants import com.android.builder.core.ComponentType +import com.android.utils.appendCapitalized import com.android.utils.combineAsCamelCase import com.android.utils.toStrings import com.google.common.base.Joiner @@ -42,6 +42,81 @@ class VariantPathHelper( private val dslServices: DslServices ) { + companion object { + /** + * Returns the full, unique name of the variant, including BuildType, flavors and test, dash + * separated. (similar to full name but with dashes) + * + * @return the name of the variant + */ + @JvmStatic + fun computeBaseName( + dimensionCombination: DimensionCombination, + componentType: ComponentType) : String { + val sb = StringBuilder() + if (dimensionCombination.productFlavors.isNotEmpty()) { + for ((_, name) in dimensionCombination.productFlavors) { + if (sb.isNotEmpty()) { + sb.append('-') + } + sb.append(name) + } + } + + dimensionCombination.buildType?.let { + if (sb.isNotEmpty()) { + sb.append('-') + } + sb.append(it) + } + + if (componentType.isNestedComponent) { + if (sb.isNotEmpty()) { + sb.append('-') + } + sb.append(componentType.prefix) + } + + if (sb.isEmpty()) { + sb.append("main") + } + + return sb.toString() + } + + /** + * Returns a full name that includes the given splits name. + * + * @param splitName the split name + * @return a unique name made up of the variant and split names. + */ + @JvmStatic + fun computeFullNameWithSplits( + variantConfiguration: ComponentIdentity, + componentType: ComponentType, + splitName: String): String { + val sb = StringBuilder() + + val flavorName = variantConfiguration.flavorName + + if (!flavorName.isNullOrEmpty()) { + sb.append(flavorName) + sb.appendCapitalized(splitName) + } else { + sb.append(splitName) + } + + variantConfiguration.buildType?.let { + sb.appendCapitalized(it) + } + + if (componentType.isNestedComponent) { + sb.append(componentType.suffix) + } + return sb.toString() + } + } + /** * Returns a unique directory name (can include multiple folders) for the variant, based on * build type, flavor and test. @@ -75,7 +150,7 @@ class VariantPathHelper( ) ) } - builder.add((dslInfo as VariantDslInfoImpl).buildTypeObj.name) + builder.add(dslInfo.buildType!!) builder.build() } @@ -103,7 +178,7 @@ class VariantPathHelper( * @return a unique name made up of the variant and split names. */ fun computeFullNameWithSplits(splitName: String): String { - return VariantDslInfoBuilder.computeFullNameWithSplits( + return computeFullNameWithSplits( dslInfo.componentIdentity, dslInfo.componentType, splitName @@ -117,8 +192,8 @@ class VariantPathHelper( * @return the name of the variant */ val baseName: String by lazy { - VariantDslInfoBuilder.computeBaseName( - dslInfo as VariantDslInfoImpl, + computeBaseName( + dslInfo, dslInfo.componentType ) } @@ -137,7 +212,7 @@ class VariantPathHelper( } } sb.append(splitName).append('-') - sb.append((dslInfo as VariantDslInfoImpl).buildTypeObj.name) + sb.append(dslInfo.buildType!!) if (dslInfo.componentType.isNestedComponent) { sb.append('-').append(dslInfo.componentType.prefix) } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt index a5d7d1cdb3..ae4c72e334 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/options/BooleanOption.kt @@ -117,6 +117,7 @@ enum class BooleanOption( */ BUILD_FEATURE_MLMODELBINDING("android.defaults.buildfeatures.mlmodelbinding", false, ApiStage.Experimental), + ENABLE_DEFAULT_DEBUG_SIGNING_CONFIG("android.experimental.useDefaultDebugSigningConfigForProfileableBuildtypes", false, ApiStage.Experimental), ENABLE_PROFILE_JSON("android.enableProfileJson", false, FeatureStage.Experimental), DISALLOW_DEPENDENCY_RESOLUTION_AT_CONFIGURATION("android.dependencyResolutionAtConfigurationTime.disallow", false, FeatureStage.Experimental), ENABLE_TEST_SHARDING("android.androidTest.shardBetweenDevices", false, FeatureStage.Experimental), @@ -203,6 +204,7 @@ enum class BooleanOption( PRIVACY_SANDBOX_SDK_SUPPORT("android.experimental.privacysandboxsdk.enable", false, FeatureStage.Experimental), + BUILD_ANALYZER_TASK_LABELS("android.experimental.buildanalyzer.tasklabels.enable", false, FeatureStage.Experimental), /* ------------------------ * SOFTLY-ENFORCED FEATURES */ diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/BundleAar.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/BundleAar.kt index 484e28872b..f076b22a85 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/BundleAar.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/BundleAar.kt @@ -142,8 +142,7 @@ abstract class BundleAar : Zip(), VariantAwareTask { creationConfig.artifacts.get( InternalArtifactType.DATA_BINDING_BASE_CLASS_LOG_ARTIFACT), prependToCopyPath( - DataBindingBuilder.DATA_BINDING_CLASS_LOG_ROOT_FOLDER_IN_AAR - ) + DataBindingBuilder.DATA_BINDING_CLASS_LOG_ROOT_FOLDER_IN_AAR) ) } @@ -394,11 +393,14 @@ abstract class BundleAar : Zip(), VariantAwareTask { } companion object { - private fun prependToCopyPath(pathSegment: String) = Action { copySpec: CopySpec -> - copySpec.eachFile { fileCopyDetails: FileCopyDetails -> - fileCopyDetails.relativePath = - fileCopyDetails.relativePath.prepend(pathSegment) - } - } + + private fun prependToCopyPath(pathSegment: String, includeEmptyDirs: Boolean = false) = + Action { copySpec: CopySpec -> + copySpec.includeEmptyDirs = includeEmptyDirs + copySpec.eachFile { fileCopyDetails: FileCopyDetails -> + fileCopyDetails.relativePath = + fileCopyDetails.relativePath.prepend(pathSegment) + } + } } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExtractDeepLinksTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExtractDeepLinksTask.kt index d89a337db3..5e710b3759 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExtractDeepLinksTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExtractDeepLinksTask.kt @@ -25,6 +25,7 @@ import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.ide.common.attribution.TaskCategoryLabel import com.android.ide.common.blame.SourceFilePosition +import com.android.build.gradle.internal.utils.setDisallowChanges import com.android.manifmerger.NavigationXmlDocumentData import com.android.manifmerger.NavigationXmlLoader import com.android.utils.FileUtils @@ -155,7 +156,12 @@ abstract class ExtractDeepLinksTask: NonIncrementalTask() { } } ) - task.manifestPlaceholders.set(creationConfig.manifestPlaceholders) + task.manifestPlaceholders.setDisallowChanges( + creationConfig.manifestPlaceholdersCreationConfig?.placeholders, + handleNullable = { + empty() + } + ) task.forAar.set(forAar) } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryBundle.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryBundle.kt index c3c0af4850..b9b76541e4 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryBundle.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryBundle.kt @@ -31,6 +31,7 @@ import org.gradle.api.tasks.bundling.Jar import org.gradle.work.DisableCachingByDefault @DisableCachingByDefault(because = "Task does not calculate anything, only creates a jar.") +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.AAR_PACKAGING]) abstract class FusedLibraryBundle: Jar() { // We have to explicitly repeat the output file as the artifacts API expects a @@ -105,6 +106,7 @@ abstract class FusedLibraryBundleAar: FusedLibraryBundle() { } @DisableCachingByDefault(because = "Task does not calculate anything, only creates a jar.") +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class FusedLibraryBundleClasses: FusedLibraryBundle() { class CreationAction( diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryManifestMergerTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryManifestMergerTask.kt index 625de74e21..fe1df0e324 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryManifestMergerTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryManifestMergerTask.kt @@ -23,12 +23,14 @@ import com.android.build.gradle.internal.fusedlibrary.FusedLibraryInternalArtifa import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope import com.android.build.gradle.internal.profile.ProfileAwareWorkAction import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.configureVariantProperties import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.build.gradle.internal.tasks.manifest.ManifestProviderImpl import com.android.build.gradle.internal.tasks.manifest.mergeManifests import com.android.build.gradle.internal.utils.setDisallowChanges import com.android.build.gradle.tasks.ProcessApplicationManifest.Companion.getArtifactName +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.manifmerger.ManifestMerger2 import com.android.utils.FileUtils import org.gradle.api.artifacts.ArtifactCollection @@ -52,6 +54,7 @@ import java.io.File * Merges Manifests from libraries that will be included with in fused library. */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.MANIFEST, TaskCategoryLabel.FUSING]) abstract class FusedLibraryManifestMergerTask : ManifestProcessorTask() { @get:Internal diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt index 112f49a87b..20321ea5dc 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeArtifactTask.kt @@ -31,10 +31,12 @@ import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope import com.android.build.gradle.internal.profile.ProfileAwareWorkAction import com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.configureVariantProperties import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.usLocaleCapitalize import org.gradle.api.attributes.Usage import org.gradle.api.file.ConfigurableFileCollection @@ -62,6 +64,7 @@ import java.io.File * once this feature is supported in the fused library plugin. */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.FUSING]) abstract class FusedLibraryMergeArtifactTask : NonIncrementalTask() { @get:Input diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeClasses.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeClasses.kt index 93d0d9530c..93bddcea87 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeClasses.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeClasses.kt @@ -20,8 +20,10 @@ import com.android.build.gradle.internal.fusedlibrary.FusedLibraryInternalArtifa import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.builder.dexing.ClassFileInput.CLASS_MATCHER +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.FileUtils import org.gradle.api.DefaultTask import org.gradle.api.attributes.Usage @@ -43,6 +45,7 @@ import java.util.jar.JarFile * merge classes.jar coming from included libraries in fused libraries plugin. */ @DisableCachingByDefault(because = "No calculation is made, merging classes. ") +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.FUSING]) abstract class FusedLibraryMergeClasses: DefaultTask() { @get:OutputDirectory diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeResourcesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeResourcesTask.kt index bd9204d8bf..d0c766ab8f 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeResourcesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/FusedLibraryMergeResourcesTask.kt @@ -25,10 +25,12 @@ import com.android.build.gradle.internal.profile.AnalyticsService import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.services.getBuildService +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalGlobalTask import com.android.build.gradle.internal.tasks.Workers import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.ide.common.blame.MergingLog import com.android.ide.common.rendering.api.ResourceNamespace import com.android.ide.common.resources.CopyToOutputDirectoryResourceCompilationService @@ -61,6 +63,7 @@ import java.io.File * handled by the AGP MergeResources task. */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.FUSING]) abstract class FusedLibraryMergeResourcesTask : NonIncrementalGlobalTask() { @get:OutputDirectory diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/GenerateManifestJarTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/GenerateManifestJarTask.kt index cc81c575b6..117f1e191d 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/GenerateManifestJarTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/GenerateManifestJarTask.kt @@ -43,7 +43,7 @@ import org.gradle.api.tasks.TaskProvider * This manifest class is used for accessing Android Manifest custom permission names. */ @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST, TaskCategoryLabel.ZIPPING]) abstract class GenerateManifestJarTask : NonIncrementalTask() { @get:InputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/InvokeManifestMerger.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/InvokeManifestMerger.kt index 90029ab7c6..236982a0ab 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/InvokeManifestMerger.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/InvokeManifestMerger.kt @@ -41,7 +41,7 @@ import org.gradle.work.DisableCachingByDefault * or overlay manifests */ @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MANIFEST, TaskCategoryLabel.MERGING]) abstract class InvokeManifestMerger : NonIncrementalTask(), Supplier<File> { @get:InputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MapSourceSetPathsTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MapSourceSetPathsTask.kt index 943ac20bfb..6a987858cd 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MapSourceSetPathsTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MapSourceSetPathsTask.kt @@ -4,11 +4,13 @@ import com.android.SdkConstants import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.scope.InternalArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.features.AndroidResourcesTaskCreationAction import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction import com.android.build.gradle.internal.tasks.factory.features.AndroidResourcesTaskCreationActionImpl import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.ide.common.resources.writeIdentifiedSourceSetsFile import com.android.utils.FileUtils import org.gradle.api.file.ConfigurableFileCollection @@ -33,6 +35,7 @@ import java.io.File * Produces a file which lists project resource source set directories with an identifier. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) abstract class MapSourceSetPathsTask : NonIncrementalTask() { @get:Input diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeResources.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeResources.kt index b8cdf73f90..cb67be719a 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeResources.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeResources.kt @@ -103,7 +103,7 @@ import javax.xml.bind.JAXBException import javax.xml.parsers.DocumentBuilderFactory @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ANDROID_RESOURCES, TaskCategoryLabel.MERGING]) abstract class MergeResources : NewIncrementalTask() { // ----- PUBLIC TASK API ----- /** Directory to write the merged resources to */ diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeSourceSetFolders.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeSourceSetFolders.kt index ed0716b91b..19d1ed0f86 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeSourceSetFolders.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeSourceSetFolders.kt @@ -69,7 +69,7 @@ import java.io.File import java.io.IOException @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.SOURCE_PROCESSING]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.SOURCE_PROCESSING, TaskCategoryLabel.MERGING]) abstract class MergeSourceSetFolders : NewIncrementalTask() { @get:OutputDirectory diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestGeneratorTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestGeneratorTask.kt index b1f5f295f9..46cb45a1e6 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestGeneratorTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestGeneratorTask.kt @@ -31,7 +31,7 @@ import org.gradle.work.DisableCachingByDefault // Disable caching since we only create a small text file. @DisableCachingByDefault -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.SOURCE_GENERATION]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.SOURCE_GENERATION, TaskCategoryLabel.MANIFEST]) abstract class PrivacySandboxSdkManifestGeneratorTask: NonIncrementalTask() { @get:OutputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestMergerTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestMergerTask.kt index 4fd70cd0cc..4d8750442a 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestMergerTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkManifestMergerTask.kt @@ -22,9 +22,11 @@ import com.android.build.gradle.internal.fusedlibrary.FusedLibraryInternalArtifa import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkInternalArtifactType import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.configureVariantProperties import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.FileUtils import org.gradle.api.attributes.Usage import org.gradle.api.file.RegularFileProperty @@ -35,6 +37,7 @@ import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskProvider @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.MANIFEST]) abstract class PrivacySandboxSdkManifestMergerTask: FusedLibraryManifestMergerTask() { @get: InputFile diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt index 3fe04500df..20936cfe03 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt @@ -43,7 +43,7 @@ import org.gradle.work.Incremental import org.gradle.work.InputChanges @CacheableTask -@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING]) +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.DEXING, TaskCategoryLabel.MERGING]) abstract class PrivacySandboxSdkMergeDexTask: NewIncrementalTask() { @get:Incremental diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeResourcesTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeResourcesTask.kt index 04f3c05f91..f66d6fb3ac 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeResourcesTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeResourcesTask.kt @@ -25,11 +25,13 @@ import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.res.Aapt2FromMaven import com.android.build.gradle.internal.services.Aapt2Input import com.android.build.gradle.internal.services.getBuildService +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.Workers import com.android.build.gradle.internal.tasks.configureVariantProperties import com.android.build.gradle.internal.tasks.factory.TaskCreationAction import com.android.build.gradle.internal.utils.setDisallowChanges +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.ide.common.workers.WorkerExecutorFacade import org.gradle.api.attributes.Usage import org.gradle.api.file.ConfigurableFileCollection @@ -54,6 +56,7 @@ import org.gradle.api.tasks.TaskProvider * handled by the AGP MergeResources task. */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.MERGING, TaskCategoryLabel.ANDROID_RESOURCES]) abstract class PrivacySandboxSdkMergeResourcesTask : NonIncrementalTask() { @get:OutputDirectory diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessAndroidResources.java b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessAndroidResources.java index b52120e8d5..f5bd0e4724 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessAndroidResources.java +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessAndroidResources.java @@ -22,10 +22,13 @@ import com.android.build.api.variant.impl.VariantOutputConfigurationImplKt; import com.android.build.api.variant.impl.VariantOutputImpl; import com.android.build.gradle.internal.component.ComponentCreationConfig; import com.android.build.gradle.internal.component.ConsumableCreationConfig; +import com.android.build.gradle.internal.tasks.BuildAnalyzer; import com.android.build.gradle.internal.tasks.NewIncrementalTask; +import com.android.ide.common.attribution.TaskCategoryLabel; import com.android.utils.FileUtils; import com.google.common.base.Preconditions; import java.io.File; + import org.gradle.api.file.DirectoryProperty; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Internal; @@ -37,6 +40,7 @@ import org.gradle.work.Incremental; /** Base class for process resources / create R class task, to satisfy existing variants API. */ @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = {TaskCategoryLabel.ANDROID_RESOURCES}) public abstract class ProcessAndroidResources extends NewIncrementalTask { protected VariantOutputImpl mainSplit; diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessApplicationManifest.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessApplicationManifest.kt index 70ac09fad1..ba1aeb1754 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessApplicationManifest.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessApplicationManifest.kt @@ -20,6 +20,7 @@ import com.android.build.api.variant.impl.VariantOutputImpl import com.android.build.api.variant.impl.getApiString import com.android.build.gradle.internal.LoggerWrapper import com.android.build.gradle.internal.component.ApkCreationConfig +import com.android.build.gradle.internal.component.ApplicationCreationConfig import com.android.build.gradle.internal.component.DynamicFeatureCreationConfig import com.android.build.gradle.internal.component.VariantCreationConfig import com.android.build.gradle.internal.dependency.ArtifactCollectionWithExtraArtifact.ExtraComponentIdentifier @@ -456,7 +457,9 @@ abstract class ProcessApplicationManifest : ManifestProcessorTask() { } task.packageOverride.setDisallowChanges(creationConfig.applicationId) task.namespace.setDisallowChanges(creationConfig.namespace) - task.profileable.setDisallowChanges(creationConfig.profileable) + task.profileable.setDisallowChanges( + (creationConfig as? ApplicationCreationConfig)?.profileable ?: false + ) task.testOnly.setDisallowChanges( ProfilingMode.getProfilingModeType( creationConfig.services.projectOptions[StringOption.PROFILING_MODE] diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessTestManifest.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessTestManifest.kt index f8a4cfb334..6d995acf01 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessTestManifest.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ProcessTestManifest.kt @@ -507,7 +507,12 @@ abstract class ProcessTestManifest : ManifestProcessorTask() { ArtifactScope.ALL, AndroidArtifacts.ArtifactType.MANIFEST ) - task.placeholdersValues.setDisallowChanges(creationConfig.manifestPlaceholders) + task.placeholdersValues.setDisallowChanges( + creationConfig.manifestPlaceholdersCreationConfig?.placeholders, + handleNullable = { + empty() + } + ) if (!creationConfig.global.namespacedAndroidResources) { task.navigationJsons = project.files( creationConfig diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/SourceJarTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/SourceJarTask.kt index 77018fa3fd..a24f8dbc96 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/SourceJarTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/SourceJarTask.kt @@ -20,8 +20,10 @@ import com.android.SdkConstants import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.scope.InternalArtifactType import com.android.build.gradle.internal.scope.getOutputPath +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.VariantAwareTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.attributes.DocsType import org.gradle.api.file.DuplicatesStrategy import org.gradle.api.tasks.Internal @@ -31,6 +33,7 @@ import org.gradle.api.tasks.util.PatternSet import org.gradle.work.DisableCachingByDefault @DisableCachingByDefault +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING]) abstract class SourceJarTask : Jar(), VariantAwareTask { @Internal diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ZipMergingTask.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ZipMergingTask.kt index 2447834f19..68e57238b3 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ZipMergingTask.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ZipMergingTask.kt @@ -21,8 +21,10 @@ import com.android.build.gradle.internal.component.ComponentCreationConfig import com.android.build.gradle.internal.packaging.JarCreatorFactory import com.android.build.gradle.internal.packaging.JarCreatorType import com.android.build.gradle.internal.scope.InternalArtifactType +import com.android.build.gradle.internal.tasks.BuildAnalyzer import com.android.build.gradle.internal.tasks.NonIncrementalTask import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction +import com.android.ide.common.attribution.TaskCategoryLabel import com.android.utils.FileUtils import com.google.common.annotations.VisibleForTesting import org.gradle.api.file.RegularFileProperty @@ -39,6 +41,7 @@ import java.util.zip.Deflater /** Task to merge the res/classes intermediate jars from a library into a single one */ @CacheableTask +@BuildAnalyzer(taskCategoryLabels = [TaskCategoryLabel.ZIPPING, TaskCategoryLabel.MERGING]) abstract class ZipMergingTask : NonIncrementalTask() { @get:InputFiles diff --git a/build-system/gradle-core/src/test/java/com/android/build/api/component/analytics/AnalyticsEnabledSourcesTest.kt b/build-system/gradle-core/src/test/java/com/android/build/api/component/analytics/AnalyticsEnabledSourcesTest.kt index 9d49113ae2..2729b58fc1 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/api/component/analytics/AnalyticsEnabledSourcesTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/api/component/analytics/AnalyticsEnabledSourcesTest.kt @@ -123,6 +123,15 @@ class AnalyticsEnabledSourcesTest { ) } + @Test + fun getResources() { + testAnalytics( + SourceDirectories.Flat::class.java, + Sources::resources, + VariantPropertiesMethodType.SOURCES_RESOURCES_ACCESS_VALUE + ) + } + private fun <T: SourceDirectories> testAnalytics( type: Class<T>, accessor: (sources: Sources) -> T?, diff --git a/build-system/gradle-core/src/test/java/com/android/build/api/variant/impl/VariantBuilderImplTest.kt b/build-system/gradle-core/src/test/java/com/android/build/api/variant/impl/VariantBuilderImplTest.kt index e25bd08b51..fe620caf90 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/api/variant/impl/VariantBuilderImplTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/api/variant/impl/VariantBuilderImplTest.kt @@ -18,7 +18,7 @@ package com.android.build.api.variant.impl import com.android.build.api.variant.ComponentIdentity import com.android.build.api.variant.VariantBuilder -import com.android.build.gradle.internal.core.VariantDslInfo +import com.android.build.gradle.internal.core.dsl.VariantDslInfo import com.android.build.gradle.internal.services.ProjectServices import com.android.build.gradle.internal.services.VariantBuilderServices import com.google.common.truth.Truth diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/DefaultVariantTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/DefaultVariantTest.kt index 5fd9108ad3..9656a4c34f 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/DefaultVariantTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/DefaultVariantTest.kt @@ -20,7 +20,7 @@ import com.android.AndroidProjectTypes import com.android.build.api.variant.VariantFilter import com.android.build.api.variant.impl.VariantImpl import com.android.build.gradle.internal.component.VariantCreationConfig -import com.android.build.gradle.internal.core.VariantDslInfoBuilder +import com.android.build.gradle.internal.core.dsl.impl.computeName import com.android.build.gradle.internal.dsl.ApplicationBuildFeaturesImpl import com.android.build.gradle.internal.scope.BuildFeatureValuesImpl import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig @@ -492,7 +492,7 @@ class DefaultVariantTest: AbstractVariantInputModelTest<String>() { Mockito.`when`(globalTaskCreationConfig.services).thenReturn(dslServices) for (variant in variantComputer.computeVariants()) { - val name = VariantDslInfoBuilder.computeName(variant, componentType) + val name = computeName(variant, componentType) val flavors = variant.productFlavors.map { (given.productFlavors[it.second] ?: error("Cant find flavor ${it.second}")).productFlavor diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/MergedFlavorTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/MergedFlavorTest.kt index eac76485d5..d74257d228 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/MergedFlavorTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/MergedFlavorTest.kt @@ -21,8 +21,10 @@ import com.android.build.gradle.internal.fixtures.FakeGradleProperty import com.android.build.gradle.internal.fixtures.FakeProviderFactory import com.android.build.gradle.internal.fixtures.FakeSyncIssueReporter import com.android.build.gradle.internal.services.DslServices +import com.android.build.gradle.internal.services.VariantServices import com.android.build.gradle.internal.services.createDslServices import com.android.build.gradle.internal.services.createProjectServices +import com.android.build.gradle.internal.services.createVariantPropertiesApiServices import com.android.build.gradle.options.BooleanOption import com.android.build.gradle.options.ProjectOptions import com.android.builder.core.AbstractProductFlavor @@ -80,10 +82,11 @@ class MergedFlavorTest { custom2.applicationId = "com.custom2.app" } } - private lateinit var dslServices: DslServices + private lateinit var dslServices: DslServices + private lateinit var services: VariantServices - private fun initDslServices(enableLegacyApi: Boolean, throwOnError: Boolean = !enableLegacyApi) { + private fun initservices(enableLegacyApi: Boolean, throwOnError: Boolean = !enableLegacyApi) { val properties = ImmutableMap.builder<String, Any>() properties.put( @@ -100,26 +103,36 @@ class MergedFlavorTest { issueReporter = FakeSyncIssueReporter(throwOnError = throwOnError) ) ) + + services = createVariantPropertiesApiServices( + createProjectServices( + projectOptions = ProjectOptions( + ImmutableMap.of(), + FakeProviderFactory(FakeProviderFactory.factory, properties.build()) + ), + issueReporter = FakeSyncIssueReporter(throwOnError = throwOnError) + ) + ) } @Test fun testClone() { - initDslServices(true) - val flavor = MergedFlavor.clone(custom, FakeGradleProperty("com.forty.two"), dslServices) + initservices(true) + val flavor = MergedFlavor.clone(custom, FakeGradleProperty("com.forty.two"), services) assertThat(flavor.toString().substringAfter("{")) .isEqualTo(custom.toString().substringAfter("{")) CopyOfTester.assertAllGettersCalled( MergedFlavor::class.java, flavor, listOf("getApplicationId") - ) { MergedFlavor.clone(it, FakeGradleProperty("com.forty.two"), dslServices) } + ) { MergedFlavor.clone(it, FakeGradleProperty("com.forty.two"), services) } } @Test fun testMergeOnDefault() { - initDslServices(true) + initservices(true) val flavor = - MergedFlavor.mergeFlavors(defaultFlavor, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), dslServices) + MergedFlavor.mergeFlavors(defaultFlavor, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), services) assertThat(flavor.minSdkVersion?.apiLevel).isEqualTo(42) assertThat(flavor.targetSdkVersion?.apiLevel).isEqualTo(43) @@ -135,10 +148,10 @@ class MergedFlavorTest { @Test fun testMergeOnCustom() { - initDslServices(true) + initservices(true) val flavor = - MergedFlavor.mergeFlavors(custom, ImmutableList.of(defaultFlavor),FakeGradleProperty("com.forty.two"), dslServices) + MergedFlavor.mergeFlavors(custom, ImmutableList.of(defaultFlavor),FakeGradleProperty("com.forty.two"), services) assertThat(flavor.minSdkVersion?.apiLevel).isEqualTo(42) assertThat(flavor.targetSdkVersion?.apiLevel).isEqualTo(43) @@ -154,13 +167,13 @@ class MergedFlavorTest { @Test fun testMergeDefaultOnDefault() { - initDslServices(enableLegacyApi = false, throwOnError = false) + initservices(enableLegacyApi = false, throwOnError = false) val defaultFlavor2 = productFlavor("default2") val flavor = MergedFlavor .mergeFlavors( - defaultFlavor2, ImmutableList.of(defaultFlavor), FakeGradleProperty("com.forty.two"), dslServices) + defaultFlavor2, ImmutableList.of(defaultFlavor), FakeGradleProperty("com.forty.two"), services) assertThat(flavor.minSdkVersion).isNull() assertThat(flavor.targetSdkVersion).isNull() @@ -176,8 +189,8 @@ class MergedFlavorTest { @Test fun testResourceConfigMerge() { - initDslServices(true) - val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), dslServices) + initservices(true) + val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), services) val configs = flavor.resourceConfigurations assertThat(configs).containsExactly("hdpi", "ldpi") @@ -185,8 +198,8 @@ class MergedFlavorTest { @Test fun testManifestPlaceholdersMerge() { - initDslServices(true) - val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), dslServices) + initservices(true) + val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), services) val manifestPlaceholders = flavor.manifestPlaceholders assertThat(manifestPlaceholders) @@ -195,8 +208,8 @@ class MergedFlavorTest { @Test fun testResValuesMerge() { - initDslServices(true) - val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), dslServices) + initservices(true) + val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), services) val resValues = flavor.resValues assertThat(resValues).hasSize(3) @@ -207,9 +220,9 @@ class MergedFlavorTest { @Test fun testBuildConfigFieldMerge() { - initDslServices(true) + initservices(true) - val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), dslServices) + val flavor = MergedFlavor.mergeFlavors(custom2, ImmutableList.of(custom), FakeGradleProperty("com.forty.two"), services) val buildConfigFields = flavor.buildConfigFields assertThat(buildConfigFields).hasSize(3) @@ -220,7 +233,7 @@ class MergedFlavorTest { @Test fun testMergeMultiple() { - initDslServices(true) + initservices(true) val custom3 = productFlavor("custom3") custom3.minSdkVersion = DefaultApiVersion(102) @@ -228,7 +241,7 @@ class MergedFlavorTest { custom3.versionNameSuffix = "custom3" val flavor = - MergedFlavor.mergeFlavors(custom, ImmutableList.of(custom3, custom2), FakeGradleProperty("com.forty.two"), dslServices) + MergedFlavor.mergeFlavors(custom, ImmutableList.of(custom3, custom2), FakeGradleProperty("com.forty.two"), services) assertThat(flavor.minSdkVersion).isEqualTo( DefaultApiVersion( @@ -241,13 +254,13 @@ class MergedFlavorTest { @Test fun testSecondDimensionOverwritesDefault() { - initDslServices(true) + initservices(true) val custom3 = productFlavor("custom3") custom3.minSdkVersion = DefaultApiVersion(102) val flavor = - MergedFlavor.mergeFlavors(custom, ImmutableList.of(custom3, custom2), FakeGradleProperty("com.forty.two"), dslServices) + MergedFlavor.mergeFlavors(custom, ImmutableList.of(custom3, custom2), FakeGradleProperty("com.forty.two"), services) assertThat(flavor.minSdkVersion).isEqualTo( DefaultApiVersion( 102 @@ -259,8 +272,8 @@ class MergedFlavorTest { @Test fun testSetVersionCodeError() { - initDslServices(false) - val flavor = MergedFlavor.clone(defaultFlavor, FakeGradleProperty("com.forty.two"), dslServices) + initservices(false) + val flavor = MergedFlavor.clone(defaultFlavor, FakeGradleProperty("com.forty.two"), services) try { flavor.versionCode = 123 fail("Setting versionCode should result in RuntimeException from issueReporter") @@ -281,8 +294,8 @@ class MergedFlavorTest { @Test fun testSetVersionNameError() { - initDslServices(false) - val flavor = MergedFlavor.clone(defaultFlavor, FakeGradleProperty("com.forty.two"), dslServices) + initservices(false) + val flavor = MergedFlavor.clone(defaultFlavor, FakeGradleProperty("com.forty.two"), services) try { flavor.versionName = "foo" fail("Setting versionName should result in RuntimeException from issueReporter") diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantBuilderComputeNameTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantBuilderComputeNameTest.kt index bb457b642a..6a3f5bbe26 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantBuilderComputeNameTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantBuilderComputeNameTest.kt @@ -17,7 +17,10 @@ package com.android.build.gradle.internal.core import com.android.build.api.component.impl.ComponentIdentityImpl +import com.android.build.gradle.internal.core.dsl.impl.computeName import com.android.build.gradle.internal.variant.DimensionCombinationImpl +import com.android.build.gradle.internal.variant.VariantPathHelper.Companion.computeBaseName +import com.android.build.gradle.internal.variant.VariantPathHelper.Companion.computeFullNameWithSplits import com.android.builder.core.ComponentType import com.android.builder.core.ComponentTypeImpl import com.android.testutils.AbstractBuildGivenBuildExpectTest @@ -205,14 +208,14 @@ class VariantBuilderComputeNameTest : override fun defaultWhen(given: GivenBuilder): ResultBuilder { val varCombo = DimensionCombinationImpl(given.buildType, given.flavors) - var flavorName: String = "" + var flavorName = "" return ResultBuilder().also { - it.name = VariantDslInfoBuilder.computeName(varCombo, given.componentType) { + it.name = computeName(varCombo, given.componentType) { flavorName = it } - it.baseName = VariantDslInfoBuilder.computeBaseName(varCombo, given.componentType) - it.fullNameWithSplit = VariantDslInfoBuilder.computeFullNameWithSplits( + it.baseName = computeBaseName(varCombo, given.componentType) + it.fullNameWithSplit = computeFullNameWithSplits( ComponentIdentityImpl( it.name, flavorName, diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest.java b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest.java index f56845f1c2..862175ec11 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest.java +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest.java @@ -19,12 +19,15 @@ package com.android.build.gradle.internal.core; import static com.google.common.truth.Truth.assertThat; import com.android.annotations.Nullable; -import com.android.build.api.dsl.CommonExtension; import com.android.build.api.variant.AndroidVersion; import com.android.build.api.variant.impl.MutableAndroidVersion; import com.android.build.gradle.BaseExtension; +import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo; +import com.android.build.gradle.internal.core.dsl.impl.DslInfoBuilder; +import com.android.build.gradle.internal.dsl.ApplicationPublishingImpl; import com.android.build.gradle.internal.dsl.BuildType; import com.android.build.gradle.internal.dsl.DefaultConfig; +import com.android.build.gradle.internal.dsl.InternalApplicationExtension; import com.android.build.gradle.internal.dsl.ProductFlavor; import com.android.build.gradle.internal.dsl.SigningConfig; import com.android.build.gradle.internal.fixtures.FakeDeprecationReporter; @@ -46,7 +49,6 @@ import com.android.builder.model.ApiVersion; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.File; -import java.util.Collections; import java.util.List; import kotlin.Pair; import org.gradle.api.Project; @@ -54,7 +56,6 @@ import org.gradle.api.file.DirectoryProperty; import org.junit.Test; import org.mockito.Mockito; -/** Test cases for {@link VariantDslInfo}. */ public class VariantDslInfoTest { private DefaultConfig defaultConfig; @@ -75,7 +76,7 @@ public class VariantDslInfoTest { SigningConfig override = signingConfig("override"); override.storePassword("override"); - VariantDslInfo variant = getVariant(override); + ApplicationVariantDslInfo variant = getVariant(override); assertThat(variant.getSigningConfig()).isEqualTo(override); } @@ -92,7 +93,7 @@ public class VariantDslInfoTest { SigningConfig override = signingConfig("override"); override.storePassword("override"); - VariantDslInfo variant = getVariant(override); + ApplicationVariantDslInfo variant = getVariant(override); assertThat(variant.getSigningConfig()).isEqualTo(override); } @@ -104,7 +105,7 @@ public class VariantDslInfoTest { AndroidVersion minSdkVersion = new MutableAndroidVersion(5); defaultConfig.setMinSdkVersion(minSdkVersion.getApiLevel()); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion()).isEqualTo(minSdkVersion); } @@ -119,7 +120,7 @@ public class VariantDslInfoTest { assertThat(defaultConfig.getMinSdk()).isEqualTo(5); assertThat(defaultConfig.getMinSdkPreview()).isNull(); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion()) .isEqualTo( @@ -137,7 +138,7 @@ public class VariantDslInfoTest { assertThat(defaultConfig.getMinSdk()).isEqualTo(25); assertThat(defaultConfig.getMinSdkPreview()).isEqualTo("O"); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion()) .isEqualTo( @@ -149,7 +150,7 @@ public class VariantDslInfoTest { public void testGetMinSdkVersionDefault() { initNoDeviceApiInjection(); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion()).isEqualTo(new MutableAndroidVersion(1)); } @@ -163,7 +164,7 @@ public class VariantDslInfoTest { assertThat(defaultConfig.getTargetSdk()).isEqualTo(5); assertThat(defaultConfig.getTargetSdkPreview()).isNull(); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getTargetSdkVersion()).isEqualTo(targetSdkVersion); } @@ -178,7 +179,7 @@ public class VariantDslInfoTest { assertThat(defaultConfig.getTargetSdk()).isEqualTo(25); assertThat(defaultConfig.getTargetSdkPreview()).isEqualTo("O"); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getTargetSdkVersion()).isEqualTo(targetSdkVersion); } @@ -190,7 +191,7 @@ public class VariantDslInfoTest { MutableAndroidVersion targetSdkVersion = new MutableAndroidVersion(9); defaultConfig.setTargetSdkVersion(targetSdkVersion.getApiLevel()); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getTargetSdkVersion()).isEqualTo(targetSdkVersion); } @@ -199,7 +200,7 @@ public class VariantDslInfoTest { public void testGetTargetSdkVersionDefault() { initNoDeviceApiInjection(); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getTargetSdkVersion()).isNull(); } @@ -213,7 +214,7 @@ public class VariantDslInfoTest { buildType.setMultiDexEnabled(true); buildType.setDebuggable(false); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion().getApiLevel()).isEqualTo(16); assertThat(variant.getTargetDeployApiFromIDE()).isEqualTo(18); @@ -228,7 +229,7 @@ public class VariantDslInfoTest { buildType.setMultiDexEnabled(false); buildType.setDebuggable(true); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion().getApiLevel()).isEqualTo(16); assertThat(variant.getTargetDeployApiFromIDE()).isEqualTo(18); @@ -243,7 +244,7 @@ public class VariantDslInfoTest { buildType.setMultiDexEnabled(true); buildType.setDebuggable(true); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion().getApiLevel()).isEqualTo(16); assertThat(variant.getTargetDeployApiFromIDE()).isEqualTo(18); @@ -258,7 +259,7 @@ public class VariantDslInfoTest { buildType.setMultiDexEnabled(true); buildType.setDebuggable(true); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getMinSdkVersion().getApiLevel()).isEqualTo(16); assertThat(variant.getTargetDeployApiFromIDE()).isEqualTo(22); @@ -271,23 +272,27 @@ public class VariantDslInfoTest { defaultConfig.applicationId("com.example.mapp"); buildType.applicationIdSuffix(""); - VariantDslInfo variant = getVariant(); + ApplicationVariantDslInfo variant = getVariant(); assertThat(variant.getApplicationId().get()).isEqualTo("com.example.mapp"); } - private VariantDslInfo getVariant() { + private ApplicationVariantDslInfo getVariant() { return createVariant(null /*signingOverride*/); } - private VariantDslInfo getVariant(SigningConfig signingOverride) { + private ApplicationVariantDslInfo getVariant(SigningConfig signingOverride) { return createVariant(signingOverride /*signingOverride*/); } - private VariantDslInfo createVariant(SigningConfig signingOverride) { + private ApplicationVariantDslInfo createVariant(SigningConfig signingOverride) { + + InternalApplicationExtension extension = Mockito.mock(InternalApplicationExtension.class); + Mockito.when(extension.getPublishing()) + .thenReturn(Mockito.mock(ApplicationPublishingImpl.class)); List<Pair<String, String>> flavors = ImmutableList.of(new Pair<>("dimension1", "flavor")); - VariantDslInfoBuilder<?, ?> builder = - VariantDslInfoBuilder.getBuilder( + DslInfoBuilder<?, ApplicationVariantDslInfo> builder = + DslInfoBuilder.getBuilder( new DimensionCombinationImpl("debug", flavors), ComponentTypeImpl.BASE_APK, defaultConfig, @@ -296,17 +301,15 @@ public class VariantDslInfoTest { new MockSourceProvider("debug"), signingOverride, Mockito.mock(LazyManifestParser.class), - dslServices, variantServices, Mockito.mock(BaseExtension.class), - Mockito.mock(CommonExtension.class), - false, - Collections.emptyMap(), - null /* testFixtureMainVariantName */); + extension, + Mockito.mock(DirectoryProperty.class), + dslServices); builder.addProductFlavor(flavorConfig, new MockSourceProvider("custom")); - return (VariantDslInfo) builder.createVariantDslInfo(Mockito.mock(DirectoryProperty.class)); + return builder.createDslInfo(); } private void initWithInjectedDeviceApi(int deviceApi) { diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest2.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/dsl/info/VariantDslInfoTest2.kt index a66d8a3d86..e56bb27e21 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/VariantDslInfoTest2.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/core/dsl/info/VariantDslInfoTest2.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2022 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. @@ -14,19 +14,22 @@ * limitations under the License. */ -package com.android.build.gradle.internal.core +package com.android.build.gradle.internal.core.dsl.info -import com.android.build.api.dsl.BuildFeatures -import com.android.build.api.dsl.CommonExtension -import com.android.build.api.dsl.TestedExtension import com.android.build.api.variant.ComponentIdentity -import com.android.build.gradle.BaseExtension import com.android.build.gradle.internal.VariantManager +import com.android.build.gradle.internal.core.dsl.AndroidTestComponentDslInfo +import com.android.build.gradle.internal.core.dsl.ApplicationVariantDslInfo +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo +import com.android.build.gradle.internal.core.dsl.impl.AndroidTestComponentDslInfoImpl +import com.android.build.gradle.internal.core.dsl.impl.ApplicationVariantDslInfoImpl import com.android.build.gradle.internal.dsl.BuildType import com.android.build.gradle.internal.dsl.DefaultConfig +import com.android.build.gradle.internal.dsl.InternalApplicationExtension import com.android.build.gradle.internal.dsl.ProductFlavor import com.android.build.gradle.internal.manifest.ManifestData import com.android.build.gradle.internal.manifest.ManifestDataProvider +import com.android.build.gradle.internal.publishing.VariantPublishingInfo import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.internal.services.ProjectServices import com.android.build.gradle.internal.services.createDslServices @@ -276,27 +279,6 @@ class VariantDslInfoTest2 : } @Test - fun `instrumentationRunner on non test`() { - given { - // no specific manifest info - manifestData { } - } - - // provide a custom convert action to only call VariantDslInfo.instrumentationRunner - // as it's not normally called for non-test variant type. - convertToResult { - instrumentationRunner = it.getInstrumentationRunner(DexingType.NATIVE_MULTIDEX).orNull - } - - exceptionRule.expect(RuntimeException::class.java) - exceptionRule.expectMessage("instrumentationRunner is not available to non-test variant") - - expect { - // value is not relevant here since exception will be thrown - } - } - - @Test fun `instrumentationRunner from defaultConfig`() { given { // no specific manifest info @@ -395,27 +377,6 @@ class VariantDslInfoTest2 : } @Test - fun `handleProfiling on non test`() { - given { - // no specific manifest info - manifestData { } - } - - // provide a custom convert action to call VariantDslInfo.handleProfiling - // even though this is not a test componentType - convertToResult { - handleProfiling = it.handleProfiling.orNull - } - - exceptionRule.expect(RuntimeException::class.java) - exceptionRule.expectMessage("handleProfiling is not available to non-test variant") - - expect { - // value is not relevant here since exception will be thrown - } - } - - @Test fun `handleProfiling from defaultConfig`() { given { // no specific manifest info @@ -514,27 +475,6 @@ class VariantDslInfoTest2 : } @Test - fun `functionalTest on non test`() { - given { - // no specific manifest info - manifestData { } - } - - // provide a custom convert action to call VariantDslInfo.functionalTest - // even though this is not a test componentType - convertToResult { - functionalTest = it.functionalTest.orNull - } - - exceptionRule.expect(RuntimeException::class.java) - exceptionRule.expectMessage("functionalTest is not available to non-test variant") - - expect { - // value is not relevant here since exception will be thrown - } - } - - @Test fun `functionalTest from defaultConfig`() { given { // no specific manifest info @@ -859,28 +799,16 @@ class VariantDslInfoTest2 : override fun instantiateGiven() = GivenData(dslServices) override fun instantiateResult() = ResultData() - interface TestedFullExtension: CommonExtension< - BuildFeatures, - com.android.build.api.dsl.BuildType, - com.android.build.api.dsl.DefaultConfig, - com.android.build.api.dsl.ProductFlavor - >, TestedExtension - - override fun defaultWhen(given: GivenData): ResultData? { + override fun defaultWhen(given: GivenData): ResultData { val componentIdentity = Mockito.mock(ComponentIdentity::class.java) Mockito.`when`(componentIdentity.name).thenReturn("compIdName") - val extension = if (given.componentType.isTestComponent) { - Mockito.mock(TestedFullExtension::class.java).also { - Mockito.`when`(it.namespace).thenReturn(given.namespace) + val extension = Mockito.mock(InternalApplicationExtension::class.java).also { + Mockito.`when`(it.namespace).thenReturn(given.namespace) + if (given.componentType.isTestComponent) { Mockito.`when`(it.testNamespace).thenReturn(given.testNamespace) } - } else { - Mockito.mock(CommonExtension::class.java).also { - Mockito.`when`(it.namespace).thenReturn(given.namespace) - } } - val oldExtension = Mockito.mock(BaseExtension::class.java) // this does not quite test what VariantManager does because this only checks // for the product flavors of that one variant, while VariantManager looks @@ -889,72 +817,67 @@ class VariantDslInfoTest2 : given.flavors ) - val parentVariant = - if (given.componentType.isNestedComponent) { - VariantDslInfoImpl( + val mainVariant = ApplicationVariantDslInfoImpl( + componentIdentity = componentIdentity, + componentType = given.testedcomponentType, + defaultConfig = given.defaultConfig, + buildTypeObj = given.buildType, + productFlavorList = given.flavors, + dataProvider = DirectManifestDataProvider(given.manifestData, projectServices), + services = services, + buildDirectory = buildDirectory, + publishInfo = VariantPublishingInfo(emptyList()), + extension = extension, + oldExtension = null, + signingConfigOverride = null, + ) + + val dslInfo = when (given.componentType) { + ComponentTypeImpl.ANDROID_TEST -> { + AndroidTestComponentDslInfoImpl( componentIdentity = componentIdentity, componentType = given.testedcomponentType, defaultConfig = given.defaultConfig, buildTypeObj = given.buildType, productFlavorList = given.flavors, + dataProvider = DirectManifestDataProvider(given.testManifestData, projectServices), + testedVariantDslInfo = mainVariant, signingConfigOverride = null, - productionVariant = null, - dataProvider = DirectManifestDataProvider(given.manifestData, projectServices), - dslServices = dslServices, + inconsistentTestAppId = inconsistentTestAppId, services = services, buildDirectory = buildDirectory, - publishInfo = null, - experimentalProperties = mapOf(), - inconsistentTestAppId = false, extension = extension, - oldExtension = oldExtension + oldExtension = null ) - } else { null } - - val variantDslInfo = VariantDslInfoImpl( - componentIdentity = componentIdentity, - componentType = given.componentType, - defaultConfig = given.defaultConfig, - buildTypeObj = given.buildType, - productFlavorList = given.flavors, - signingConfigOverride = null, - productionVariant = parentVariant, - dataProvider = - if (given.componentType.isTestComponent) { - DirectManifestDataProvider(given.testManifestData, projectServices) - } else { - DirectManifestDataProvider(given.manifestData, projectServices) - }, - dslServices = dslServices, - services = services, - buildDirectory = buildDirectory, - experimentalProperties = mapOf(), - publishInfo = null, - inconsistentTestAppId = inconsistentTestAppId, - extension = extension, - oldExtension = oldExtension - ) + } + ComponentTypeImpl.BASE_APK -> { + mainVariant + } + else -> { + throw RuntimeException("Unexpected type") + } + } return instantiateResult().also { if (convertAction != null) { - convertAction?.invoke(it, variantDslInfo) + convertAction?.invoke(it, dslInfo) } else { - it.versionCode = variantDslInfo.versionCode.orNull - it.versionName = variantDslInfo.versionName.orNull + it.versionCode = (dslInfo as? ApplicationVariantDslInfo)?.versionCode?.orNull + it.versionName = (dslInfo as? ApplicationVariantDslInfo)?.versionName?.orNull // only query these if this is not a test. - if (given.componentType.isForTesting) { - it.instrumentationRunner = variantDslInfo.getInstrumentationRunner(given.dexingType).orNull - it.handleProfiling = variantDslInfo.handleProfiling.get() - it.functionalTest = variantDslInfo.functionalTest.get() + if (dslInfo is AndroidTestComponentDslInfo) { + it.instrumentationRunner = dslInfo.getInstrumentationRunner(given.dexingType).orNull + it.handleProfiling = dslInfo.handleProfiling.get() + it.functionalTest = dslInfo.functionalTest.get() } try { - it.namespace = variantDslInfo.namespace.orNull + it.namespace = dslInfo.namespace.orNull } catch (e: RuntimeException) { // RuntimeException can be thrown when ManifestData.packageName is null it.namespace = null } try { - it.namespaceForR = variantDslInfo.namespaceForR.orNull + it.namespaceForR = (dslInfo as? AndroidTestComponentDslInfo)?.namespaceForR?.orNull } catch (e: RuntimeException) { // RuntimeException can be thrown when ManifestData.packageName is null it.namespaceForR = null @@ -974,14 +897,14 @@ class VariantDslInfoTest2 : } /** optional conversion action from variantDslInfo to result Builder. */ - private var convertAction: (ResultData.(variantInfo: VariantDslInfo) -> Unit)? = null + private var convertAction: (ResultData.(variantInfo: ComponentDslInfo) -> Unit)? = null /** * registers a custom conversion from variantDslInfo to ResultBuilder. * This avoid having to use when {} which requires implementing all that defaultWhen() * does. */ - private fun convertToResult(action: ResultData.(variantInfo: VariantDslInfo) -> Unit) { + private fun convertToResult(action: ResultData.(variantInfo: ComponentDslInfo) -> Unit) { convertAction = action } diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/services/LintParallelBuildServiceTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/services/LintParallelBuildServiceTest.kt new file mode 100644 index 0000000000..6fde02c568 --- /dev/null +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/services/LintParallelBuildServiceTest.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 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.services + +import com.android.build.gradle.options.BooleanOption +import com.android.build.gradle.options.ProjectOptions +import com.android.build.gradle.options.StringOption +import com.google.common.truth.Truth +import kotlin.test.fail +import org.junit.Rule +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule + +/** Unit tests for [LintParallelBuildService] */ +class LintParallelBuildServiceTest { + + @get:Rule + val rule: MockitoRule = MockitoJUnit.rule() + + @Mock + lateinit var projectOptions: ProjectOptions + + @Test fun testCalculateMaxParallelUsages() { + // first test in process cases + Mockito.`when`(projectOptions.get(BooleanOption.RUN_LINT_IN_PROCESS)).thenReturn(true) + + // Check normal case + Truth.assertThat( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 20 * GB, + totalPhysicalMemory = 40 * GB + ) + ).isEqualTo(30) + + // Check case when there's not enough memory, but should still return 1 + Truth.assertThat( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 0, + totalPhysicalMemory = 40 * GB + ) + ).isEqualTo(1) + + // then test out of process cases + Mockito.`when`(projectOptions.get(BooleanOption.RUN_LINT_IN_PROCESS)).thenReturn(false) + + // Check no specified lint heap size + Mockito.`when`(projectOptions.get(StringOption.LINT_HEAP_SIZE)).thenReturn(null) + Truth.assertThat( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 10 * GB, + totalPhysicalMemory = 40 * GB + ) + ).isEqualTo(2) + + // Check with specified lint heap size + Mockito.`when`(projectOptions.get(StringOption.LINT_HEAP_SIZE)).thenReturn("2g") + Truth.assertThat( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 10 * GB, + totalPhysicalMemory = 40 * GB + ) + ).isEqualTo(18) + + // Check case when there's not enough memory, but should still return 1 + Truth.assertThat( + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 1 * GB, + totalPhysicalMemory = 1 * GB + ) + ).isEqualTo(1) + + // Check case when user specifies invalid lint heap size + Mockito.`when`(projectOptions.get(StringOption.LINT_HEAP_SIZE)).thenReturn("invalid") + try { + LintParallelBuildService.calculateMaxParallelUsages( + projectOptions, + maxRuntimeMemory = 1 * GB, + totalPhysicalMemory = 1 * GB + ) + fail("expected RuntimeException") + } catch (e: RuntimeException) { + Truth.assertThat(e.message) + .isEqualTo( + "Failed to parse ${StringOption.LINT_HEAP_SIZE.propertyName} \"invalid\"." + ) + } + } +} + +private const val GB = 1024 * 1024 * 1024L diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/AarMetadataTaskTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/AarMetadataTaskTest.kt index f43b85f83c..5bd21056fc 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/AarMetadataTaskTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/AarMetadataTaskTest.kt @@ -76,7 +76,7 @@ class AarMetadataTaskTest { task.minCompileSdk.set(28) task.minCompileSdkExtension.set(1) task.minAgpVersion.set("7.0.0") - task.forceCompileSdkPreview.set("Tiramisu") + task.forceCompileSdkPreview.set("TiramisuPrivacySandbox") task.taskAction() checkAarMetadataFile( @@ -86,7 +86,7 @@ class AarMetadataTaskTest { minCompileSdk = "28", minCompileSdkExtension = "1", minAgpVersion = "7.0.0", - compileSdkPreview = "Tiramisu" + compileSdkPreview = "TiramisuPrivacySandbox" ) } 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 e7ba183ea0..a76a66b8dc 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 @@ -447,7 +447,7 @@ class CheckAarMetadataTaskTest { minCompileSdk = 28, minCompileSdkExtension = 0, minAgpVersion = "3.0.0", - forceCompileSdkPreview = "Tiramisu" + forceCompileSdkPreview = "TiramisuPrivacySandbox" ) }, identifier = FakeComponentIdentifier("displayName") @@ -468,13 +468,13 @@ class CheckAarMetadataTaskTest { An issue was found when checking AAR metadata: 1. Dependency 'displayName' requires libraries and applications that - depend on it to compile against codename "Tiramisu" of the + depend on it to compile against codename "TiramisuPrivacySandbox" of the Android APIs. :app is currently compiled against android-28. Recommended action: Use a different version of dependency 'displayName', - or set compileSdkPreview to "Tiramisu" in your build.gradle + or set compileSdkPreview to "TiramisuPrivacySandbox" in your build.gradle file if you intend to experiment with that preview SDK. """.trimIndent() ) diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/TaskMethodModifiersAndAnnotationsTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/TaskMethodModifiersAndAnnotationsTest.kt index c283e00014..91cfc37d3d 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/TaskMethodModifiersAndAnnotationsTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/tasks/TaskMethodModifiersAndAnnotationsTest.kt @@ -16,7 +16,7 @@ package com.android.build.gradle.internal.tasks -import com.android.build.gradle.internal.core.VariantDslInfo +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo import com.android.build.gradle.tasks.PackageAndroidArtifact import com.android.ide.common.workers.WorkerExecutorFacade import com.google.common.reflect.ClassPath @@ -183,7 +183,7 @@ class TaskMethodModifiersAndAnnotationsTest { @Test fun checkVariantConfigurationIsNotAField() { - Truth.assertThat(findTaskFieldsOfType(VariantDslInfo::class.java)).isEmpty() + Truth.assertThat(findTaskFieldsOfType(ComponentDslInfo::class.java)).isEmpty() } @Test diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/variant/VariantPathHelperTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/variant/VariantPathHelperTest.kt index 20b4cff3a8..db89949f56 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/variant/VariantPathHelperTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/internal/variant/VariantPathHelperTest.kt @@ -16,9 +16,7 @@ package com.android.build.gradle.internal.variant -import com.android.build.api.dsl.BuildType -import com.android.build.gradle.internal.core.VariantDslInfo -import com.android.build.gradle.internal.core.VariantDslInfoImpl +import com.android.build.gradle.internal.core.dsl.ComponentDslInfo import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.options.BooleanOption import com.android.build.gradle.options.IntegerOption @@ -33,7 +31,6 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito import org.mockito.Mockito.`when` import org.mockito.Mockito.doReturn import org.mockito.junit.MockitoJUnit @@ -52,7 +49,7 @@ internal class VariantPathHelperTest { } @Mock - lateinit var variantDslInfo: VariantDslInfoImpl + lateinit var variantDslInfo: ComponentDslInfo @Mock lateinit var dslServices: DslServices @@ -65,9 +62,7 @@ internal class VariantPathHelperTest { `when`(dslServices.projectOptions).thenReturn(projectOptions) `when`(variantDslInfo.componentType).thenReturn(ComponentTypeImpl.LIBRARY) `when`(variantDslInfo.productFlavorList).thenReturn(emptyList()) - val buildType = Mockito.mock(BuildType::class.java) - `when`(buildType.name).thenReturn("apk_location") - `when`(variantDslInfo.buildTypeObj).thenReturn(buildType) + `when`(variantDslInfo.buildType).thenReturn("apk_location") } @Test diff --git a/build-system/gradle-core/src/test/java/com/android/build/gradle/tasks/BuildAnalyzerTest.kt b/build-system/gradle-core/src/test/java/com/android/build/gradle/tasks/BuildAnalyzerTest.kt index 67c79d76e2..1ba8a8d57b 100644 --- a/build-system/gradle-core/src/test/java/com/android/build/gradle/tasks/BuildAnalyzerTest.kt +++ b/build-system/gradle-core/src/test/java/com/android/build/gradle/tasks/BuildAnalyzerTest.kt @@ -16,132 +16,18 @@ package com.android.build.gradle.tasks -import com.android.build.gradle.internal.coverage.JacocoReportTask -import com.android.build.gradle.internal.lint.AndroidLintAnalysisTask -import com.android.build.gradle.internal.lint.AndroidLintCopyReportTask -import com.android.build.gradle.internal.lint.AndroidLintGlobalTask -import com.android.build.gradle.internal.lint.AndroidLintTask -import com.android.build.gradle.internal.lint.AndroidLintTextOutputTask -import com.android.build.gradle.internal.lint.LintModelWriterTask -import com.android.build.gradle.internal.pipeline.IncrementalTransformTask -import com.android.build.gradle.internal.pipeline.NonIncrementalTransformTask -import com.android.build.gradle.internal.pipeline.StreamBasedTask -import com.android.build.gradle.internal.pipeline.TransformTask -import com.android.build.gradle.internal.res.GenerateApiPublicTxtTask -import com.android.build.gradle.internal.res.GenerateEmptyResourceFilesTask -import com.android.build.gradle.internal.res.GenerateLibraryRFileTask -import com.android.build.gradle.internal.res.LinkAndroidResForBundleTask -import com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask -import com.android.build.gradle.internal.res.ParseLibraryResourcesTask -import com.android.build.gradle.internal.res.PrivacySandboxSdkLinkAndroidResourcesTask -import com.android.build.gradle.internal.res.namespaced.CreateNonNamespacedLibraryManifestTask -import com.android.build.gradle.internal.res.namespaced.GenerateNamespacedLibraryRFilesTask -import com.android.build.gradle.internal.res.namespaced.LinkLibraryAndroidResourcesTask -import com.android.build.gradle.internal.res.namespaced.ProcessAndroidAppResourcesTask -import com.android.build.gradle.internal.res.namespaced.StaticLibraryManifestTask -import com.android.build.gradle.internal.tasks.AarMetadataTask -import com.android.build.gradle.internal.tasks.AndroidReportTask -import com.android.build.gradle.internal.tasks.ApkZipPackagingTask -import com.android.build.gradle.internal.tasks.AppClasspathCheckTask -import com.android.build.gradle.internal.tasks.AppMetadataTask -import com.android.build.gradle.internal.tasks.ApplicationIdWriterTask -import com.android.build.gradle.internal.tasks.AssetPackManifestGenerationTask -import com.android.build.gradle.internal.tasks.AssetPackPreBundleTask +import com.android.build.gradle.internal.tasks.AnalyticsRecordingTask +import com.android.build.gradle.internal.tasks.AndroidVariantTask +import com.android.build.gradle.internal.tasks.AppPreBuildTask +import com.android.build.gradle.internal.tasks.BaseTask import com.android.build.gradle.internal.tasks.BuildAnalyzer -import com.android.build.gradle.internal.tasks.BundleLibraryJavaRes -import com.android.build.gradle.internal.tasks.BundleReportDependenciesTask -import com.android.build.gradle.internal.tasks.BundleToApkTask -import com.android.build.gradle.internal.tasks.BundleToStandaloneApkTask -import com.android.build.gradle.internal.tasks.CheckAarMetadataTask -import com.android.build.gradle.internal.tasks.CheckDuplicateClassesTask -import com.android.build.gradle.internal.tasks.CheckJetifierTask -import com.android.build.gradle.internal.tasks.CheckManifest -import com.android.build.gradle.internal.tasks.CheckMultiApkLibrariesTask -import com.android.build.gradle.internal.tasks.CheckProguardFiles -import com.android.build.gradle.internal.tasks.ClasspathComparisonTask -import com.android.build.gradle.internal.tasks.CompileArtProfileTask -import com.android.build.gradle.internal.tasks.CompressAssetsTask -import com.android.build.gradle.internal.tasks.D8BundleMainDexListTask -import com.android.build.gradle.internal.tasks.DependencyReportTask -import com.android.build.gradle.internal.tasks.DesugarLibKeepRulesMergeTask -import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask -import com.android.build.gradle.internal.tasks.DeviceSerialTestTask -import com.android.build.gradle.internal.tasks.DexArchiveBuilderTask -import com.android.build.gradle.internal.tasks.DexFileDependenciesTask -import com.android.build.gradle.internal.tasks.DexMergingTask -import com.android.build.gradle.internal.tasks.ExportConsumerProguardFilesTask -import com.android.build.gradle.internal.tasks.ExtractApksTask -import com.android.build.gradle.internal.tasks.ExtractNativeDebugMetadataTask -import com.android.build.gradle.internal.tasks.ExtractProfilerNativeDependenciesTask -import com.android.build.gradle.internal.tasks.ExtractProguardFiles -import com.android.build.gradle.internal.tasks.FeatureDexMergeTask -import com.android.build.gradle.internal.tasks.FinalizeBundleTask -import com.android.build.gradle.internal.tasks.GenerateApkDataTask -import com.android.build.gradle.internal.tasks.GenerateLibraryProguardRulesTask -import com.android.build.gradle.internal.tasks.InstallVariantTask -import com.android.build.gradle.internal.tasks.InstallVariantViaBundleTask -import com.android.build.gradle.internal.tasks.JacocoTask -import com.android.build.gradle.internal.tasks.L8DexDesugarLibTask -import com.android.build.gradle.internal.tasks.LibraryJniLibsTask -import com.android.build.gradle.internal.tasks.LinkManifestForAssetPackTask -import com.android.build.gradle.internal.tasks.LintCompile -import com.android.build.gradle.internal.tasks.LintModelMetadataTask -import com.android.build.gradle.internal.tasks.ListingFileRedirectTask -import com.android.build.gradle.internal.tasks.ManagedDeviceInstrumentationTestResultAggregationTask -import com.android.build.gradle.internal.tasks.ManagedDeviceInstrumentationTestTask -import com.android.build.gradle.internal.tasks.MergeArtProfileTask -import com.android.build.gradle.internal.tasks.MergeConsumerProguardFilesTask -import com.android.build.gradle.internal.tasks.MergeJavaResourceTask -import com.android.build.gradle.internal.tasks.MergeNativeDebugMetadataTask -import com.android.build.gradle.internal.tasks.MergeNativeLibsTask -import com.android.build.gradle.internal.tasks.ModuleMetadataWriterTask -import com.android.build.gradle.internal.tasks.OptimizeResourcesTask -import com.android.build.gradle.internal.tasks.PackageBundleTask -import com.android.build.gradle.internal.tasks.PackageForUnitTest -import com.android.build.gradle.internal.tasks.PackageRenderscriptTask -import com.android.build.gradle.internal.tasks.ParseIntegrityConfigTask -import com.android.build.gradle.internal.tasks.PerModuleBundleTask -import com.android.build.gradle.internal.tasks.PerModuleReportDependenciesTask -import com.android.build.gradle.internal.tasks.PrepareLintJarForPublish -import com.android.build.gradle.internal.tasks.ProcessAssetPackManifestTask -import com.android.build.gradle.internal.tasks.ProcessJavaResTask -import com.android.build.gradle.internal.tasks.ProguardConfigurableTask -import com.android.build.gradle.internal.tasks.R8Task -import com.android.build.gradle.internal.tasks.RecalculateStackFramesTask -import com.android.build.gradle.internal.tasks.SdkDependencyDataGeneratorTask -import com.android.build.gradle.internal.tasks.ShrinkResourcesOldShrinkerTask -import com.android.build.gradle.internal.tasks.SigningConfigVersionsWriterTask -import com.android.build.gradle.internal.tasks.SigningConfigWriterTask -import com.android.build.gradle.internal.tasks.SigningReportTask -import com.android.build.gradle.internal.tasks.SourceSetsTask -import com.android.build.gradle.internal.tasks.StripDebugSymbolsTask -import com.android.build.gradle.internal.tasks.TestServerTask -import com.android.build.gradle.internal.tasks.UninstallTask -import com.android.build.gradle.internal.tasks.UnsafeOutputsTask -import com.android.build.gradle.internal.tasks.ValidateSigningTask -import com.android.build.gradle.internal.tasks.databinding.DataBindingExportFeatureInfoTask -import com.android.build.gradle.internal.tasks.databinding.DataBindingExportFeatureNamespacesTask -import com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask -import com.android.build.gradle.internal.tasks.databinding.DataBindingMergeDependencyArtifactsTask -import com.android.build.gradle.internal.tasks.databinding.DataBindingTriggerTask -import com.android.build.gradle.internal.tasks.featuresplit.FeatureNameWriterTask -import com.android.build.gradle.internal.tasks.featuresplit.FeatureSetMetadataWriterTask -import com.android.build.gradle.internal.tasks.featuresplit.FeatureSplitDeclarationWriterTask -import com.android.build.gradle.internal.tasks.featuresplit.PackagedDependenciesWriterTask -import com.android.build.gradle.internal.tasks.mlkit.GenerateMlModelClass -import com.android.build.gradle.internal.transforms.LegacyShrinkBundleModuleResourcesTask -import com.android.build.gradle.internal.transforms.ShrinkAppBundleResourcesTask -import com.android.build.gradle.internal.transforms.ShrinkResourcesNewShrinkerTask -import com.android.build.gradle.tasks.factory.AndroidUnitTest -import com.android.build.gradle.tasks.sync.AbstractVariantModelTask -import com.android.build.gradle.tasks.sync.AndroidTestVariantModelTask -import com.android.build.gradle.tasks.sync.ApplicationVariantModelTask -import com.android.build.gradle.tasks.sync.DynamicFeatureVariantModelTask -import com.android.build.gradle.tasks.sync.LibraryVariantModelTask -import com.android.build.gradle.tasks.sync.ModuleVariantModelTask -import com.android.build.gradle.tasks.sync.TestModuleVariantModelTask -import com.android.build.gradle.tasks.sync.TestVariantModelTask -import com.android.build.gradle.tasks.sync.UnitTestVariantModelTask +import com.android.build.gradle.internal.tasks.GeneratePrivacySandboxSdkRuntimeConfigFile +import com.android.build.gradle.internal.tasks.NewIncrementalTask +import com.android.build.gradle.internal.tasks.NonIncrementalGlobalTask +import com.android.build.gradle.internal.tasks.NonIncrementalTask +import com.android.build.gradle.internal.tasks.TestPreBuildTask +import com.android.build.gradle.tasks.sync.AppIdListTask +import com.android.ide.common.attribution.TaskCategoryLabel import org.gradle.api.Task import com.google.common.reflect.ClassPath import com.google.common.reflect.TypeToken @@ -152,196 +38,49 @@ import kotlin.test.assertEquals class BuildAnalyzerTest { @Test - fun `all tasks have build analyzer annotations`() { + fun `all tasks have build analyzer annotations unless in allow-list`() { val allTasks = getAllTasks() - // When annotations for all tasks are added, - // can just assert missingTasks is empty - val missingTasks = allTasks.filter { + val actualTasksWithoutAnnotations = allTasks.filter { !it.isAnnotationPresent(BuildAnalyzer::class.java) } - val tasksWithAnnotations = allTasks.filter { + // Make sure a task was not added twice in allow-list + assertEquals(expectedTasksWithoutAnnotations.toSet().size, expectedTasksWithoutAnnotations.size) + // Tasks without annotations has to be added into allow-list, otherwise it needs annotation + assertThat(actualTasksWithoutAnnotations).containsExactlyElementsIn(expectedTasksWithoutAnnotations) + } + + @Test + fun `build analyzer annotated tasks does not have unallowed labels`() { + val allTasks = getAllTasks() + val unallowedLabels = listOf(TaskCategoryLabel.GRADLE, + TaskCategoryLabel.MISC, TaskCategoryLabel.UNKNOWN) + val tasksWithUnallowedLabels = allTasks.filter { it.isAnnotationPresent(BuildAnalyzer::class.java) + }.filter { clazz -> + clazz.getAnnotation(BuildAnalyzer::class.java).taskCategoryLabels.any{ it in unallowedLabels } } - // Make sure a task was not added twice in list - assertEquals(TASKS_WITH_ANNOTATIONS.toSet().size, TASKS_WITH_ANNOTATIONS.size) - // Make sure tasks without annotation weren't accidentally added in - assertThat(missingTasks).containsNoneIn(TASKS_WITH_ANNOTATIONS) - assertThat(tasksWithAnnotations).containsExactlyElementsIn(TASKS_WITH_ANNOTATIONS) - assertEquals(allTasks.size,missingTasks.size + TASKS_WITH_ANNOTATIONS.size) + assertThat(tasksWithUnallowedLabels).isEmpty() } - // List of tasks which has BuildAnalyzerAnnotation, added manually - private val TASKS_WITH_ANNOTATIONS = listOf( - AidlCompile::class.java, - JavaPreCompileTask::class.java, - CompileArtProfileTask::class.java, - LintCompile::class.java, - CompileLibraryResourcesTask::class.java, - RenderscriptCompile::class.java, - ShaderCompile::class.java, - AndroidReportTask::class.java, - AndroidUnitTest::class.java, - DeviceProviderInstrumentTestTask::class.java, - JacocoReportTask::class.java, - TestServerTask::class.java, - GenerateTestConfig::class.java, - PackageForUnitTest::class.java, - JacocoTask::class.java, - ManagedDeviceInstrumentationTestTask::class.java, - DeviceSerialTestTask::class.java, - ManagedDeviceInstrumentationTestResultAggregationTask::class.java, - CheckManifest::class.java, - CompatibleScreensManifest::class.java, - InvokeManifestMerger::class.java, - ProcessApplicationManifest::class.java, - ProcessLibraryManifest::class.java, - ProcessTestManifest::class.java, - StaticLibraryManifestTask::class.java, - CreateNonNamespacedLibraryManifestTask::class.java, - ManifestProcessorTask::class.java, - AssetPackManifestGenerationTask::class.java, - ProcessAssetPackManifestTask::class.java, - LinkManifestForAssetPackTask::class.java, - ProcessManifestForBundleTask::class.java, - ProcessManifestForMetadataFeatureTask::class.java, - ProcessManifestForInstantAppTask::class.java, - ProcessPackagedManifestTask::class.java, - ProcessMultiApkApplicationManifest::class.java, - GenerateManifestJarTask::class.java, - LinkLibraryAndroidResourcesTask::class.java, - LinkApplicationAndroidResourcesTask::class.java, - LinkAndroidResForBundleTask::class.java, - GenerateResValues::class.java, - MergeResources::class.java, - VerifyLibraryResourcesTask::class.java, - ProcessAndroidAppResourcesTask::class.java, - GenerateLibraryRFileTask::class.java, - GenerateNamespacedLibraryRFilesTask::class.java, - LegacyShrinkBundleModuleResourcesTask::class.java, - ParseLibraryResourcesTask::class.java, - ExtractDeepLinksTask::class.java, - ShrinkResourcesOldShrinkerTask::class.java, - GenerateEmptyResourceFilesTask::class.java, - OptimizeResourcesTask::class.java, - ShrinkAppBundleResourcesTask::class.java, - ShrinkResourcesNewShrinkerTask::class.java, - PrivacySandboxSdkLinkAndroidResourcesTask::class.java, - ExternalNativeBuildJsonTask::class.java, - ExternalNativeBuildTask::class.java, - ExternalNativeCleanTask::class.java, - MergeNativeLibsTask::class.java, - StripDebugSymbolsTask::class.java, - LibraryJniLibsTask::class.java, - ExtractNativeDebugMetadataTask::class.java, - MergeNativeDebugMetadataTask::class.java, - PrefabPackageTask::class.java, - PrefabPackageConfigurationTask::class.java, - ProcessJavaResTask::class.java, - BundleLibraryJavaRes::class.java, - MergeJavaResourceTask::class.java, - JavaDocGenerationTask::class.java, - JavaDocJarTask::class.java, - PackageRenderscriptTask::class.java, - DexMergingTask::class.java, - DexFileDependenciesTask::class.java, - DexArchiveBuilderTask::class.java, - L8DexDesugarLibTask::class.java, - D8BundleMainDexListTask::class.java, - FeatureDexMergeTask::class.java, - PrivacySandboxSdkDexTask::class.java, - PrivacySandboxSdkMergeDexTask::class.java, - MergeArtProfileTask::class.java, - ProcessLibraryArtProfileTask::class.java, - PrepareLintJarForPublish::class.java, - LintModelWriterTask::class.java, - AndroidLintTask::class.java, - AndroidLintGlobalTask::class.java, - AndroidLintCopyReportTask::class.java, - AndroidLintAnalysisTask::class.java, - LintModelMetadataTask::class.java, - AndroidLintTextOutputTask::class.java, - DataBindingTriggerTask::class.java, - DataBindingGenBaseClassesTask::class.java, - DataBindingExportFeatureNamespacesTask::class.java, - DataBindingExportFeatureInfoTask::class.java, - DataBindingMergeDependencyArtifactsTask::class.java, - GenerateApkDataTask::class.java, - FeatureSplitDeclarationWriterTask::class.java, - ModuleMetadataWriterTask::class.java, - FeatureSetMetadataWriterTask::class.java, - ApplicationIdWriterTask::class.java, - ParseIntegrityConfigTask::class.java, - FeatureNameWriterTask::class.java, - SdkDependencyDataGeneratorTask::class.java, - AarMetadataTask::class.java, - CheckAarMetadataTask::class.java, - GenerateApiPublicTxtTask::class.java, - AppMetadataTask::class.java, - SigningConfigVersionsWriterTask::class.java, - ListingFileRedirectTask::class.java, - ApplicationVariantModelTask::class.java, - AbstractVariantModelTask::class.java, - LibraryVariantModelTask::class.java, - DynamicFeatureVariantModelTask::class.java, - AndroidTestVariantModelTask::class.java, - TestVariantModelTask::class.java, - UnitTestVariantModelTask::class.java, - ModuleVariantModelTask::class.java, - TestModuleVariantModelTask::class.java, - InstallVariantTask::class.java, - UninstallTask::class.java, - InstallVariantViaBundleTask::class.java, - DependencyReportTask::class.java, - SigningReportTask::class.java, - SourceSetsTask::class.java, - PackagedDependenciesWriterTask::class.java, - AnalyzeDependenciesTask::class.java, - ClasspathComparisonTask::class.java, - UnsafeOutputsTask::class.java, - PackageApplication::class.java, - ExtractApksTask::class.java, - BundleToApkTask::class.java, - BundleToStandaloneApkTask::class.java, - SigningConfigWriterTask::class.java, - ApkZipPackagingTask::class.java, - BundleAar::class.java, - FusedLibraryBundleAar::class.java, - PackageBundleTask::class.java, - PerModuleBundleTask::class.java, - FinalizeBundleTask::class.java, - BundleReportDependenciesTask::class.java, - PerModuleReportDependenciesTask::class.java, - AssetPackPreBundleTask::class.java, - PackagePrivacySandboxSdkBundle::class.java, - ValidateSigningTask::class.java, - CheckTestedAppObfuscation::class.java, - CheckMultiApkLibrariesTask::class.java, - AppClasspathCheckTask::class.java, - CheckDuplicateClassesTask::class.java, - CheckJetifierTask::class.java, - ExtractProguardFiles::class.java, - CheckProguardFiles::class.java, - MergeConsumerProguardFilesTask::class.java, - GenerateLibraryProguardRulesTask::class.java, - ProguardConfigurableTask::class.java, - ExportConsumerProguardFilesTask::class.java, - R8Task::class.java, - CompressAssetsTask::class.java, - GenerateBuildConfig::class.java, - GenerateMlModelClass::class.java, - PrivacySandboxSdkManifestGeneratorTask::class.java, - ExtractAnnotations::class.java, - MergeSourceSetFolders::class.java, - StreamBasedTask::class.java, - TransformTask::class.java, - RecalculateStackFramesTask::class.java, - ExtractProfilerNativeDependenciesTask::class.java, - TransformClassesWithAsmTask::class.java, - DesugarLibKeepRulesMergeTask::class.java, - FusedLibraryClassesRewriteTask::class.java, - IncrementalTransformTask::class.java, - NonIncrementalTransformTask::class.java, - ) as List<Class<*>> + // Allow-list of tasks that are defined to not have annotations. + // Usually due to it being a base task, and hence is implemented by other tasks. + // Another reason is that it does not fall into any TaskCategoryLabel, + // and the task will not show up in Build Analyzer anyway. + private val expectedTasksWithoutAnnotations = listOf( + AppPreBuildTask::class.java, + TestPreBuildTask::class.java, + AndroidVariantTask::class.java, + NewIncrementalTask::class.java, + NonIncrementalTask::class.java, + PackageAndroidArtifact::class.java, + BaseTask::class.java, + NonIncrementalGlobalTask::class.java, + AnalyticsRecordingTask::class.java, + BuildPrivacySandboxSdkApks::class.java, + GeneratePrivacySandboxAsar::class.java, + GeneratePrivacySandboxSdkRuntimeConfigFile::class.java, + AppIdListTask::class.java + ) private fun getAllTasks(): List<Class<*>> { val classPath = ClassPath.from(this.javaClass.classLoader) diff --git a/build-system/gradle-core/src/test/resources/com/android/build/gradle/pseudo-api.txt b/build-system/gradle-core/src/test/resources/com/android/build/gradle/pseudo-api.txt index 3f0aa7535e..f6a6a89641 100644 --- a/build-system/gradle-core/src/test/resources/com/android/build/gradle/pseudo-api.txt +++ b/build-system/gradle-core/src/test/resources/com/android/build/gradle/pseudo-api.txt @@ -1455,7 +1455,7 @@ com.android.build.gradle.internal.dsl.ExternalNativeNdkBuildOptions.setcFlags: v com.android.build.gradle.internal.dsl.ExternalNativeNdkBuildOptions.targets: void (java.lang.String[]) com.android.build.gradle.internal.dsl.InitWithUtilKt com.android.build.gradle.internal.dsl.InitWithUtilKt.initExtensions: void (org.gradle.api.plugins.ExtensionAware, org.gradle.api.plugins.ExtensionAware) -com.android.build.gradle.internal.dsl.InternalApplicationExtension implements com.android.build.api.dsl.ApplicationExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension, com.android.build.gradle.internal.dsl.InternalCommonExtension +com.android.build.gradle.internal.dsl.InternalApplicationExtension implements com.android.build.api.dsl.ApplicationExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension com.android.build.gradle.internal.dsl.InternalApplicationExtension.bundle: void (org.gradle.api.Action<com.android.build.gradle.internal.dsl.BundleOptions>) com.android.build.gradle.internal.dsl.InternalApplicationExtension.dependenciesInfo: void (org.gradle.api.Action<com.android.build.api.dsl.DependenciesInfo>) com.android.build.gradle.internal.dsl.InternalApplicationExtension.getAssetPacks: java.util.Set<java.lang.String> () @@ -1502,8 +1502,8 @@ com.android.build.gradle.internal.dsl.InternalCommonExtension.splits: void (org. com.android.build.gradle.internal.dsl.InternalCommonExtension.testCoverage: void (org.gradle.api.Action<com.android.build.api.dsl.TestCoverage>) com.android.build.gradle.internal.dsl.InternalCommonExtension.testOptions: void (org.gradle.api.Action<com.android.build.gradle.internal.dsl.TestOptions>) com.android.build.gradle.internal.dsl.InternalCommonExtension.viewBinding: void (org.gradle.api.Action<com.android.build.gradle.internal.dsl.ViewBindingOptionsImpl>) -com.android.build.gradle.internal.dsl.InternalDynamicFeatureExtension implements com.android.build.api.dsl.DynamicFeatureExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension, com.android.build.gradle.internal.dsl.InternalCommonExtension -com.android.build.gradle.internal.dsl.InternalLibraryExtension implements com.android.build.api.dsl.LibraryExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension, com.android.build.gradle.internal.dsl.InternalCommonExtension +com.android.build.gradle.internal.dsl.InternalDynamicFeatureExtension implements com.android.build.api.dsl.DynamicFeatureExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension +com.android.build.gradle.internal.dsl.InternalLibraryExtension implements com.android.build.api.dsl.LibraryExtension, com.android.build.gradle.internal.dsl.InternalTestedExtension com.android.build.gradle.internal.dsl.InternalLibraryExtension.getAidlPackagedList: java.util.Collection<java.lang.String> () com.android.build.gradle.internal.dsl.InternalLibraryExtension.publishing: void (org.gradle.api.Action<com.android.build.api.dsl.LibraryPublishing>) com.android.build.gradle.internal.dsl.InternalLibraryExtension.setAidlPackagedList: void (java.util.Collection<java.lang.String>) @@ -1511,7 +1511,7 @@ com.android.build.gradle.internal.dsl.InternalPrivacySandboxSdkExtension impleme com.android.build.gradle.internal.dsl.InternalPrivacySandboxSdkExtension.bundle: void (org.gradle.api.Action<com.android.build.api.dsl.PrivacySandboxSdkBundle>) com.android.build.gradle.internal.dsl.InternalSigningConfig implements com.android.build.api.dsl.SigningConfig, com.android.build.api.dsl.ApkSigningConfig, org.gradle.api.Named, com.android.builder.model.SigningConfig com.android.build.gradle.internal.dsl.InternalTestExtension implements com.android.build.api.dsl.TestExtension, com.android.build.gradle.internal.dsl.InternalCommonExtension -com.android.build.gradle.internal.dsl.InternalTestedExtension implements com.android.build.api.dsl.TestedExtension +com.android.build.gradle.internal.dsl.InternalTestedExtension implements com.android.build.api.dsl.TestedExtension, com.android.build.gradle.internal.dsl.InternalCommonExtension com.android.build.gradle.internal.dsl.InternalTestedExtension.testFixtures: void (org.gradle.api.Action<com.android.build.api.dsl.TestFixtures>) com.android.build.gradle.internal.dsl.JavaCompileOptions implements com.android.build.gradle.api.JavaCompileOptions, com.android.build.api.dsl.JavaCompileOptions com.android.build.gradle.internal.dsl.JavaCompileOptions.<init>: com.android.build.gradle.internal.dsl.JavaCompileOptions () diff --git a/build-system/integration-test/application/BUILD.bazel b/build-system/integration-test/application/BUILD.bazel index 023e05c1b5..78657f4a74 100644 --- a/build-system/integration-test/application/BUILD.bazel +++ b/build-system/integration-test/application/BUILD.bazel @@ -49,7 +49,7 @@ OLD_SDKS = [ ] PREVIEW_SDKS = [ - "//prebuilts/studio/sdk:platforms/android-Tiramisu_build_only", + "//prebuilts/studio/sdk:platforms/android-TiramisuPrivacySandbox_build_only", ] #keep sorted diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/AarPublishTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/AarPublishTest.kt index 552d4b8bca..80e6ad83a0 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/AarPublishTest.kt +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/AarPublishTest.kt @@ -16,11 +16,15 @@ package com.android.build.gradle.integration.application +import com.android.SdkConstants import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.app.MinimalSubProject import com.android.build.gradle.integration.common.fixture.app.MultiModuleTestProject +import com.android.build.gradle.integration.common.fixture.testprojects.PluginType +import com.android.build.gradle.integration.common.fixture.testprojects.createGradleProject import com.android.build.gradle.options.BooleanOption import com.android.utils.FileUtils +import com.google.wireless.android.sdk.stats.GradleBuildProject import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -30,18 +34,30 @@ import java.util.zip.ZipFile /* * Tests to verify that AARs produced from library modules in build/output/aar are in a state -* which can be published e.g to public repository like Maven. +* which can be published +* e.g. to a public repository like Maven, AAR contains expected file structure. */ class AarPublishTest { @get:Rule - val project = GradleTestProject.builder().fromTestApp( - MultiModuleTestProject.builder() - .subproject( - ":library", MinimalSubProject.lib("com.example.library") - .appendToBuild("android.buildTypes.debug.testCoverageEnabled true") - ).build() - ).create() + val project = createGradleProject { + subProject(":library") { + plugins.add(PluginType.ANDROID_LIB) + android { + defaultCompileSdk() + namespace = "com.example.library" + buildTypes { + named("debug") { + testCoverageEnabled = true + } + } + addFile("src/main/res/values/strings.xml", + "<resources>\n" + + "<string name=\"one\">Some string</string>\n" + + "</resources>") + } + } + } @get:Rule val temporaryDirectory = TemporaryFolder() @@ -55,7 +71,6 @@ class AarPublishTest { val libraryPublishedAar = FileUtils.join(librarySubproject.outputDir, "aar", "library-debug.aar") val tempTestData = temporaryDirectory.newFolder("testData") - val buildConfigClasspath = "com/example/library/BuildConfig.class" val extractedJar = File(tempTestData, "classes.jar") // Extracts the zipped BuildConfig.class in library-debug.aar/classes.jar to // the extractedBuildConfigClass temporary file, so it can be later loaded @@ -81,4 +96,18 @@ class AarPublishTest { } } } + + @Test + fun aarContainsAllowedRootDirectories() { + project.execute("library:assembleDebug") + project.getSubproject(":library").assertThatAar(GradleTestProject.ApkType.DEBUG.buildType) { + containsFile("/AndroidManifest.xml") + containsFile("/R.txt") + containsFile("/classes.jar") + containsFile("/res/values/values.xml") + containsFile("META-INF/com/android/build/gradle/aar-metadata.properties") + // Regression test for b/232117952 + doesNotContain("/values/") + } + } } 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 23e42bac5f..42c028fb5e 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 @@ -424,11 +424,11 @@ class CheckAarMetadataTaskTest { addAarWithPossiblyInvalidAarMetadataToAppProject( aarFormatVersion = AarMetadataTask.AAR_FORMAT_VERSION, aarMetadataVersion = AarMetadataTask.AAR_METADATA_VERSION, - forceCompileSdkPreview = "Tiramisu" + forceCompileSdkPreview = "TiramisuPrivacySandbox" ) TestFileUtils.appendToFile( project.getSubproject("app").buildFile, - "\n\nandroid.compileSdkPreview 'Tiramisu'\n\n" + "\n\nandroid.compileSdkPreview 'TiramisuPrivacySandbox'\n\n" ) val result = project.executor().run(":app:checkDebugAarMetadata") ScannerSubject.assertThat(result.stdout).contains("BUILD SUCCESSFUL") @@ -439,7 +439,7 @@ class CheckAarMetadataTaskTest { addAarWithPossiblyInvalidAarMetadataToAppProject( aarFormatVersion = AarMetadataTask.AAR_FORMAT_VERSION, aarMetadataVersion = AarMetadataTask.AAR_METADATA_VERSION, - forceCompileSdkPreview = "Tiramisu" + forceCompileSdkPreview = "TiramisuPrivacySandbox" ) // Test that build fails with desired error message. @@ -453,13 +453,13 @@ class CheckAarMetadataTaskTest { An issue was found when checking AAR metadata: 1. Dependency 'library.aar' requires libraries and applications that - depend on it to compile against codename "Tiramisu" of the + depend on it to compile against codename "TiramisuPrivacySandbox" of the Android APIs. :app is currently compiled against $compileSdkHash. Recommended action: Use a different version of dependency 'library.aar', - or set compileSdkPreview to "Tiramisu" in your build.gradle + or set compileSdkPreview to "TiramisuPrivacySandbox" in your build.gradle file if you intend to experiment with that preview SDK. """.trimIndent() ) diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/DifferentProjectClassLoadersTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/DifferentProjectClassLoadersTest.kt index d1c79e9849..651e5f9add 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/DifferentProjectClassLoadersTest.kt +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/DifferentProjectClassLoadersTest.kt @@ -21,6 +21,7 @@ import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.app.MinimalSubProject import com.android.build.gradle.integration.common.fixture.app.MultiModuleTestProject import com.android.build.gradle.integration.common.utils.TestFileUtils +import com.android.build.gradle.internal.services.LintParallelBuildService import com.android.build.gradle.options.StringOption import com.android.ide.common.attribution.AndroidGradlePluginAttributionData import com.google.common.truth.Truth.assertThat @@ -65,6 +66,15 @@ class DifferentProjectClassLoadersTest { project.executor().run("assembleDebug") } + /** + * Test lint because we register the [LintParallelBuildService] once instead of registering one + * per classloader. + */ + @Test + fun testLint() { + project.executor().run("lintDebug") + } + @Test fun testAttributionFile() { fun setUpDummyTask(taskName: String): String = diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/NoCruncherTest.java b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/NoCruncherTest.java index df401c3cf5..deaaee215a 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/NoCruncherTest.java +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/NoCruncherTest.java @@ -20,7 +20,6 @@ import static com.android.testutils.truth.PathSubject.assertThat; import static com.google.common.truth.Truth.assertThat; import com.android.annotations.NonNull; -import com.android.build.gradle.integration.common.fixture.BaseGradleExecutor; import com.android.build.gradle.integration.common.fixture.GradleTestProject; import com.android.build.gradle.integration.common.fixture.GradleTestProject.ApkType; import com.android.build.gradle.integration.common.fixture.TemporaryProjectModification; @@ -79,7 +78,7 @@ public class NoCruncherTest { checkResource(ApkType.RELEASE, "drawable/icon.png", true); } // QA is debuggable, but inits from release, so the cruncher is default enabled. - checkResource(ApkType.of("qa", true), "drawable/icon.png", true); + checkResource(ApkType.of("qa", false), "drawable/icon.png", true); }); } @@ -95,7 +94,7 @@ public class NoCruncherTest { projectModification.replaceInFile( "build.gradle", "// crunchPngs false", "crunchPngs false"); noPngCrunch.executor().run("assembleQa"); - checkResource(ApkType.of("qa", true), "drawable/icon.png", false); + checkResource(ApkType.of("qa", false), "drawable/icon.png", false); }); } diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ProfileableTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ProfileableTest.kt index 808f50e32c..30489aa17c 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ProfileableTest.kt +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/application/ProfileableTest.kt @@ -16,6 +16,7 @@ package com.android.build.gradle.integration.application +import com.android.apksig.ApkVerifier import com.android.build.gradle.integration.common.fixture.DEFAULT_COMPILE_SDK_VERSION import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.app.MinimalSubProject @@ -25,6 +26,7 @@ import com.android.build.gradle.integration.common.truth.ScannerSubject import com.android.build.gradle.integration.common.truth.TruthHelper.assertThat import com.android.build.gradle.integration.common.utils.SigningHelper import com.android.build.gradle.integration.common.utils.TestFileUtils +import com.android.build.gradle.options.BooleanOption import com.android.build.gradle.options.StringOption import org.junit.Rule import org.junit.Test @@ -50,14 +52,16 @@ class ProfileableTest { fun `test dsl setting the release build type to be profileable`() { val app = project.getSubproject(":app") app.buildFile.appendText("android.buildTypes.release.profileable true") - project.executor().run("assembleRelease") - val apkType = GradleTestProject.ApkType.RELEASE_SIGNED - val apk = project.getSubproject("app").getApk(apkType) - val verificationResult = SigningHelper.assertApkSignaturesVerify(apk, 30) + project.executor() + .with(BooleanOption.ENABLE_DEFAULT_DEBUG_SIGNING_CONFIG, true) + .run("assembleRelease") + val apkSigned = + project.getSubproject("app").getApk(GradleTestProject.ApkType.RELEASE_SIGNED) + val verificationResult = SigningHelper.assertApkSignaturesVerify(apkSigned, 30) assertThat( verificationResult.signerCertificates.first().subjectX500Principal.name ).isEqualTo("C=US,O=Android,CN=Android Debug") - val manifest = ApkSubject.getManifestContent(apk.file.toAbsolutePath()) + val manifest = ApkSubject.getManifestContent(apkSigned.file.toAbsolutePath()) assertThat(manifest).containsAtLeastElementsIn( arrayListOf( " E: application (line=11)", @@ -66,6 +70,13 @@ class ProfileableTest { " A: http://schemas.android.com/apk/res/android:shell(0x01010594)=true" ) ) + + // Test no signing config configured, if the automatic signing config assignment is disabled. + project.executor().with(BooleanOption.ENABLE_DEFAULT_DEBUG_SIGNING_CONFIG, false) + .run("clean", "assembleRelease") + val apkUnsigned = + project.getSubproject("app").getApk(GradleTestProject.ApkType.RELEASE) + ApkSubject.assertThat(apkUnsigned).doesNotContainApkSigningBlock() } @Test @@ -108,6 +119,7 @@ class ProfileableTest { val app = project.getSubproject(":app") project.executor() .with(StringOption.PROFILING_MODE, "profileable") + .with(BooleanOption.ENABLE_DEFAULT_DEBUG_SIGNING_CONFIG, true) .run("assembleRelease") checkProjectContainsProfileableInManifest(app, GradleTestProject.ApkType.RELEASE_SIGNED) } diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/library/AarMetadataTaskTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/library/AarMetadataTaskTest.kt index 20926ebbdc..f43cf475b2 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/library/AarMetadataTaskTest.kt +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/library/AarMetadataTaskTest.kt @@ -257,7 +257,7 @@ class AarMetadataTaskTest { project.getSubproject("lib").buildFile.appendText( """ android { - compileSdkPreview 'Tiramisu' + compileSdkPreview 'TiramisuPrivacySandbox' } """.trimIndent() ) @@ -271,7 +271,7 @@ class AarMetadataTaskTest { AarMetadataTask.AAR_METADATA_FILE_NAME ) PathSubject.assertThat(aarMetadataFile).contains( - "${FORCE_COMPILE_SDK_PREVIEW_PROPERTY}=Tiramisu" + "${FORCE_COMPILE_SDK_PREVIEW_PROPERTY}=TiramisuPrivacySandbox" ) } } diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/manifest/ProcessTestManifestTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/manifest/ProcessTestManifestTest.kt index 8296f0dadd..7bb456e36e 100644 --- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/manifest/ProcessTestManifestTest.kt +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/manifest/ProcessTestManifestTest.kt @@ -298,8 +298,8 @@ class ProcessTestManifestTest { """.trimIndent()) project.file("src/main/AndroidManifest.xml").delete() FileUtils.createFile( - project.file("src/main/AndroidManifest.xml"), - """ + project.file("src/main/AndroidManifest.xml"), + """ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/resources/UserAddedGeneratedResourcesTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/resources/UserAddedGeneratedResourcesTest.kt new file mode 100644 index 0000000000..dce683c863 --- /dev/null +++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/resources/UserAddedGeneratedResourcesTest.kt @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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.integration.resources + +import com.android.build.gradle.integration.common.fixture.GradleTestProject +import com.android.build.gradle.integration.common.fixture.app.MinimalSubProject +import com.android.build.gradle.integration.common.fixture.app.MultiModuleTestProject +import com.android.testutils.truth.PathSubject +import org.junit.Rule +import org.junit.Test + +class UserAddedGeneratedResourcesTest { + + private val buildSrc = MinimalSubProject.buildSrc().also { + it.addFile("src/main/java/TestPlugin.java", + // language=java + """ + import org.gradle.api.Action; + import org.gradle.api.Plugin; + import org.gradle.api.Project; + import org.gradle.api.file.Directory; + import org.gradle.api.file.ProjectLayout; + import org.gradle.api.model.ObjectFactory; + import org.gradle.api.provider.Provider; + import org.gradle.api.tasks.TaskContainer; + import org.gradle.api.tasks.TaskProvider; + + import com.android.build.api.dsl.AndroidSourceSet; + import com.android.build.api.variant.AndroidComponentsExtension; + import com.android.build.api.variant.Variant; + + import java.util.Arrays; + + @SuppressWarnings({"rawtypes", "UnstableApiUsage"}) + public class TestPlugin implements Plugin<Project> + { + public void apply(Project project) { + + final ProjectLayout layout = project.getLayout(); + final TaskContainer tasks = project.getTasks(); + final ObjectFactory objects = project.getObjects(); + + Action<? super Plugin> action = plugin -> { + AndroidComponentsExtension components = project.getExtensions().getByType(AndroidComponentsExtension.class); + components.onVariants(components.selector().all(), (Action<? super Variant>) variant -> { + + TaskProvider<MyCopy> copyTask = tasks.register("copyResources" + variant.getName(), MyCopy.class, task -> { + task.setDescription("Copy resources into target directory"); + task.setGroup("Custom"); + task.getInputFiles().from( + project.fileTree( + layout.getProjectDirectory().dir("default"), + c -> c.include("**/*.xml"))); + }); + + variant.getSources().getRes().addGeneratedSourceDirectory(copyTask, MyCopy::getOutputDirectory); + }); + }; + + project.getPlugins().withId("com.android.application", action); + } + } + """.trimIndent()) + + it.addFile("src/main/java/MyCopy.java", + // language=java + """ + import org.gradle.api.DefaultTask; + import org.gradle.api.file.ConfigurableFileCollection; + import org.gradle.api.file.DirectoryProperty; + import org.gradle.api.file.FileSystemOperations; + import org.gradle.api.tasks.InputFiles; + import org.gradle.api.tasks.OutputDirectory; + import org.gradle.api.tasks.TaskAction; + + import javax.inject.Inject; + + public abstract class MyCopy extends DefaultTask { + + @OutputDirectory + public abstract DirectoryProperty getOutputDirectory(); + + @InputFiles + public abstract ConfigurableFileCollection getInputFiles(); + + @Inject + public abstract FileSystemOperations getFileSystemOperations(); + + @TaskAction + public void copy() { + getFileSystemOperations().copy( c -> { + c.from(getInputFiles()); + c.into(getOutputDirectory()); + }); + } + } + + """.trimIndent()) + } + + private val app = MinimalSubProject.app("com.example.app") + .withFile("default/values/ConnectStatus.xml", + // language=xml + """ + <?xml version="1.0" encoding="UTF-8"?> + <resources> + <string name="connect_status_none">Unknown status.</string> + </resources> + """.trimIndent()) + + private val testApp = + MultiModuleTestProject.builder() + .buildSrcProject(buildSrc) + .subproject(":app", app) + .build() + + @get:Rule + val project = GradleTestProject.builder().fromTestApp(testApp).create() + + @Test + fun testGeneratedResourcesArePresentInMergedResources() { + val appProject = project.getSubproject(":app") + appProject.buildFile.appendText( + "apply plugin: TestPlugin" + ) + project.execute(":app:mergeDebugResources") + + val mergedAppValues = appProject.getIntermediateFile( + "incremental", + "debug", + "mergeDebugResources", + "merged.dir", + "values", + "values.xml" + ) + + // Make sure the merged values in app (big merge) contain both overlayable from app and lib, + // as well as their content. + PathSubject.assertThat(mergedAppValues).containsAllOf( + "<string name=\"connect_status_none\">Unknown status.</string>" + ) + } +} diff --git a/build-system/integration-test/connected/BUILD.bazel b/build-system/integration-test/connected/BUILD.bazel index 902ac418dd..4797701801 100644 --- a/build-system/integration-test/connected/BUILD.bazel +++ b/build-system/integration-test/connected/BUILD.bazel @@ -54,7 +54,6 @@ avd(name = "avd") #keep sorted TEST_DATA = [ - ":avd", "//prebuilts/studio/sdk:build-tools/latest", "//prebuilts/studio/sdk:platform-tools", "//tools/base/build-system:gradle-distrib", @@ -81,6 +80,7 @@ TEST_MAVEN_REPOS = [ gradle_connected_test( name = "AdditionalTestOutputConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/additionalTestOutput"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -91,6 +91,7 @@ gradle_connected_test( gradle_connected_test( name = "AdditionalTestOutputOverrideConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/additionalTestOutputOverride"], maven_repo_zips = MAVEN_REPO_ZIPS, maven_repos = TEST_MAVEN_REPOS, @@ -100,6 +101,7 @@ gradle_connected_test( gradle_connected_test( name = "AndroidTestResourcesConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -110,6 +112,7 @@ gradle_connected_test( gradle_connected_test( name = "AnnotationProcessorConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -120,6 +123,7 @@ gradle_connected_test( gradle_connected_test( name = "ApiConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/api"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -130,6 +134,7 @@ gradle_connected_test( gradle_connected_test( name = "ApplibtestConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/applibtest"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -140,6 +145,7 @@ gradle_connected_test( gradle_connected_test( name = "AttrOrderConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/attrOrder"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -150,6 +156,7 @@ gradle_connected_test( gradle_connected_test( name = "BasicConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/basic"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -160,6 +167,7 @@ gradle_connected_test( gradle_connected_test( name = "CmakeJniLibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/nativebuild/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -174,6 +182,7 @@ gradle_connected_test( gradle_connected_test( name = "ComposeHelloWorldConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/composeHelloWorld"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -186,6 +195,7 @@ gradle_connected_test( gradle_connected_test( name = "CoreLibraryDesugarConversionConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -197,6 +207,7 @@ gradle_connected_test( gradle_connected_test( name = "CustomTestedApksTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -208,6 +219,7 @@ gradle_connected_test( gradle_connected_test( name = "D8DesugaringConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -218,6 +230,7 @@ gradle_connected_test( gradle_connected_test( name = "DataBindingExternalArtifactDependencyConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/databinding/", + avd = ":avd", data = TEST_DATA + [ "//tools/data-binding:integration-test-projects", "//tools/data-binding:integration-test-projects-support", @@ -235,6 +248,7 @@ gradle_connected_test( gradle_connected_test( name = "DataBindingIntegrationTestAppsConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/databinding/", + avd = ":avd", data = TEST_DATA + [ "//tools/data-binding:integration-test-projects", "//tools/data-binding:integration-test-projects-support", @@ -252,6 +266,7 @@ gradle_connected_test( gradle_connected_test( name = "DensitySplitConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/densitySplit"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -262,6 +277,7 @@ gradle_connected_test( gradle_connected_test( name = "DependenciesConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/dependencies"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -272,6 +288,7 @@ gradle_connected_test( gradle_connected_test( name = "DynamicFeatureConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/feature/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -282,6 +299,7 @@ gradle_connected_test( gradle_connected_test( name = "FlavoredConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/flavored"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -292,6 +310,7 @@ gradle_connected_test( gradle_connected_test( name = "FlavoredlibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/flavoredlib"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -302,6 +321,7 @@ gradle_connected_test( gradle_connected_test( name = "FlavorlibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/flavorlib"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -312,6 +332,7 @@ gradle_connected_test( gradle_connected_test( name = "FlavorsConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/flavors"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -322,6 +343,7 @@ gradle_connected_test( gradle_connected_test( name = "JacocoConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -332,6 +354,7 @@ gradle_connected_test( gradle_connected_test( name = "JarsInLibrariesConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/assets"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -343,6 +366,7 @@ gradle_connected_test( gradle_connected_test( name = "KotlinAppConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/kotlinApp"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -353,6 +377,7 @@ gradle_connected_test( gradle_connected_test( name = "LibMinifyJarDepConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/libMinifyJarDep"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -363,6 +388,7 @@ gradle_connected_test( gradle_connected_test( name = "LibMinifyLibDepConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/libMinifyLibDep"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -373,6 +399,7 @@ gradle_connected_test( gradle_connected_test( name = "LibsTestConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/libsTest"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -383,6 +410,7 @@ gradle_connected_test( gradle_connected_test( name = "LibTestDepConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/libTestDep"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -393,6 +421,7 @@ gradle_connected_test( gradle_connected_test( name = "MigratedConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/migrated"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -403,6 +432,7 @@ gradle_connected_test( gradle_connected_test( name = "MinifyConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/minify"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -413,6 +443,7 @@ gradle_connected_test( gradle_connected_test( name = "MinifyLibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/minifyLib"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -423,6 +454,7 @@ gradle_connected_test( gradle_connected_test( name = "MlModelBindingConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + [ "//tools/base/build-system/integration-test:test-projects/mlModelBinding", "//prebuilts/tools/common/mlkit/testData", @@ -436,6 +468,7 @@ gradle_connected_test( gradle_connected_test( name = "MultiDexConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/multiDex"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -446,6 +479,7 @@ gradle_connected_test( gradle_connected_test( name = "MultiDexWithLibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/multiDexWithLib"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -456,6 +490,7 @@ gradle_connected_test( gradle_connected_test( name = "MultiProjectConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/multiproject"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -466,6 +501,7 @@ gradle_connected_test( gradle_connected_test( name = "MultiresConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/multires"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -476,6 +512,7 @@ gradle_connected_test( gradle_connected_test( name = "NdkConnectedCheckTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/ndk/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -489,6 +526,7 @@ gradle_connected_test( gradle_connected_test( name = "NdkJniLibConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/ndk/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -503,6 +541,7 @@ gradle_connected_test( gradle_connected_test( name = "NdkLibPrebuiltsConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/ndk/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -517,6 +556,7 @@ gradle_connected_test( gradle_connected_test( name = "NdkSanAngelesConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/ndk/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -531,6 +571,7 @@ gradle_connected_test( gradle_connected_test( name = "NoSplitNdkVariantsConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/ndk/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -544,6 +585,7 @@ gradle_connected_test( gradle_connected_test( name = "Overlay1ConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/overlay1"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -554,6 +596,7 @@ gradle_connected_test( gradle_connected_test( name = "Overlay2ConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/overlay2"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -564,6 +607,7 @@ gradle_connected_test( gradle_connected_test( name = "Overlay3ConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/overlay3"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -574,6 +618,7 @@ gradle_connected_test( gradle_connected_test( name = "PkgOverrideConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/pkgOverride"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -584,6 +629,7 @@ gradle_connected_test( gradle_connected_test( name = "RenderscriptNdkConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/nativebuild/", + avd = ":avd", data = TEST_DATA + [ "//prebuilts/studio/sdk:cmake", "//prebuilts/studio/sdk:ndk", @@ -598,6 +644,7 @@ gradle_connected_test( gradle_connected_test( name = "ResValueTypeConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -608,6 +655,7 @@ gradle_connected_test( gradle_connected_test( name = "ShardingConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/appWithTests"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -618,6 +666,7 @@ gradle_connected_test( gradle_connected_test( name = "SameNamedLibsConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/library/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/sameNamedLibs"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -628,6 +677,7 @@ gradle_connected_test( gradle_connected_test( name = "SeparateTestModuleConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/separateTestModule"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -638,6 +688,7 @@ gradle_connected_test( gradle_connected_test( name = "SeparateTestModuleWithMinifiedAppConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/separateTestModuleWithMinifiedApp"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -648,6 +699,7 @@ gradle_connected_test( gradle_connected_test( name = "SeparateTestWithAarDependencyConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/separateTestModule"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -658,6 +710,7 @@ gradle_connected_test( gradle_connected_test( name = "SeparateTestWithMinificationButNoObfuscationConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/separateTestWithMinificationButNoObfuscation"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -668,6 +721,7 @@ gradle_connected_test( gradle_connected_test( name = "SigningConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -679,6 +733,7 @@ gradle_connected_test( gradle_connected_test( name = "TestingSupportLibraryConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/testing/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -689,6 +744,7 @@ gradle_connected_test( gradle_connected_test( name = "TestWithSameDepAsAppConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/dependencies/", + avd = ":avd", data = TEST_DATA, flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, @@ -699,6 +755,7 @@ gradle_connected_test( gradle_connected_test( name = "UtpConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + [ "//tools/adt/idea/utp:addGradleAndroidTestListener", "//tools/base/build-system/integration-test:test-projects/utp", @@ -714,6 +771,7 @@ gradle_connected_test( gradle_connected_test( name = "FailureRetentionConnectedTest", srcs = "src/test/java/com/android/build/gradle/integration/connected/application/", + avd = ":avd", data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/failureRetention"], flaky = True, # b/148626301 flaky emulator connectivity maven_repo_zips = MAVEN_REPO_ZIPS, diff --git a/build-system/integration-test/connected/connected-test.bzl b/build-system/integration-test/connected/connected-test.bzl index f32ec45109..d874560da9 100644 --- a/build-system/integration-test/connected/connected-test.bzl +++ b/build-system/integration-test/connected/connected-test.bzl @@ -1,4 +1,5 @@ load("//tools/base/build-system/integration-test:integration-test.bzl", "single_gradle_integration_test") +load("//tools/base/bazel:maven.bzl", "maven_repository") # A gradle connected test # @@ -15,18 +16,32 @@ load("//tools/base/build-system/integration-test:integration-test.bzl", "single_ def gradle_connected_test( name, srcs, + avd, deps, data, maven_repos, + maven_artifacts = [], runtime_deps = [], tags = [], timeout = "long", + jvm_flags = [], **kwargs): + if avd: + emulator_path = "%s/%s" % (native.package_name(), avd[1:]) + jvm_flags = jvm_flags + ["-DEMULATOR_PATH=%s" % emulator_path] + if maven_artifacts: + repo_name = name + ".mavenRepo" + maven_repository( + name = repo_name, + artifacts = maven_artifacts, + ) + absolute_path = "//%s:%s" % (native.package_name(), repo_name) + maven_repos += [absolute_path] single_gradle_integration_test( name = name, srcs = srcs, deps = deps, - data = data, + data = data + ([avd] if avd else []), maven_repos = maven_repos, runtime_deps = runtime_deps, tags = tags + [ @@ -34,5 +49,6 @@ def gradle_connected_test( "no_windows", ], timeout = timeout, + jvm_flags = jvm_flags, **kwargs ) diff --git a/build-system/integration-test/connected/src/main/java/com/android/build/gradle/integration/connected/utils/EmulatorUtils.kt b/build-system/integration-test/connected/src/main/java/com/android/build/gradle/integration/connected/utils/EmulatorUtils.kt index 812aa97c89..d9efdef784 100644 --- a/build-system/integration-test/connected/src/main/java/com/android/build/gradle/integration/connected/utils/EmulatorUtils.kt +++ b/build-system/integration-test/connected/src/main/java/com/android/build/gradle/integration/connected/utils/EmulatorUtils.kt @@ -27,7 +27,7 @@ import org.junit.rules.ExternalResource * <p>The executable is the script that starts and stops emulators and must be used to launch * the emulator. */ -private const val DEVICE = "tools/base/build-system/integration-test/connected/avd" +private val DEVICE = System.getProperty("EMULATOR_PATH") /** * Port at which to open the emulator. diff --git a/build-system/integration-test/connected/src/test/java/com/android/build/gradle/integration/connected/application/PrivacySandboxSdkConnectedTest.kt b/build-system/integration-test/connected/src/test/java/com/android/build/gradle/integration/connected/application/PrivacySandboxSdkConnectedTest.kt new file mode 100644 index 0000000000..89bbd33ddd --- /dev/null +++ b/build-system/integration-test/connected/src/test/java/com/android/build/gradle/integration/connected/application/PrivacySandboxSdkConnectedTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 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.integration.connected.application + +import com.android.build.gradle.integration.common.fixture.GradleTestProject.Companion.builder +import com.android.build.gradle.integration.connected.utils.getEmulator +import com.android.ddmlib.AndroidDebugBridge +import com.android.ddmlib.IDevice +import org.junit.Before +import org.junit.ClassRule +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import java.util.concurrent.TimeUnit + + +/** + * Connected tests using UTP test executor. + */ +class PrivacySandboxSdkConnectedTest { + init { + AndroidDebugBridge.init(true) + } + // private val adb: AndroidDebugBridge by lazy { AndroidDebugBridge.createBridge(10, TimeUnit.SECONDS) } + private val adb: AndroidDebugBridge = AndroidDebugBridge.createBridge(10, TimeUnit.SECONDS) + private lateinit var device: IDevice + + @get:Rule var project = builder() + .fromTestProject("privacySandboxSdk/libraryAndConsumer") + .create() + + @Before + fun setUp() { + // fail fast if no response + project.addAdbTimeout(); + adb.hasInitialDeviceList() + assert(adb.devices.size == 1) + device = adb.devices[0] + + device.uninstallPackage("com.example.rubidumconsumer") + device.uninstallPackage("com.example.rubidumconsumer.test") + device.uninstallPackage("com.myrbsdk_10000") + } + + @Test + fun `connectedAndroidTest task, SDK preinstalled`() { + project.execute(":app:buildPrivacySandboxSdkApksForDebug") + device.installPackage( + project.getSubproject("app").getIntermediateFile( + "extracted_apks_from_privacy_sandbox_sdks", + "debug", + "ads-sdk", + "standalone.apk" + ).path, + /* reinstall */ true + ) + project.execute("connectedAndroidTest") + } + + @Test + @Ignore // This doesn't work because deployment is not handled yet. + fun `connectedAndroidTest task`() { + project.execute("connectedAndroidTest") + } + + @Test + @Ignore // This doesn't work because deployment is not handled yet. + fun `install and uninstall works for both SDK and APK`() { + project.execute("installDebug") + // Verify both APKs are installed here. + project.execute("uninstallAll") + // Verify both APKs are deleted + } + + companion object { + @JvmField @ClassRule val emulator = getEmulator() + } +} diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/BuildSrcProject.kt b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/BuildSrcProject.kt new file mode 100644 index 0000000000..7f36186429 --- /dev/null +++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/BuildSrcProject.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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.integration.common.fixture + +import java.io.File + +/** + * Specialization of the [GradleProject] fpr buildSrc project. + */ +class BuildSrcProject: GradleProject("buildSrc") { + + override fun containsFullBuildScript(): Boolean = false + + override fun write(projectDir: File, buildScriptContent: String?, projectRepoScript: String) { + super.write(projectDir, buildScriptContent, projectRepoScript) + val buildFileName = + if (sourceFiles.containsKey("build.gradle.kts")) "build.gradle.kts" else "build.gradle" + val buildFile = File(projectDir, buildFileName) + buildFile.appendText( + projectRepoScript + ) + } +} diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleProject.kt b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleProject.kt index b9f452d08a..f1c4c834fb 100644 --- a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleProject.kt +++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/GradleProject.kt @@ -16,7 +16,6 @@ package com.android.build.gradle.integration.common.fixture -import com.android.build.gradle.integration.common.fixture.app.MinimalSubProject import com.android.build.gradle.integration.common.fixture.app.TestSourceFile import java.io.File @@ -46,7 +45,7 @@ abstract class GradleProject( } /** Map from a relative path to the corresponding [TestSourceFile] instance. */ - private val sourceFiles: MutableMap<String, TestSourceFile> = mutableMapOf() + protected val sourceFiles: MutableMap<String, TestSourceFile> = mutableMapOf() /** Returns a source file with the specified file path. */ fun getFile(relativePath: String): TestSourceFile { diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MinimalSubProject.kt b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MinimalSubProject.kt index 02172fb7db..4e5c121167 100644 --- a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MinimalSubProject.kt +++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MinimalSubProject.kt @@ -16,6 +16,7 @@ package com.android.build.gradle.integration.common.fixture.app +import com.android.build.gradle.integration.common.fixture.BuildSrcProject import com.android.build.gradle.integration.common.fixture.GradleProject import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.SUPPORT_LIB_MIN_SDK @@ -79,6 +80,10 @@ class MinimalSubProject private constructor( companion object { + fun buildSrc(): BuildSrcProject { + return BuildSrcProject() + } + @JvmOverloads fun app(namespace: String = "com.example.app", projectPath: String = "app"): MinimalSubProject { return MinimalSubProject( diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MultiModuleTestProject.java b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MultiModuleTestProject.java index 216c018c8f..a79f01989f 100644 --- a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MultiModuleTestProject.java +++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/app/MultiModuleTestProject.java @@ -4,6 +4,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.android.annotations.NonNull; import com.android.annotations.Nullable; +import com.android.build.gradle.integration.common.fixture.BuildSrcProject; import com.android.build.gradle.integration.common.fixture.GradleProject; import com.android.build.gradle.integration.common.fixture.TestProject; import com.google.common.collect.BiMap; @@ -19,6 +20,7 @@ import java.util.Map; public class MultiModuleTestProject implements TestProject { private final ImmutableMap<String, TestProject> subprojects; + @Nullable private final BuildSrcProject buildSrcProject; /** * Creates a MultiModuleTestProject. @@ -27,7 +29,14 @@ public class MultiModuleTestProject implements TestProject { * value. */ public MultiModuleTestProject(@NonNull Map<String, ? extends TestProject> subprojects) { + this(subprojects, null); + } + + public MultiModuleTestProject( + @NonNull Map<String, ? extends TestProject> subprojects, + @Nullable BuildSrcProject buildSrcProject) { this.subprojects = ImmutableMap.copyOf(subprojects); + this.buildSrcProject = buildSrcProject; } /** @@ -44,6 +53,7 @@ public class MultiModuleTestProject implements TestProject { builder.put(baseName + i, subproject); } subprojects = builder.build(); + buildSrcProject = null; } /** Return the test project with the given project path. */ @@ -68,6 +78,19 @@ public class MultiModuleTestProject implements TestProject { subproject.write(subprojectDir, null, projectRepoScript); } + if (buildSrcProject != null) { + File subprojectDir = new File(projectDir, "buildSrc"); + if (!subprojectDir.exists()) { + subprojectDir.mkdirs(); + } + // buildSrc requires the repo declaration. + buildSrcProject.write( + subprojectDir, + "dependencies { implementation \"com.android.tools.build:gradle-api:" + + com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + + "\" }\n", + projectRepoScript); + } StringBuilder builder = new StringBuilder(); for (String subprojectName : subprojects.keySet()) { builder.append("include '").append(subprojectName).append("'\n"); @@ -96,6 +119,22 @@ public class MultiModuleTestProject implements TestProject { public static class Builder { private BiMap<String, GradleProject> projects = HashBiMap.create(); + private BuildSrcProject buildSrcProject = null; + + /** + * Adds a buildSrc project to the current test project. Can only be called once. + * + * @param buildSrcProject the [BuildSrcProject] to use as buildSrc + * @return itself. + */ + @NonNull + public Builder buildSrcProject(@NonNull BuildSrcProject buildSrcProject) { + if (this.buildSrcProject != null) { + throw new IllegalStateException("Test project can only have one buildSrc project"); + } + this.buildSrcProject = buildSrcProject; + return this; + } @NonNull public Builder subproject(@NonNull GradleProject testProject) { @@ -165,7 +204,7 @@ public class MultiModuleTestProject implements TestProject { @NonNull public MultiModuleTestProject build() { - return new MultiModuleTestProject(projects); + return new MultiModuleTestProject(projects, buildSrcProject); } } } diff --git a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/testprojects/TestProjectBuilderImpl.kt b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/testprojects/TestProjectBuilderImpl.kt index 2a4f0fc9a5..f0d78c1596 100644 --- a/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/testprojects/TestProjectBuilderImpl.kt +++ b/build-system/integration-test/framework/src/main/java/com/android/build/gradle/integration/common/fixture/testprojects/TestProjectBuilderImpl.kt @@ -17,7 +17,6 @@ package com.android.build.gradle.integration.common.fixture.testprojects import com.android.Version -import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.TestProject import com.android.testutils.MavenRepoGenerator import com.android.utils.FileUtils diff --git a/build-system/integration-test/managed-devices/BUILD.bazel b/build-system/integration-test/managed-devices/BUILD.bazel index e8d89c99e9..4063427184 100644 --- a/build-system/integration-test/managed-devices/BUILD.bazel +++ b/build-system/integration-test/managed-devices/BUILD.bazel @@ -65,6 +65,7 @@ TEST_MAVEN_REPOS = [ gradle_connected_test( name = "UtpManagedDeviceTest", srcs = "src/test/java/com/android/build/gradle/integration/manageddevice/application/", + avd = None, data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/utp"], jvm_flags = sdk_jvm_flags, maven_repo_zips = MAVEN_REPO_ZIPS, @@ -80,6 +81,7 @@ gradle_connected_test( gradle_connected_test( name = "SimpleManagedDeviceTest", srcs = "src/test/java/com/android/build/gradle/integration/manageddevice/application/", + avd = None, data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/utp"], jvm_flags = sdk_jvm_flags, maven_repo_zips = MAVEN_REPO_ZIPS, @@ -93,6 +95,7 @@ gradle_connected_test( gradle_connected_test( name = "TestApplicationManagedDeviceTest", srcs = "src/test/java/com/android/build/gradle/integration/manageddevice/application/", + avd = None, data = TEST_DATA + ["//tools/base/build-system/integration-test:test-projects/utp"], jvm_flags = sdk_jvm_flags, maven_repo_zips = MAVEN_REPO_ZIPS, diff --git a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/nativebuild/CmakeBasicProjectTest.kt b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/nativebuild/CmakeBasicProjectTest.kt index 8f5e0ad177..0d31e4aa8e 100644 --- a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/nativebuild/CmakeBasicProjectTest.kt +++ b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/nativebuild/CmakeBasicProjectTest.kt @@ -17,7 +17,9 @@ package com.android.build.gradle.integration.nativebuild import com.android.SdkConstants.CURRENT_PLATFORM +import com.android.SdkConstants.NDK_DEFAULT_VERSION import com.android.SdkConstants.PLATFORM_WINDOWS +import com.android.Version import com.android.build.gradle.integration.common.fixture.GradleBuildResult import com.android.build.gradle.integration.common.fixture.GradleTestProject import com.android.build.gradle.integration.common.fixture.GradleTestProject.ApkLocation @@ -53,11 +55,13 @@ import com.android.build.gradle.internal.core.Abi import com.android.build.gradle.internal.cxx.attribution.decodeBuildTaskAttributions import com.android.build.gradle.internal.cxx.configure.CMakeVersion import com.android.build.gradle.internal.cxx.configure.shouldConfigure +import com.android.build.gradle.internal.cxx.hashing.sha256Of import com.android.build.gradle.internal.cxx.io.SynchronizeFile.Outcome.CREATED_HARD_LINK_FROM_SOURCE_TO_DESTINATION import com.android.build.gradle.internal.cxx.io.decodeSynchronizeFile import com.android.build.gradle.internal.cxx.json.AndroidBuildGradleJsons import com.android.build.gradle.internal.cxx.json.AndroidBuildGradleJsons.getNativeBuildMiniConfig import com.android.build.gradle.internal.cxx.model.compileCommandsJsonBinFile +import com.android.build.gradle.internal.cxx.model.cxxBuildHashKeyFile import com.android.build.gradle.internal.cxx.model.jsonGenerationLoggingRecordFile import com.android.build.gradle.internal.cxx.model.miniConfigFile import com.android.build.gradle.internal.cxx.model.ninjaBuildFile @@ -411,6 +415,49 @@ class CmakeBasicProjectTest( } @Test + fun `ensure hashed output paths are stable`() { + Assume.assumeTrue(mode == Mode.CMake && cmakeVersionInDsl != "3.6.0") + project.execute("configure${mode.buildFolderTag}Debug[x86_64]") + val abi = project.recoverExistingCxxAbiModels().single { it.abi == Abi.X86_64 } + val hashKey = abi.cxxBuildHashKeyFile.readText() + val hashSegment = abi.cxxBuildHashKeyFile.parentFile.name + val hashKeyExpected = + """ + # Values used to calculate the hash in this folder name. + # Should not depend on the absolute path of the project itself. + # - AGP: ${Version.ANDROID_GRADLE_PLUGIN_VERSION}. + # - ${'$'}NDK is the path to NDK $NDK_DEFAULT_VERSION. + # - ${'$'}PROJECT is the path to the parent folder of the root Gradle build file. + # - ${'$'}ABI is the ABI to be built with. The specific value doesn't contribute to the value of the hash. + # - ${'$'}HASH is the hash value computed from this text. + # - ${'$'}CMAKE is the path to CMake $cmakeVersionInDsl. + # - ${'$'}NINJA is the path to Ninja. + -H${'$'}PROJECT + -DCMAKE_SYSTEM_NAME=Android + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + -DCMAKE_SYSTEM_VERSION=16 + -DANDROID_PLATFORM=android-16 + -DANDROID_ABI=${'$'}ABI + -DCMAKE_ANDROID_ARCH_ABI=${'$'}ABI + -DANDROID_NDK=${'$'}NDK + -DCMAKE_ANDROID_NDK=${'$'}NDK + -DCMAKE_TOOLCHAIN_FILE=${'$'}NDK/build/cmake/android.toolchain.cmake + -DCMAKE_MAKE_PROGRAM=${'$'}NINJA + -DCMAKE_C_FLAGS=-DTEST_C_FLAG -DTEST_C_FLAG_2 + -DCMAKE_CXX_FLAGS=-DTEST_CPP_FLAG + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${'$'}PROJECT/build/intermediates/cxx/Debug/${'$'}HASH/obj/${'$'}ABI + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${'$'}PROJECT/build/intermediates/cxx/Debug/${'$'}HASH/obj/${'$'}ABI + -DCMAKE_BUILD_TYPE=Debug + -B${'$'}PROJECT/.cxx/Debug/${'$'}HASH/${'$'}ABI + -GNinja + """.trimIndent() + assertThat(hashKey).isEqualTo(hashKeyExpected) + val expectedHashSegment = sha256Of(hashKeyExpected, includeGradleVersionInHash = false).substring(0,8) + // If the text above passes then the SHA-256 of it should be stable. + assertThat(hashSegment).isEqualTo(expectedHashSegment) + } + + @Test fun `ensure CMake arguments have macros expanded`() { if (mode != Mode.CMake) return // This is a CMake-only test TestFileUtils.appendToFile( diff --git a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/ModuleToModuleDepsTest.kt b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/ModuleToModuleDepsTest.kt index b0d76e3f3c..ac70ef8940 100644 --- a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/ModuleToModuleDepsTest.kt +++ b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/ModuleToModuleDepsTest.kt @@ -31,9 +31,11 @@ import com.android.build.gradle.integration.ndk.ModuleToModuleDepsTest.BuildSyst import com.android.build.gradle.internal.core.Abi import com.android.build.gradle.internal.cxx.configure.CMakeVersion import com.android.build.gradle.internal.cxx.json.AndroidBuildGradleJsons +import com.android.build.gradle.internal.cxx.json.readJsonFile import com.android.build.gradle.internal.cxx.logging.LoggingMessage import com.android.build.gradle.internal.cxx.logging.decodeLoggingMessage import com.android.build.gradle.internal.cxx.logging.text +import com.android.build.gradle.internal.cxx.prefab.ModuleMetadataV1 import com.android.builder.model.v2.ide.SyncIssue import com.google.common.truth.Truth.assertThat import org.junit.Assume @@ -109,11 +111,18 @@ class ModuleToModuleDepsTest( .dependency(app, lib) .build() + private val appOutputRoot : File get() = + if (outputStructureType == OutputStructureType.Normal) project.getSubproject("app").buildDir.parentFile + else { + // The output folder for lib is at $PROJECT_ROOT/out/lib + project.getSubproject("app").buildDir.parentFile.parentFile.resolve("out/app") + } + private val libOutputRoot : File get() = if (outputStructureType == OutputStructureType.Normal) project.getSubproject("lib").buildDir.parentFile else { // The output folder for lib is at $PROJECT_ROOT/out/lib - project.getSubproject("lib").buildDir.parentFile.parentFile.parentFile.resolve("out/lib") + project.getSubproject("lib").buildDir.parentFile.parentFile.resolve("out/lib") } @get:Rule @@ -172,7 +181,6 @@ class ModuleToModuleDepsTest( .buildFile .parentFile .parentFile - .parentFile .absolutePath.replace("\\", "/") val appStructureStanza = if (outputStructureType == OutputStructureType.Normal) "" else when(appBuildSystem) { is CMake -> """ @@ -196,6 +204,8 @@ class ModuleToModuleDepsTest( """.trimIndent() else -> error("$appBuildSystem") } + val libExportLibrariesStanza = + "android.externalNativeBuild.experimentalProperties[\"prefab.foo.exportLibraries\"] = [\"-llog\"]" project.getSubproject(":app").buildFile.appendText( """ @@ -263,6 +273,7 @@ class ModuleToModuleDepsTest( $libStanza $libStlStanza $libStructureStanza + $libExportLibrariesStanza """) val header = project.getSubproject(":lib").buildFile.resolveSibling("src/main/cpp/include/foo.h") @@ -354,7 +365,6 @@ class ModuleToModuleDepsTest( int callFoo() { return foo(); } """.trimIndent()) } - enableCxxStructuredLogging(project) } @@ -470,6 +480,19 @@ class ModuleToModuleDepsTest( assertThat(libOutput.isFile) .named("$libOutput") .isFalse() + + // Check that export libraries informations winds up in the final prefab structure + var sawAtleastOneModule = false + appOutputRoot.walkTopDown().forEach { file -> + if (file.name == "module.json") { + val module = readJsonFile<ModuleMetadataV1>(file) + assertThat(module.exportLibraries).containsExactly("-llog") + sawAtleastOneModule = true + } + } + assertThat(sawAtleastOneModule) + .named("Expected at least one Prefab module") + .isTrue() } @Test diff --git a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/PrefabPublishingTest.kt b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/PrefabPublishingTest.kt index 62bf6eb2de..892d456a1d 100644 --- a/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/PrefabPublishingTest.kt +++ b/build-system/integration-test/native/src/test/java/com/android/build/gradle/integration/ndk/PrefabPublishingTest.kt @@ -212,6 +212,9 @@ class PrefabPublishingTest( containsFile("prefab/prefab.json") containsFile("prefab/modules/$gradleModuleName/module.json") containsFile("prefab/modules/${gradleModuleName}_static/module.json") + // Regression test for b/232117952 + doesNotContain("/modules/$gradleModuleName/") + doesNotContain("/modules/$gradleModuleName/include/$gradleModuleName/") } } diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/build.gradle b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/build.gradle new file mode 100644 index 0000000000..733f73ea4d --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/build.gradle @@ -0,0 +1,22 @@ +plugins { + id 'com.android.library' +} + +android { + namespace 'com.example.ads_sdk_implementation' + compileSdkPreview = 'TiramisuPrivacySandbox' + + defaultConfig { + minSdk 33 + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation 'androidx.annotation:annotation:1.2.0-rc01' +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..abfbe8f055 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + <application></application> +</manifest>
\ No newline at end of file diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/assets/example.txt b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/assets/example.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/assets/example.txt diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/java/com/myrbsdk/MyAdsSdkEntryPoint.java b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/java/com/myrbsdk/MyAdsSdkEntryPoint.java new file mode 100644 index 0000000000..38e31f8c99 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk-implementation/src/main/java/com/myrbsdk/MyAdsSdkEntryPoint.java @@ -0,0 +1,44 @@ +package com.myrbsdk; + +import android.app.sdksandbox.SandboxedSdkContext; +import android.app.sdksandbox.SandboxedSdkProvider; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.RequiresApi; + +import java.util.concurrent.Executor; + +@RequiresApi(api = 34) +public class MyAdsSdkEntryPoint extends SandboxedSdkProvider { + + @Override + public void initSdk(SandboxedSdkContext sandboxedSdkContext, Bundle bundle, + Executor executor, InitSdkCallback initSdkCallback) { + Log.i("SDK", "initSdk"); + executor.execute(() -> initSdkCallback.onInitSdkFinished(new Bundle())); + } + + @Override + public View getView(Context windowContext, Bundle bundle) { + Log.i("SDK", "getView"); + + LinearLayout layout = new LinearLayout(windowContext); + layout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT + )); + layout.setBackgroundColor(Color.RED); + return layout; + } + + @Override + public void onDataReceived(Bundle bundle, DataReceivedCallback dataReceivedCallback) { + Log.i("SDK", "onDataReceived"); + } +} + diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk/build.gradle b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk/build.gradle new file mode 100644 index 0000000000..d7f6d1dc30 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/ads-sdk/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'com.android.privacy-sandbox-sdk' +} + +android { + compileSdkPreview 'TiramisuPrivacySandbox' + minSdk = 33 + namespace = "com.example.adssdk" + + bundle { + packageName = "com.myrbsdk" + sdkProviderClassName = "com.myrbsdk.MyAdsSdkEntryPoint" + setVersion(1, 0, 0) + } +} + +dependencies { + include project(':ads-sdk-implementation') +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/build.gradle b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/build.gradle new file mode 100644 index 0000000000..a650b29b0f --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.example.rubidumconsumer' + compileSdkPreview = 'TiramisuPrivacySandbox' + defaultConfig { + applicationId "com.example.rubidumconsumer" + minSdk 24 + targetSdk 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation project(':ads-sdk') + implementation 'androidx.appcompat:appcompat:1.4.1' + + // This is implementation because of https://github.com/android/android-test/issues/1412 + // (or https://issuetracker.google.com/issues/240993946) + // It needs to merge the underlying bootstrap activities to the main manifest + implementation 'androidx.test.ext:junit:1.1.3' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/androidTest/java/com/example/rubidumconsumer/MainActivityTest.kt b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/androidTest/java/com/example/rubidumconsumer/MainActivityTest.kt new file mode 100644 index 0000000000..4266984229 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/androidTest/java/com/example/rubidumconsumer/MainActivityTest.kt @@ -0,0 +1,25 @@ +package com.example.rubidumconsumer + +import android.graphics.Color +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MainActivityTest { + + @get:Rule var rule = ActivityScenarioRule(MainActivity::class.java) + + @Test + fun viewIsUpdatedBySdk() { + InstrumentationRegistry.getInstrumentation().apply { + waitForIdle { + val bitmap = uiAutomation.takeScreenshot() + assert(bitmap.getPixel(bitmap.width / 2, bitmap.height / 2) == Color.RED) + } + } + } +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/AndroidManifest.xml b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..325b2885f5 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + + <application + android:label="@string/app_name" + android:supportsRtl="true" + tools:targetApi="33"> + + <activity + android:name=".MainActivity" + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.AppCompat"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/MainActivity.java b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/MainActivity.java new file mode 100644 index 0000000000..36579a5520 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/MainActivity.java @@ -0,0 +1,62 @@ +package com.example.rubidumconsumer; + +import android.annotation.SuppressLint; +import android.app.sdksandbox.SdkSandboxManager; +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.SurfaceControlViewHost; +import android.view.SurfaceView; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowMetrics; + +@SuppressLint("NewApi") +public class MainActivity extends AppCompatActivity { + + // Needs to be the package name of the SDK as defined in the SdkModulesConfig.pb.json when building the SDK + static final String SDK_PACKAGE_NAME = "com.myrbsdk"; + + private SdkSandboxManager sdkSandboxManager; + + private RemoteSdkCallbackImpl callback; + private SurfaceView renderedView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + renderedView = findViewById(R.id.rendered_view); + sdkSandboxManager = getApplicationContext().getSystemService( + SdkSandboxManager.class); + } + + @Override + public void onResume() { + super.onResume(); + renderedView.setVisibility(View.INVISIBLE); + callback = new RemoteSdkCallbackImpl(this); + sdkSandboxManager.loadSdk(SDK_PACKAGE_NAME, new Bundle(), Runnable::run, callback); + } + + void requestSurfacePackage() { + final WindowMetrics metrics = getApplicationContext().getSystemService( + WindowManager.class).getCurrentWindowMetrics(); + + sdkSandboxManager.requestSurfacePackage( + SDK_PACKAGE_NAME, getDisplay().getDisplayId(), + metrics.getBounds().width(), + metrics.getBounds().height(), + new Bundle(), + Runnable::run, + callback); + } + + void renderSurfaceView(SurfaceControlViewHost.SurfacePackage surfacePackage) { + new Handler(Looper.getMainLooper()).post(() -> { + renderedView.setChildSurfacePackage(surfacePackage); + renderedView.setVisibility(View.VISIBLE); + }); + } +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/RemoteSdkCallbackImpl.java b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/RemoteSdkCallbackImpl.java new file mode 100644 index 0000000000..76e87ef10b --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/java/com/example/rubidumconsumer/RemoteSdkCallbackImpl.java @@ -0,0 +1,43 @@ +package com.example.rubidumconsumer; + +import android.annotation.SuppressLint; +import android.app.sdksandbox.SdkSandboxManager; +import android.os.Bundle; +import android.util.Log; +import android.view.SurfaceControlViewHost; +import androidx.annotation.NonNull; + +@SuppressLint("NewApi") +public class RemoteSdkCallbackImpl implements SdkSandboxManager.LoadSdkCallback, SdkSandboxManager.RequestSurfacePackageCallback { + + + RemoteSdkCallbackImpl(MainActivity mainActivity) { + this.mainActivity = mainActivity; + } + + private MainActivity mainActivity; + + @Override + public void onLoadSdkSuccess(Bundle bundle) { + Log.i("App", "onLoadSdkSuccess"); + mainActivity.requestSurfacePackage(); + } + + @Override + public void onLoadSdkFailure(int errorCode, String errorMessage) { + Log.i("App", String.format("onLoadSdkFailure. Error code: %d, Error message: %s",errorCode, errorMessage)); + } + + @Override + public void onSurfacePackageReady(@NonNull SurfaceControlViewHost.SurfacePackage surfacePackage, + int i, @NonNull Bundle bundle) { + Log.i("App", "onSurfacePackageReady"); + mainActivity.renderSurfaceView(surfacePackage); + } + + @Override + public void onSurfacePackageError(int errorCode, String errorMessage) { + Log.i("App", "onSurfacePackageError"); + } +} + diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/layout/activity_main.xml b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000..1b878ac32a --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".MainActivity"> + <SurfaceView + android:id="@+id/rendered_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> +</LinearLayout> diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/values/strings.xml b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..cbaab5ba60 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">RubidumConsumer</string> +</resources>
\ No newline at end of file diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/build.gradle b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/build.gradle new file mode 100644 index 0000000000..a5a7957e08 --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/build.gradle @@ -0,0 +1,11 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +apply from: "../commonHeader.gradle" + +buildscript { + apply from: "../commonHeader.gradle" // for $kotlinVersion + apply from: "../commonBuildScript.gradle" + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$rootProject.kotlinVersion" + } +} diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/gradle.properties b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/gradle.properties new file mode 100644 index 0000000000..da3a59093e --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/gradle.properties @@ -0,0 +1,2 @@ +android.useAndroidX=true +android.experimental.privacysandboxsdk.enable=true diff --git a/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/settings.gradle b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/settings.gradle new file mode 100644 index 0000000000..288816bd9e --- /dev/null +++ b/build-system/integration-test/test-projects/privacySandboxSdk/libraryAndConsumer/settings.gradle @@ -0,0 +1,5 @@ +apply from: "../commonLocalRepo.gradle", to: pluginManagement + +include ':app' +include ':ads-sdk-implementation' +include ':ads-sdk' diff --git a/ddmlib/src/main/java/com/android/ddmlib/internal/DeviceClientMonitorTask.java b/ddmlib/src/main/java/com/android/ddmlib/internal/DeviceClientMonitorTask.java index 96a60802f7..1333b7be5a 100644 --- a/ddmlib/src/main/java/com/android/ddmlib/internal/DeviceClientMonitorTask.java +++ b/ddmlib/src/main/java/com/android/ddmlib/internal/DeviceClientMonitorTask.java @@ -731,6 +731,17 @@ class DeviceClientMonitorTask implements Runnable { private class CmdlineFileProcessor extends Processor { + // CmdlineFileProcessor is peculiar since contrary to TrackServiceProcessor it tap into a + // source that does not prefix its message with their size (it runs a bash command). Also + // the source does not send several messages, it returns a single message made fo the whole + // update of the bash command. + // + // To be compliant with the parseMessage/onMessage system, it always return false on + // parseMessage() until the Processor is closed. After that parseMessage returns true once + // and then false each subsequent calls. + + private boolean messageReceived = false; + private final int mPid; private int mRetryCount; // The number of attempts left to read the cmdline file. @@ -752,10 +763,11 @@ class DeviceClientMonitorTask implements Runnable { @Override protected Optional<ByteBuffer> parseMessage() { - if (mSocketConnected) { + if (mSocketConnected || messageReceived) { return Optional.empty(); } + messageReceived = true; return Optional.of(ByteBuffer.wrap(mStream.buf(), 0, mStream.size())); } @@ -797,6 +809,7 @@ class DeviceClientMonitorTask implements Runnable { message.remaining(), AdbHelper.DEFAULT_CHARSET); + message.position(message.remaining()); name = name.trim(); if (name.isEmpty()) { return; diff --git a/ddmlib/src/test/java/com/android/ddmlib/testing/FakeAdbRule.kt b/ddmlib/src/test/java/com/android/ddmlib/testing/FakeAdbRule.kt index ad666e453c..816ed66e40 100644 --- a/ddmlib/src/test/java/com/android/ddmlib/testing/FakeAdbRule.kt +++ b/ddmlib/src/test/java/com/android/ddmlib/testing/FakeAdbRule.kt @@ -101,6 +101,7 @@ class FakeAdbRule : ExternalResource() { release: String, sdk: String, abi: String = "x86_64", + properties: Map<String, String> = emptyMap(), hostConnectionType: DeviceState.HostConnectionType = DeviceState.HostConnectionType.USB, avdName: String? = null, avdPath: String? = null @@ -110,7 +111,16 @@ class FakeAdbRule : ExternalResource() { if (avdName != null && avdPath != null) { EmulatorConsole.registerConsoleForTest(deviceId, consoleFactory(avdName, avdPath)) } - val device = fakeAdbServer.connectDevice(deviceId, manufacturer, model, release, sdk, abi, hostConnectionType).get() + val deviceFuture = fakeAdbServer.connectDevice( + deviceId, + manufacturer, + model, + release, + sdk, + abi, + properties, + hostConnectionType) + val device = deviceFuture.get() device.deviceStatus = DeviceState.DeviceStatus.ONLINE assertThat(startLatch.await(30, TimeUnit.SECONDS)).isTrue() return device diff --git a/deploy/agent/runtime/android.sdktools.deployer.deployer-runtime-support.iml b/deploy/agent/runtime/android.sdktools.deployer.deployer-runtime-support.iml index 2e2c1fb27a..2e515c3dc7 100644 --- a/deploy/agent/runtime/android.sdktools.deployer.deployer-runtime-support.iml +++ b/deploy/agent/runtime/android.sdktools.deployer.deployer-runtime-support.iml @@ -6,27 +6,21 @@ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" /> + <excludeFolder url="file://$MODULE_DIR$/src/main/java/com/android/tools/deploy/liveedit/superclasses" /> </content> <orderEntry type="inheritedJdk" /> <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module-library"> <library> <CLASSES> - <root url="jar://$MODULE_DIR$/lib/kotlin-eval4j.jar!/" /> - </CLASSES> - <JAVADOC /> - <SOURCES /> - </library> - </orderEntry> - <orderEntry type="module-library"> - <library> - <CLASSES> - <root url="jar://$MODULE_DIR$/lib/kotlin-stdlib.jar!/" /> + <root url="jar://$MODULE_DIR$/lib/deploy_asm4.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES /> </library> </orderEntry> + <orderEntry type="module-library"> <library> <CLASSES> @@ -77,7 +71,20 @@ <SOURCES /> </library> </orderEntry> - <orderEntry type="library" scope="TEST" name="mockito" level="project" /> + <orderEntry type="module-library" scope="TEST"> + <library name="mockito-junit-jupiter" type="repository"> + <properties maven-id="org.mockito:mockito-junit-jupiter:3.12.4" /> + <CLASSES> + <root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-junit-jupiter/3.12.4/mockito-junit-jupiter-3.12.4.jar!/" /> + <root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-core/3.12.4/mockito-core-3.12.4.jar!/" /> + </CLASSES> + <JAVADOC> + <root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-junit-jupiter/3.12.4/mockito-junit-jupiter-3.12.4-javadoc.jar!/" /> + <root url="jar://$MAVEN_REPOSITORY$/org/mockito/mockito-core/3.12.4/mockito-core-3.12.4-javadoc.jar!/" /> + </JAVADOC> + <SOURCES /> + </library> + </orderEntry> <orderEntry type="library" scope="TEST" name="studio-sdk" level="project" /> </component> -</module>
\ No newline at end of file +</module> diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DefaultProvisionerPlugin.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DefaultProvisionerPlugin.kt index 35c1593a7c..cc3bac4154 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DefaultProvisionerPlugin.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DefaultProvisionerPlugin.kt @@ -17,13 +17,9 @@ package com.android.sdklib.deviceprovisioner import com.android.adblib.ConnectedDevice import com.android.adblib.deviceProperties -import com.android.adblib.scope -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch /** * Plugin which provides handles for devices when no other plugin claims them. This will offer a diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProperties.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProperties.kt index 19a6f0fd14..601f554bff 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProperties.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProperties.kt @@ -16,7 +16,6 @@ package com.android.sdklib.deviceprovisioner import com.android.sdklib.AndroidVersion -import com.android.sdklib.AndroidVersion.AndroidVersionException import com.android.sdklib.devices.Abi /** @@ -26,56 +25,62 @@ import com.android.sdklib.devices.Abi */ interface DeviceProperties { - val model: String? - val manufacturer: String? - val apiLevel: AndroidVersion - val abi: Abi? + val model: String? + val manufacturer: String? + val abi: Abi? + /** The Android API level. May include a codename if not a release version. */ + val androidVersion: AndroidVersion + /** The user-visible version of Android, like "7.1" or "11". */ + val androidRelease: String? - open class Builder { + /** + * A string ideally unique to the device instance (e.g. serial number or emulator console port), + * used for disambiguating this device from others with similar properties. + */ + val disambiguator: String? - var manufacturer: String? = null - var model: String? = null - var apiLevel = AndroidVersion.DEFAULT - var abi: Abi? = null + open class Builder { - fun readCommonProperties(properties: Map<String, String>) { - manufacturer = - properties["ro.product.manufacturer"] - ?: properties["ro.manufacturer"] - model = - properties["ro.product.model"] - ?: properties["ro.model"] - apiLevel = - properties["ro.build.version.sdk"]?.let { - try { - AndroidVersion(it) - } catch (e: AndroidVersionException) { - null - } - } ?: AndroidVersion.DEFAULT - abi = properties["ro.product.cpu.abi"]?.let { Abi.getEnum(it) } - } + var manufacturer: String? = null + var model: String? = null + var abi: Abi? = null + var androidVersion = AndroidVersion.DEFAULT + var androidRelease: String? = null + var disambiguator: String? = null - fun buildBase(): DeviceProperties = Impl(manufacturer, model, apiLevel, abi) + fun readCommonProperties(properties: Map<String, String>) { + manufacturer = properties["ro.product.manufacturer"] ?: properties["ro.manufacturer"] + model = properties["ro.product.model"] ?: properties["ro.model"] + androidVersion = + properties["ro.build.version.sdk"]?.let { it.toIntOrNull() }?.let { sdk -> + AndroidVersion(sdk, properties["ro.build.version.codename"]) + } + ?: AndroidVersion.DEFAULT + abi = properties["ro.product.cpu.abi"]?.let { Abi.getEnum(it) } + androidRelease = properties["ro.build.version.release"] } - class Impl( - override val manufacturer: String?, - override val model: String?, - override val apiLevel: AndroidVersion, - override val abi: Abi? - ) : DeviceProperties + fun buildBase(): DeviceProperties = + Impl(manufacturer, model, androidVersion, abi, androidRelease, disambiguator) + } - /** - * Default implementation of device title; may be overridden. - */ - fun title(): String = + class Impl( + override val manufacturer: String?, + override val model: String?, + override val androidVersion: AndroidVersion, + override val abi: Abi?, + override val androidRelease: String?, + override val disambiguator: String? + ) : DeviceProperties + + /** Default implementation of device title; may be overridden. */ + fun title(): String = + when { + manufacturer.isNullOrBlank() -> model ?: "Unknown" + else -> when { - manufacturer.isNullOrBlank() -> - model ?: "Unknown" - else -> when { - model.isNullOrBlank() -> "$manufacturer Device" - else -> "$manufacturer $model" - } + model.isNullOrBlank() -> "$manufacturer Device" + else -> "$manufacturer $model" } + } } diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisioner.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisioner.kt index bb47ecb1e9..eb0c983377 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisioner.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisioner.kt @@ -66,7 +66,9 @@ private constructor( // We want to update whenever the ConnectedDevicesTracker updates, or when one of the // devices' deviceInfoFlow updates (to know when the device comes online, since it will // often appear initially in an offline state, and we ignore offline devices). - adbSession.connectedDevicesTracker.connectedDevices + adbSession + .connectedDevicesTracker + .connectedDevices .flatMapLatest { devices -> combine(devices.map { device -> device.deviceInfoFlow.map { Pair(device, it) } }) { it.mapNotNull { (device, info) -> diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisionerPlugin.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisionerPlugin.kt index b3c56e1dcc..cec13a9925 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisionerPlugin.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceProvisionerPlugin.kt @@ -24,9 +24,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -/** - * A component of [DeviceProvisioner] responsible for a particular class of device. - */ +/** A component of [DeviceProvisioner] responsible for a particular class of device. */ interface DeviceProvisionerPlugin { /** @@ -56,28 +54,20 @@ interface DeviceProvisionerPlugin { val templates: StateFlow<List<DeviceTemplate>> get() = MutableStateFlow(emptyList<DeviceTemplate>()).asStateFlow() - /** - * A [DeviceAction] that creates a device, typically based on input from the user. - */ + /** A [DeviceAction] that creates a device, typically based on input from the user. */ val createDeviceAction: CreateDeviceAction? get() = null - /** - * A [DeviceAction] that creates a template, typically based on input from the user. - */ + /** A [DeviceAction] that creates a template, typically based on input from the user. */ val createDeviceTemplateAction: CreateDeviceTemplateAction? get() = null } -/** - * On device disconnection, runs the given block in the [AdbSession] scope. - */ +/** On device disconnection, runs the given block in the [AdbSession] scope. */ fun ConnectedDevice.invokeOnDisconnection(block: suspend () -> Unit) { scope.coroutineContext[Job]?.invokeOnCompletion { // Run the block in the AdbSession scope, since this CompletionHandler must // be fast, non-blocking, and thread-safe, and not throw exceptions. - session.scope.launch { - block() - } + session.scope.launch { block() } } } diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceState.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceState.kt index 42b04859b1..e05320e2af 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceState.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceState.kt @@ -17,8 +17,8 @@ package com.android.sdklib.deviceprovisioner import com.android.adblib.ConnectedDevice import com.google.common.base.Stopwatch -import kotlinx.coroutines.Job import java.time.Duration +import kotlinx.coroutines.Job /** * Identifies the state of a provisionable device with respect to ADB: disconnected, connecting, diff --git a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceTemplate.kt b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceTemplate.kt index b297b8f3f2..ad0f34ab0b 100644 --- a/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceTemplate.kt +++ b/device-provisioner/src/main/com/android/sdklib/deviceprovisioner/DeviceTemplate.kt @@ -16,14 +16,14 @@ package com.android.sdklib.deviceprovisioner /** - * A DeviceTemplate contains the information necessary to activate / lease a device - * from a provisioner. In contrast to a DeviceHandle, it does not refer to a specific device: - * each activation produces a different device. + * A DeviceTemplate contains the information necessary to activate / lease a device from a + * provisioner. In contrast to a DeviceHandle, it does not refer to a specific device: each + * activation produces a different device. */ interface DeviceTemplate { - val displayName: String + val displayName: String - val activationAction: ActivationAction + val activationAction: ActivationAction - val editAction: EditTemplateAction + val editAction: EditTemplateAction? } diff --git a/device-provisioner/src/test/com/android/sdklib/deviceprovisioner/DeviceProvisionerTest.kt b/device-provisioner/src/test/com/android/sdklib/deviceprovisioner/DeviceProvisionerTest.kt index 4b09d83506..74af6d1ef3 100644 --- a/device-provisioner/src/test/com/android/sdklib/deviceprovisioner/DeviceProvisionerTest.kt +++ b/device-provisioner/src/test/com/android/sdklib/deviceprovisioner/DeviceProvisionerTest.kt @@ -199,8 +199,8 @@ class DeviceProvisionerTest { /** * Receives messages on this channel until one is received that does not cause an [AssertionError] - * in the supplied block. This should be used within a withTimeout() block. If timeout occurs, throws - * a new AssertionError with the last received error as a cause, if one was received. + * in the supplied block. This should be used within a withTimeout() block. If timeout occurs, + * throws a new AssertionError with the last received error as a cause, if one was received. */ suspend fun <T, R> Channel<T>.receiveUntilPassing(block: (T) -> R): R { var lastError: AssertionError? = null diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/DeviceState.java b/fakeadbserver/src/main/java/com/android/fakeadbserver/DeviceState.java index 649120cc39..ca92f065f3 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/DeviceState.java +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/DeviceState.java @@ -32,6 +32,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.Vector; import java.util.stream.Collectors; @@ -69,6 +70,8 @@ public class DeviceState { private final String mCpuAbi; + private final Map<String, String> mProperties; + private DeviceStatus mDeviceStatus; private final ServiceManager mServiceManager; @@ -90,6 +93,7 @@ public class DeviceState { @NonNull String release, @NonNull String sdk, @NonNull String cpuAbi, + @NonNull Map<String, String> properties, @NonNull HostConnectionType hostConnectionType, int transportId) { mServer = server; @@ -100,6 +104,7 @@ public class DeviceState { mBuildVersionSdk = sdk; mCpuAbi = cpuAbi; mFeatures = initFeatures(sdk); + mProperties = combinedProperties(manufacturer, model, release, sdk, cpuAbi, properties); mHostConnectionType = hostConnectionType; myTransportId = transportId; mDeviceStatus = DeviceStatus.OFFLINE; @@ -115,6 +120,7 @@ public class DeviceState { config.getBuildVersionRelease(), config.getBuildVersionSdk(), config.getCpuAbi(), + config.getProperties(), config.getHostConnectionType(), transportId); config.getFiles().forEach(fileState -> mFiles.put(fileState.getPath(), fileState)); @@ -165,6 +171,10 @@ public class DeviceState { } } + public Map<String, String> getProperties() { + return mProperties; + } + @NonNull public DeviceStatus getDeviceStatus() { return mDeviceStatus; @@ -354,6 +364,7 @@ public class DeviceState { mBuildVersionRelease, mBuildVersionSdk, mCpuAbi, + mProperties, mDeviceStatus); } @@ -416,6 +427,22 @@ public class DeviceState { return (List<String>) mAbbLogs.clone(); } + private static Map<String, String> combinedProperties( + @NonNull String manufacturer, + @NonNull String model, + @NonNull String release, + @NonNull String sdk, + @NonNull String cpuAbi, + @NonNull Map<String, String> properties) { + Map<String, String> combined = new TreeMap<>(properties); + combined.put("ro.product.manufacturer", manufacturer); + combined.put("ro.product.model", model); + combined.put("ro.build.version.release", release); + combined.put("ro.build.version.sdk", sdk); + combined.put("ro.product.cpu.abi", cpuAbi); + return combined; + } + /** * The state of a device. */ diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServer.java b/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServer.java index a7a8ddd397..0fb881c997 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServer.java +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServer.java @@ -249,7 +249,7 @@ public final class FakeAdbServer implements AutoCloseable { * for handlers that inherit from {@link CommandHandler}. The purpose of the hub is to propagate * server events to existing connections with the server. * - * <p>For example, if {@link #connectDevice(String, String, String, String, String, + * <p>For example, if {@link #connectDevice(String, String, String, String, String, Map, * DeviceState.HostConnectionType)} is called, an event will be sent through the {@link * DeviceStateChangeHub} to all open connections waiting on host:track-devices messages. */ @@ -267,6 +267,7 @@ public final class FakeAdbServer implements AutoCloseable { * @param release is the Android OS version of the device * @param sdk is the SDK version of the device * @param cpuAbi is the ABI of the device CPU + * @param properties is the device properties * @param hostConnectionType is the simulated connection type to the device @return the future * @return a future to allow synchronization of the side effects of the call */ @@ -277,6 +278,7 @@ public final class FakeAdbServer implements AutoCloseable { @NonNull String release, @NonNull String sdk, @NonNull String cpuAbi, + @NonNull Map<String, String> properties, @NonNull DeviceState.HostConnectionType hostConnectionType) { DeviceState device = new DeviceState( @@ -287,6 +289,7 @@ public final class FakeAdbServer implements AutoCloseable { release, sdk, cpuAbi, + properties, hostConnectionType, newTransportId()); if (mConnectionHandlerTask == null) { @@ -318,6 +321,7 @@ public final class FakeAdbServer implements AutoCloseable { release, sdk, "x86_64", + Collections.emptyMap(), hostConnectionType); } diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServerConfig.kt b/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServerConfig.kt index 89f1438748..0bd94089dc 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServerConfig.kt +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/FakeAdbServerConfig.kt @@ -50,5 +50,6 @@ class DeviceStateConfig( val buildVersionRelease: String, val buildVersionSdk: String, val cpuAbi: String, + val properties: Map<String, String>, var deviceStatus: DeviceState.DeviceStatus, ) diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/execcommandhandlers/GetPropExecCommandHandler.kt b/fakeadbserver/src/main/java/com/android/fakeadbserver/execcommandhandlers/GetPropExecCommandHandler.kt index 45c733c9c4..701f89ae26 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/execcommandhandlers/GetPropExecCommandHandler.kt +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/execcommandhandlers/GetPropExecCommandHandler.kt @@ -30,16 +30,13 @@ class GetPropExecCommandHandler : SimpleExecHandler("getprop") { ) { val stream = responseSocket.getOutputStream() writeOkay(stream) // Send ok first. - val builder = """ - # This is some build info - # This is more build info - - [ro.product.manufacturer]: [${device.manufacturer}] - [ro.product.model]: [${device.model}] - [ro.build.version.release]: [${device.buildVersionRelease}] - [ro.build.version.sdk]: [${device.buildVersionSdk}] - - """.trimIndent() - stream.write(builder.toByteArray(Charsets.UTF_8)) + val buf = StringBuilder() + buf.append("# This is some build info\n") + buf.append("# This is more build info\n") + buf.append("\n") + for (entry in device.properties) { + buf.append("[${entry.key}]: [${entry.value}]\n") + } + stream.write(buf.toString().toByteArray(Charsets.UTF_8)) } } diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/shellcommandhandlers/GetPropCommandHandler.java b/fakeadbserver/src/main/java/com/android/fakeadbserver/shellcommandhandlers/GetPropCommandHandler.java index 316d3fabc8..6fe13babf0 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/shellcommandhandlers/GetPropCommandHandler.java +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/shellcommandhandlers/GetPropCommandHandler.java @@ -25,6 +25,7 @@ import com.google.common.base.Charsets; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; +import java.util.Map; /** shell:getprop gets the device properties of the specified device. */ public class GetPropCommandHandler extends SimpleShellHandler { @@ -42,25 +43,18 @@ public class GetPropCommandHandler extends SimpleShellHandler { try { OutputStream stream = responseSocket.getOutputStream(); CommandHandler.writeOkay(stream); // Send ok first. - String builder = - "# This is some build info\n" - + "# This is more build info\n\n" - + "[ro.product.cpu.abi]: [" - + device.getCpuAbi() - + "]\n" - + "[ro.product.manufacturer]: [" - + device.getManufacturer() - + "]\n" - + "[ro.product.model]: [" - + device.getModel() - + "]\n" - + "[ro.build.version.release]: [" - + device.getBuildVersionRelease() - + "]\n" - + "[ro.build.version.sdk]: [" - + device.getBuildVersionSdk() - + "]\n"; - stream.write(builder.getBytes(Charsets.UTF_8)); + StringBuilder buf = new StringBuilder(); + buf.append("# This is some build info\n"); + buf.append("# This is more build info\n"); + buf.append("\n"); + for (Map.Entry<String, String> entry : device.getProperties().entrySet()) { + buf.append('['); + buf.append(entry.getKey()); + buf.append("]: ["); + buf.append(entry.getValue()); + buf.append("]\n"); + } + stream.write(buf.toString().getBytes(Charsets.UTF_8)); } catch (IOException ignored) { } } diff --git a/fakeadbserver/src/main/java/com/android/fakeadbserver/shellv2commandhandlers/GetPropV2CommandHandler.kt b/fakeadbserver/src/main/java/com/android/fakeadbserver/shellv2commandhandlers/GetPropV2CommandHandler.kt index 477e3652c9..2e092a44fa 100644 --- a/fakeadbserver/src/main/java/com/android/fakeadbserver/shellv2commandhandlers/GetPropV2CommandHandler.kt +++ b/fakeadbserver/src/main/java/com/android/fakeadbserver/shellv2commandhandlers/GetPropV2CommandHandler.kt @@ -34,17 +34,14 @@ class GetPropV2CommandHandler : SimpleShellV2Handler("getprop") { ) { protocol.writeOkay() - val builder = """ - # This is some build info - # This is more build info - - [ro.product.manufacturer]: [${device.manufacturer}] - [ro.product.model]: [${device.model}] - [ro.build.version.release]: [${device.buildVersionRelease}] - [ro.build.version.sdk]: [${device.buildVersionSdk}] - - """.trimIndent() - protocol.writeStdout(builder.toByteArray(Charsets.UTF_8)) + val buf = StringBuilder() + buf.append("# This is some build info\n") + buf.append("# This is more build info\n") + buf.append("\n") + for (entry in device.properties) { + buf.append("[${entry.key}]: [${entry.value}]\n") + } + protocol.writeStdout(buf.toString().toByteArray(Charsets.UTF_8)) protocol.writeExitCode(0) } } diff --git a/gmaven/src/test/resources/com/android/tools/test/gmaven-aars.txt b/gmaven/src/test/resources/com/android/tools/test/gmaven-aars.txt index 9886730e33..2f2fe602c3 100644 --- a/gmaven/src/test/resources/com/android/tools/test/gmaven-aars.txt +++ b/gmaven/src/test/resources/com/android/tools/test/gmaven-aars.txt @@ -17,7 +17,6 @@ androidx/databinding/databinding-adapters res/ res/values/ res/values/values.xml - values/ androidx/databinding/databinding-ktx AndroidManifest.xml @@ -44,7 +43,6 @@ androidx/databinding/databinding-runtime res/ res/values/ res/values/values.xml - values/ androidx/databinding/viewbinding AndroidManifest.xml @@ -77,7 +75,6 @@ com/android/databinding/adapters res/ res/values/ res/values/values.xml - values/ com/android/databinding/library AndroidManifest.xml @@ -95,7 +92,6 @@ com/android/databinding/library res/ res/values/ res/values/values.xml - values/ com/android/databinding/viewbinding AndroidManifest.xml diff --git a/gmaven/src/test/resources/com/android/tools/test/gmaven-jars.txt b/gmaven/src/test/resources/com/android/tools/test/gmaven-jars.txt index 21918747bb..1576336dd5 100644 --- a/gmaven/src/test/resources/com/android/tools/test/gmaven-jars.txt +++ b/gmaven/src/test/resources/com/android/tools/test/gmaven-jars.txt @@ -420,6 +420,7 @@ com/android/tools/build/gradle com/android/build/gradle/internal/component/legacy/ com/android/build/gradle/internal/core/ com/android/build/gradle/internal/core/dsl/ + com/android/build/gradle/internal/core/dsl/impl/ com/android/build/gradle/internal/coverage/ com/android/build/gradle/internal/crash/ com/android/build/gradle/internal/cxx/ diff --git a/lint/cli/src/main/java/com/android/tools/lint/LintFixPerformer.kt b/lint/cli/src/main/java/com/android/tools/lint/LintFixPerformer.kt index de7a0ff56f..3c175d2f48 100644 --- a/lint/cli/src/main/java/com/android/tools/lint/LintFixPerformer.kt +++ b/lint/cli/src/main/java/com/android/tools/lint/LintFixPerformer.kt @@ -740,7 +740,7 @@ open class LintFixPerformer constructor( if (to == -1) { to = line.length } - imported.add(line.substring("package ".length, to).trim { it <= ' ' } + ".") + imported.add(line.substring("package ".length, to).trim() + ".") } else if (line.startsWith("import ")) { var from = "import ".length if (line.startsWith("static ", from)) { @@ -753,7 +753,7 @@ open class LintFixPerformer constructor( if (line[to - 1] == '*') { to-- } - imported.add(line.substring(from, to).trim { it <= ' ' }) + imported.add(line.substring(from, to).trim()) } } for (full in imported) { @@ -766,7 +766,7 @@ open class LintFixPerformer constructor( } clz = clz.substring(0, index + 1) } - replacement = replacement.replace(clz, "") + replacement = removePackage(replacement, clz) } } } @@ -807,6 +807,53 @@ open class LintFixPerformer constructor( return true } + /** + * Given a package [prefix] and a Java/Kotlin source fragment, removes the + * package prefix from any fully qualified references with that package + * prefix. The reason we can't just use [String.replace] is that we only + * want to replace prefixes in the same package, not in any sub packages. + * + * For example, given the package prefix `p1.p2`, for the source + * string `p1.p2.p3.Class1, `p1.p2.Class2`, this method will return + * `p1.p2.p3.Class1, Class2`. + */ + private fun removePackage(source: String, prefix: String): String { + if (prefix.isEmpty()) { + return source + } + + // Checks whether the symbol starting at offset [next] references + // the [prefix] package and not potentially some subpackage of it + fun isPackageMatchAt(next: Int): Boolean { + var i = next + prefix.length + while (i < source.length) { + val c = source[i++] + if (c == '.') { + return false + } else if (!c.isJavaIdentifierPart()) { + return true + } + } + return true + } + + val sb = StringBuilder() + var index = 0 + while (true) { + val next = source.indexOf(prefix, index) + sb.append(source.substring(index, if (next == -1) source.length else next)) + if (next == -1) { + break + } + index = next + prefix.length + if ((index == source.length || !source[index].isUpperCase()) && !isPackageMatchAt(next)) { + sb.append(source.substring(next, index)) + } + } + + return sb.toString() + } + fun computeEdits(incident: Incident, lintFix: LintFix): List<PendingEditFile> { val fileMap = mutableMapOf<File, PendingEditFile>() registerFix(fileMap, incident, lintFix) diff --git a/lint/cli/src/main/java/com/android/tools/lint/UastEnvironment.kt b/lint/cli/src/main/java/com/android/tools/lint/UastEnvironment.kt index f0842f116d..6c251ce9c4 100644 --- a/lint/cli/src/main/java/com/android/tools/lint/UastEnvironment.kt +++ b/lint/cli/src/main/java/com/android/tools/lint/UastEnvironment.kt @@ -129,7 +129,7 @@ interface UastEnvironment { fun create( config: Configuration, ): UastEnvironment { - return when(config) { + return when (config) { is FirUastEnvironment.Configuration -> FirUastEnvironment.create(config) else -> diff --git a/lint/cli/src/main/java/com/android/tools/lint/gradle/GroovyGradleVisitor.java b/lint/cli/src/main/java/com/android/tools/lint/gradle/GroovyGradleVisitor.java index e9d09f853c..35fb93caea 100644 --- a/lint/cli/src/main/java/com/android/tools/lint/gradle/GroovyGradleVisitor.java +++ b/lint/cli/src/main/java/com/android/tools/lint/gradle/GroovyGradleVisitor.java @@ -20,6 +20,7 @@ import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.lint.checks.GradleDetector; import com.android.tools.lint.client.api.GradleVisitor; +import com.android.tools.lint.client.api.LintClient; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.DefaultPosition; import com.android.tools.lint.detector.api.GradleContext; @@ -55,6 +56,11 @@ public class GroovyGradleVisitor extends GradleVisitor { @NonNull GradleContext context, @NonNull List<? extends GradleScanner> detectors) { try { visitQuietly(context, detectors); + } catch (AssertionError e) { + // Test infrastructure checks + if (LintClient.isUnitTest()) { + throw e; + } } catch (Throwable t) { // else: ignore // Parsing the build script can involve class loading that we sometimes can't diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/JarFileIssueRegistry.kt b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/JarFileIssueRegistry.kt index 482361ec65..271b31d6c8 100644 --- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/JarFileIssueRegistry.kt +++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/JarFileIssueRegistry.kt @@ -331,16 +331,6 @@ The Lint API version currently running is $CURRENT_API (${describeApi(CURRENT_AP } recordRejectedIssues(issues) return null - } else if (verifier.hasPackageConflict()) { - if (reportErrors(driver)) { - val message = getPackagingConflictMessage(className, verifier) - LintClient.report( - client = client, issue = OBSOLETE_LINT_CHECK, - message = message, file = jarFile, project = currentProject, driver = driver - ) - } - recordRejectedIssues(issues) - return null } // Not returning here: try to run the checks } else { @@ -393,16 +383,6 @@ The Lint API version currently running is $CURRENT_API (${describeApi(CURRENT_AP } recordRejectedIssues(issues) return null - } else if (verifier.hasPackageConflict()) { - if (reportErrors(driver)) { - val message = getPackagingConflictMessage(className, verifier) - LintClient.report( - client = client, issue = OBSOLETE_LINT_CHECK, - message = message, file = jarFile, project = currentProject, driver = driver - ) - } - recordRejectedIssues(issues) - return null } } } catch (e: Throwable) { @@ -485,33 +465,6 @@ The Lint API version currently running is $CURRENT_API (${describeApi(CURRENT_AP issues.forEach { rejectedIssues.add(it.id) } } - private fun getPackagingConflictMessage(className: String, verifier: LintJarVerifier): String { - return """ -Lint found an issue registry (`$className`) -which contains code in some of lint's reserved packages. - -This is usually because the lint jar has accidentally -packed in libraries that are part of lint's API surface, -such as the Kotlin standard library (`kotlin.*`), or -some of the Android tooling libraries (`com.android.*`) -including lint's own API jars, or some of the third party -libraries that lint depends on, such as UAST. -If you need these and cannot rely on the ones provided -in lint's runtime environment, consider `jarjar`ing your -own versions. - -A second reason is one where you've accidentally placed -your own detector code into one of these package -namespaces, since they are pretty broad (`com.android.*`). -For Android specifically, you can place them under -`com.android.internal.*` which is explicitly allowed. - -The first bundled package that is part of lint's API -surface namespace is: -${verifier.describeFirstPackagedDependency()} -""".trim() - } - private fun getVendor( client: LintClient, registry: IssueRegistry, diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintDriver.kt b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintDriver.kt index fb8796dc3c..be66a6c772 100644 --- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintDriver.kt +++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintDriver.kt @@ -3429,7 +3429,7 @@ class LintDriver( names: Collection<String>? ) { var message = "Issue `${issue.id}` is not allowed to be suppressed" - if (names?.isNotEmpty() == true) { + if (names?.isNotEmpty() == true && context !is XmlContext) { message += " (but can be with ${ formatList( names.map { "`@$it`" }.toList(), @@ -3489,6 +3489,12 @@ class LintDriver( } } + val customSuppressNames = if (!allowSuppress) { + issue.suppressNames?.toSet() + } else { + null + } + var currentNode = node if (currentNode is Attr) { currentNode = currentNode.ownerElement @@ -3501,9 +3507,27 @@ class LintDriver( if (element.hasAttributeNS(TOOLS_URI, ATTR_IGNORE)) { val ignore = element.getAttributeNS(TOOLS_URI, ATTR_IGNORE) if (isSuppressed(issue, ignore)) { + if (customSuppressNames != null && context != null) { + flagInvalidSuppress( + context, issue, context.getLocation(currentNode), + currentNode, issue.suppressNames + ) + return false + } + return true + } + if (customSuppressNames != null && isSuppressed(customSuppressNames, ignore)) { return true } - } else if (checkComments && context!!.isSuppressedWithComment(currentNode, issue)) { + } else if (checkComments && context != null && context.isSuppressedWithComment(currentNode, issue)) { + if (customSuppressNames != null) { + flagInvalidSuppress( + context, issue, context.getLocation(currentNode), + currentNode, issue.suppressNames + ) + return false + } + return true } } @@ -3959,6 +3983,30 @@ class LintDriver( return false } + private fun isSuppressed(issueIds: Collection<String>, string: String): Boolean { + return issueIds.any { isSuppressed(it, string) } + } + + private fun isSuppressed(issueId: String, string: String): Boolean { + if (string.isEmpty()) { + return false + } + + if (string.indexOf(',') == -1) { + if (matches(issueId, string)) { + return true + } + } else { + for (id in Splitter.on(',').trimResults().split(string)) { + if (matches(issueId, id)) { + return true + } + } + } + + return false + } + /** * Returns true if the given AST modifier has a suppress * annotation for the given issue (which can be null to check diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintJarVerifier.kt b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintJarVerifier.kt index a9e5acd4d4..d64a91ea8f 100644 --- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintJarVerifier.kt +++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/LintJarVerifier.kt @@ -51,23 +51,14 @@ class LintJarVerifier(jarFile: File) : ClassVisitor(ASM9) { * we want to check for validity? */ private fun isRelevantApi(internal: String): Boolean { + val relevant = internal.startsWith("com/android/") || + // Imported APIs + internal.startsWith("org/jetbrains/uast") || + internal.startsWith("org/jetbrains/kotlin") || + internal.startsWith("com/intellij") // Libraries unlikely to change: org.w3c.dom, org.objectweb.asm, org.xmlpull, etc. - if (internal.startsWith("com/android/") && - // Reserved for various Android-internal checks such as CallingIdentityTokenDetector in AOSP - !internal.startsWith("com/android/internal/") && - // We have a few clashes with this namespace which are not part of - // the API surface; remove these - !internal.startsWith("com/android/tools/lint/checks/studio/") && - !internal.startsWith("com/android/tools/lint/checks/infrastructure/") - ) { - return true - } - // Imported APIs - return internal.startsWith("org/jetbrains/uast") || - internal.startsWith("org/jetbrains/kotlin/psi") || - internal.startsWith("org/jetbrains/kotlin/asJava") || - internal.startsWith("com/intellij/psi") + return relevant && !bundledClasses.contains(internal) } /** @@ -79,14 +70,6 @@ class LintJarVerifier(jarFile: File) : ClassVisitor(ASM9) { return incompatibleReference == null } - /** - * Returns true if the lint jar contains classes that conflict with - * (or are repackaging) lint's own API surface. - */ - fun hasPackageConflict(): Boolean { - return packageConflict != null - } - fun getVerificationThrowable(): Throwable? = verifyProblem /** @@ -97,39 +80,38 @@ class LintJarVerifier(jarFile: File) : ClassVisitor(ASM9) { // Scans through the bytecode for all the classes in lint.jar, and // checks any class, method or field reference accessing the Lint API // and makes sure that API is found in the bytecode + val classes = mutableMapOf<String, ByteArray>() JarFile(lintJar).use { jar -> jar.entries().also { entries -> - var firstInDir = true while (entries.hasMoreElements()) { (entries.nextElement() as java.util.jar.JarEntry).also { entry -> val directory = entry.isDirectory val name = entry.name - if (directory) { - firstInDir = true - } else if (name.endsWith(DOT_CLASS)) { - if (firstInDir) { - if (packageConflict == null) { - val packageOwner = name.substring(0, name.lastIndexOf('/') + 1) - if (isRelevantApi(packageOwner)) { - packageConflict = packageOwner - } - } - firstInDir = false - } - currentClassFile = name + if (!directory && name.endsWith(DOT_CLASS)) { jar.getInputStream(entry).use { stream -> val bytes = ByteStreams.toByteArray(stream) - val reader = ClassReader(bytes) - reader.accept(this, SKIP_DEBUG or SKIP_FRAMES) - if (incompatibleReference != null) { - return - } + classes[name] = bytes } } } } } } + + classes.forEach { (name, _) -> + // Note that jar file internal names always use forward slash, not File.separator + // so we can compute the internal name by just dropping the .class suffix + bundledClasses.add(name.removeSuffix(DOT_CLASS)) + } + + for ((name, bytes) in classes) { + currentClassFile = name + val reader = ClassReader(bytes) + reader.accept(this, SKIP_DEBUG or SKIP_FRAMES) + if (incompatibleReference != null) { + return + } + } } /** Returns a message describing the incompatibility */ @@ -170,9 +152,6 @@ class LintJarVerifier(jarFile: File) : ClassVisitor(ASM9) { return incompatibleReferencer!! // should only be called if incompatibleReference is non null } - fun describeFirstPackagedDependency(): String = - packageConflict?.replace('/', '.')?.removeSuffix(".") ?: "None" - /** * An exception thrown if there is some other verification problem * (invalid class file etc) @@ -182,15 +161,15 @@ class LintJarVerifier(jarFile: File) : ClassVisitor(ASM9) { /** The internal name of the invalid reference. */ private var incompatibleReference: String? = null + /** The internal names of the classes in the Jar file */ + private val bundledClasses: MutableSet<String> = mutableSetOf() + /** * The class file containing the reference to * [incompatibleReference] */ private var incompatibleReferencer: String? = null - /** The first conflicting package found */ - private var packageConflict: String? = null - private val methodVisitor = object : MethodVisitor(ASM9) { override fun visitMethodInsn( opcode: Int, diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/UastLintUtils.kt b/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/UastLintUtils.kt index b87a702441..c65691c8a7 100644 --- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/UastLintUtils.kt +++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/UastLintUtils.kt @@ -29,6 +29,7 @@ import com.intellij.psi.PsiMethod import com.intellij.psi.PsiModifier import com.intellij.psi.PsiParameter import com.intellij.psi.PsiVariable +import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.uast.UAnnotation @@ -493,6 +494,16 @@ fun UElement.isBelow(parent: UElement, strict: Boolean = false): Boolean { } /** + * Returns true if [this] element is a child or indirect child of the + * given [parent]. If [strict] is false, this method will return true + * when [parent] is the same as [this]. + */ +fun PsiElement?.isBelow(parent: PsiElement, strict: Boolean = false): Boolean { + this ?: return false + return PsiTreeUtil.isAncestor(parent, this, strict) +} + +/** * Like [UFile.accept], but in the case of multi-file classes (where * multiple source files containing top level declarations are annotated * with `@JvmMultifileClass`, all naming the same target class) the diff --git a/lint/libs/lint-api/src/main/java/com/android/tools/lint/helpers/DefaultUastParser.kt b/lint/libs/lint-api/src/main/java/com/android/tools/lint/helpers/DefaultUastParser.kt index aa8c58818d..ec0a0fbeef 100644 --- a/lint/libs/lint-api/src/main/java/com/android/tools/lint/helpers/DefaultUastParser.kt +++ b/lint/libs/lint-api/src/main/java/com/android/tools/lint/helpers/DefaultUastParser.kt @@ -137,7 +137,9 @@ open class DefaultUastParser( if (psiFile is PsiPlainTextFile) { // plain text: file too large to process with PSI if (!warnedAboutLargeFiles) { warnedAboutLargeFiles = true - val max = FileUtilRt.getUserFileSizeLimit() + // default user file size limit = 2500 KiB + // default user content load limit = 20000 KiB + val max = max(FileUtilRt.getUserFileSizeLimit(), FileUtilRt.getUserContentLoadLimit()) / 1024 val size = file.length() / 1024 val sizeRoundedUp = 2.0.pow(ceil(log10(size.toDouble()) / log10(2.0) + 0.2)).toInt() context.report( diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CheckResultDetector.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CheckResultDetector.kt index ad72c0bcbd..4173191ee1 100644 --- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CheckResultDetector.kt +++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CheckResultDetector.kt @@ -30,6 +30,7 @@ import com.android.tools.lint.detector.api.SourceCodeScanner import com.android.tools.lint.detector.api.UImplicitCallExpression import com.android.tools.lint.detector.api.UastLintUtils.Companion.getAnnotationStringValue import com.android.tools.lint.detector.api.findSelector +import com.android.tools.lint.detector.api.isBelow import com.android.tools.lint.detector.api.isJava import com.android.tools.lint.detector.api.isKotlin import com.android.tools.lint.detector.api.nextStatement @@ -313,11 +314,15 @@ class CheckResultDetector : AbstractAnnotationDetector(), SourceCodeScanner { curr = curr.uastParent ?: return true } - @Suppress("RedundantIf") if (curr is UBlockExpression) { - if (curr.sourcePsi is PsiSynchronizedStatement) { - return false + val sourcePsi = curr.sourcePsi + if (sourcePsi is PsiSynchronizedStatement) { + val lock = sourcePsi.lockExpression + if (lock != null && element.sourcePsi.isBelow(lock)) { + return false + } } + // In Java, it's apparent when an expression is unused: // the parent is a block expression. However, in Kotlin it's // much trickier: values can flow through blocks and up through @@ -342,7 +347,7 @@ class CheckResultDetector : AbstractAnnotationDetector(), SourceCodeScanner { // It's the last child: see if the parent is unused val parent = skipParenthesizedExprUp(curr.uastParent) - if (parent is ULambdaExpression && isKotlin(curr.sourcePsi)) { + if (parent is ULambdaExpression && isKotlin(sourcePsi)) { val expressionType = parent.getExpressionType()?.canonicalText if (expressionType != null && expressionType.startsWith("kotlin.jvm.functions.Function") && @@ -357,7 +362,7 @@ class CheckResultDetector : AbstractAnnotationDetector(), SourceCodeScanner { return false } - if (isJava(curr.sourcePsi)) { + if (isJava(sourcePsi)) { // In Java there's no implicit passing to the parent return true } diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.kt index 92b974986d..5ab0ff488c 100644 --- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.kt +++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.kt @@ -108,8 +108,9 @@ class DeprecationDetector : ResourceXmlDetector(), SourceCodeScanner { return listOf(ABSOLUTE_LAYOUT, TAG_USES_PERMISSION_SDK_M) } - override fun getApplicableAttributes(): Collection<String>? { + override fun getApplicableAttributes(): Collection<String> { return listOf( + ATTR_USER_SHARED_ID, // TODO: fill_parent is deprecated as of API 8. // We could warn about it, but it will probably be very noisy // and make people disable the deprecation check; let's focus on @@ -158,6 +159,16 @@ class DeprecationDetector : ResourceXmlDetector(), SourceCodeScanner { val fix: String var minSdk = 1 when (name) { + ATTR_USER_SHARED_ID -> { + if (!attribute.ownerElement.hasAttributeNS(ANDROID_URI, ATTR_SHARED_USER_MAX_SDK_VERSION)) { + fix = "Consider removing `$ATTR_USER_SHARED_ID` for new users by adding " + + "`android:sharedUserMaxSdkVersion=\"32\"` to your manifest. " + + "See https://developer.android.com/guide/topics/manifest/manifest-element for details." + val addFix = fix().set(ANDROID_URI, ATTR_SHARED_USER_MAX_SDK_VERSION, "32").build() + context.report(ISSUE, attribute, context.getLocation(attribute), fix, addFix) + } + return + } ATTR_PERMISSION -> { if (TAG_SERVICE == attribute.ownerElement.tagName && CHOOSER_TARGET_SERVICE_PERM == attribute.value @@ -302,6 +313,9 @@ class DeprecationDetector : ResourceXmlDetector(), SourceCodeScanner { private const val APP_ACTIONS_MIGRATION_URL = "https://developers.google.com/assistant/app/legacy/migration-guide" + private const val ATTR_USER_SHARED_ID = "sharedUserId" + private const val ATTR_SHARED_USER_MAX_SDK_VERSION = "sharedUserMaxSdkVersion" + /** Usage of deprecated views or attributes. */ @JvmField val ISSUE = create( diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt index 584942531c..ab3bcd51e4 100644 --- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt +++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GooglePlaySdkIndex.kt @@ -49,6 +49,7 @@ abstract class GooglePlaySdkIndex(cacheDir: Path? = null) : NetworkCache( const val VIEW_DETAILS_MESSAGE = "View details in Google Play SDK Index" } + private lateinit var lastReadResult: ReadDataResult private var initialized: Boolean = false private var status: GooglePlaySdkIndexStatus = GooglePlaySdkIndexStatus.NOT_READY private val libraryToSdk = HashMap<String, LibraryToSdk>() @@ -66,6 +67,25 @@ abstract class GooglePlaySdkIndex(cacheDir: Path? = null) : NetworkCache( initialize(null) } + private fun readIndexData(readFunction: () -> InputStream?): ReadDataResult { + var readDataErrorType = ReadDataErrorType.DATA_FUNCTION_EXCEPTION + try { + val rawData = readFunction.invoke() + if (rawData != null) { + readDataErrorType = ReadDataErrorType.GZIP_EXCEPTION + val gzipData = GZIPInputStream(rawData) + readDataErrorType = ReadDataErrorType.INDEX_PARSE_EXCEPTION + val index = Index.parseFrom(gzipData) + readDataErrorType = if (index != null) ReadDataErrorType.NO_ERROR else ReadDataErrorType.INDEX_PARSE_NULL_ERROR + return ReadDataResult(index, readDataErrorType, exception = null) + } + } + catch (exception: Exception) { + return ReadDataResult(index = null, readDataErrorType, exception) + } + return ReadDataResult(index = null, readDataErrorType = ReadDataErrorType.DATA_FUNCTION_NULL_ERROR, exception = null) + } + @VisibleForTesting fun initialize(overriddenData: InputStream? = null) { synchronized(this) { @@ -76,27 +96,45 @@ abstract class GooglePlaySdkIndex(cacheDir: Path? = null) : NetworkCache( status = GooglePlaySdkIndexStatus.NOT_READY } var index: Index? = null + val indexDataSource: DataSourceType // Read from cache/network if (overriddenData != null) { // Do not check for exceptions, calling from a test + lastReadSourceType = DataSourceType.TEST_DATA + indexDataSource = lastReadSourceType index = Index.parseFrom(overriddenData) - } else { - try { - index = Index.parseFrom(GZIPInputStream(findData(GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_FILE))) - } catch (exception: Exception) { - val message = if (exception.message.isNullOrEmpty()) exception.toString() else exception.message - logCachingError(message) - try { - index = Index.parseFrom(GZIPInputStream(readDefaultData(GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_RESOURCE))) - } catch (defaultException: Exception) { - logErrorInDefaultData(defaultException.message) + } + else { + lastReadResult = readIndexData { findData(GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_FILE) } + if (lastReadResult.index != null) { + // Using data from cache + indexDataSource = lastReadSourceType + index = lastReadResult.index + } + else { + if (lastReadSourceType != DataSourceType.DEFAULT_DATA) { + lastReadSourceType = DataSourceType.UNKNOWN_SOURCE + val offlineResult = readIndexData { + readDefaultData(GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_RESOURCE) + } + if (offlineResult.index != null) { + indexDataSource = DataSourceType.DEFAULT_DATA + index = offlineResult.index + } else { + indexDataSource = DataSourceType.UNKNOWN_SOURCE + logErrorInDefaultData(offlineResult) + } + } + else { + indexDataSource = DataSourceType.UNKNOWN_SOURCE + logErrorInDefaultData(lastReadResult) } } } if (index != null) { setMaps(index) status = GooglePlaySdkIndexStatus.READY - logIndexLoadedCorrectly() + logIndexLoadedCorrectly(indexDataSource) } } @@ -259,10 +297,13 @@ abstract class GooglePlaySdkIndex(cacheDir: Path? = null) : NetworkCache( } override fun readDefaultData(relative: String): InputStream? { - if (GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_RESOURCE == relative) { - return GooglePlaySdkIndex::class.java.getResourceAsStream("/$GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_RESOURCE") + // This function is called only if there were errors while reading the cached data, log that error if the previous source was known + if (lastReadSourceType != DataSourceType.UNKNOWN_SOURCE) { + // Log reason for not being able to use cached file + logCachingError(lastReadResult, lastReadSourceType) } - return null + // We only have a single file, return it no matter what relative string is used + return GooglePlaySdkIndex::class.java.getResourceAsStream("/$GOOGLE_PLAY_SDK_INDEX_SNAPSHOT_RESOURCE") } /** @@ -325,12 +366,31 @@ abstract class GooglePlaySdkIndex(cacheDir: Path? = null) : NetworkCache( protected open fun logOutdated(groupId: String, artifactId: String, versionString: String, file: File?) { } - protected open fun logCachingError(message: String?) { + protected open fun logCachingError(readResult: ReadDataResult, dataSourceType: DataSourceType) { + } + + protected open fun logErrorInDefaultData(readResult: ReadDataResult) { } - protected open fun logErrorInDefaultData(message: String?) { + protected open fun logIndexLoadedCorrectly(dataSourceType: DataSourceType) { } - protected open fun logIndexLoadedCorrectly() { + protected enum class ReadDataErrorType { + NO_ERROR, + // Function used to get the data caused an exception + DATA_FUNCTION_EXCEPTION, + // Function used to get the data returned null + DATA_FUNCTION_NULL_ERROR, + // There was an exception while decompressing the raw data + GZIP_EXCEPTION, + // Exception while parsing decompressed data + INDEX_PARSE_EXCEPTION, + // Resulted Index was null after parsing + INDEX_PARSE_NULL_ERROR,; } + + protected class ReadDataResult(val index: Index?, val readDataErrorType: ReadDataErrorType, val exception: Exception?) + + @VisibleForTesting + fun getLastReadSource() = lastReadSourceType } diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GradleDetector.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GradleDetector.kt index 40afd231ce..992e9d6b32 100644 --- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GradleDetector.kt +++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/GradleDetector.kt @@ -1061,7 +1061,13 @@ open class GradleDetector : Detector(), GradleScanner { if (newerVersion != null && version > GradleVersion(0, 0, 0) && newerVersion > version) { val versionString = newerVersion.toString() - val message = getNewerVersionAvailableMessage(dependency, versionString, null) + val message = if (dependency.groupId == "androidx.slidingpanelayout" && dependency.artifactId == "slidingpanelayout") { + "Upgrade `androidx.slidingpanelayout` for keyboard and mouse support" + } else if (dependency.groupId == "androidx.compose.foundation" && dependency.artifactId == "foundation") { + "Upgrade `androidx.compose.foundation` for keyboard and mouse support" + } else { + getNewerVersionAvailableMessage(dependency, versionString, null) + } val fix = if (!isResolved) getUpdateDependencyFix(revision, versionString) else null report(context, cookie, issue, message, fix) } diff --git a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/PluralsDetector.kt b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/PluralsDetector.kt index 402aebe6f1..0accd2f927 100644 --- a/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/PluralsDetector.kt +++ b/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/PluralsDetector.kt @@ -24,6 +24,7 @@ import com.android.tools.lint.checks.PluralsDatabase.Quantity import com.android.tools.lint.checks.TranslationDetector.Companion.getLanguageDescription import com.android.tools.lint.detector.api.Category import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Incident import com.android.tools.lint.detector.api.Issue.Companion.create import com.android.tools.lint.detector.api.ResourceXmlDetector import com.android.tools.lint.detector.api.Scope @@ -121,21 +122,24 @@ class PluralsDetector : ResourceXmlDetector() { if (!missing.isEmpty()) { val examplesLookup = PluralExamplesLookup.getInstance() val withExamples = missing.map { form -> - val example = examplesLookup.findExample(language, form.name) - form to example?.formattedWithNumber() - }.map { (form, example) -> + val example = examplesLookup.findExample(language, form.name)?.formattedWithNumber() if (example != null) { "`${form.name}` (e.g. \"$example\")" } else { "`${form.name}`" } } + val languageDescription = getLanguageDescription(language) val message = if (withExamples.size == 1) { - "For locale ${getLanguageDescription(language)} the following quantity should also be defined: ${withExamples.single()}" + "For locale $languageDescription the following quantity should also be defined: ${withExamples.single()}" } else { - "For locale ${getLanguageDescription(language)} the following quantities should also be defined: ${withExamples.joinToString(", ")}" + "For locale $languageDescription the following quantities should also be defined: ${withExamples.joinToString(", ")}" } - context.report(MISSING, element, context.getLocation(element), message) + val incident = Incident(MISSING, element, context.getLocation(element), message) + if (NEW_PLURAL_FORMS.containsKey(language) && missing.singleOrNull() == NEW_PLURAL_FORMS[language]) { + incident.overrideSeverity(Severity.WARNING) + } + context.report(incident) } // Look for irrelevant @@ -157,6 +161,15 @@ class PluralsDetector : ResourceXmlDetector() { ) /** + * For these languages and plural forms, issue a warning as opposed to an error, since they have been recently + * added in the database. Will be removed once [PluralsDatabase] has a diff table for handling successive versions + * of the ICU database (i.e. version 40 and above). + */ + private val NEW_PLURAL_FORMS = mapOf( + "fr" to Quantity.many + ) + + /** * This locale should define a quantity string for the given * quantity */ diff --git a/lint/libs/lint-checks/src/main/resources/sdk-index-offline-snapshot.proto.gz b/lint/libs/lint-checks/src/main/resources/sdk-index-offline-snapshot.proto.gz Binary files differindex 9c3268f0f6..5844c15531 100644 --- a/lint/libs/lint-checks/src/main/resources/sdk-index-offline-snapshot.proto.gz +++ b/lint/libs/lint-checks/src/main/resources/sdk-index-offline-snapshot.proto.gz diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/LintFixPerformerTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/LintFixPerformerTest.kt index f21c954e12..b17d9dfb29 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/LintFixPerformerTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/LintFixPerformerTest.kt @@ -42,7 +42,8 @@ class LintFixPerformerTest : TestCase() { vararg fixes: LintFix, expected: String, expectedOutput: String? = null, - expectedFailure: String? = null + expectedFailure: String? = null, + includeMarkers: Boolean = false ) { val client = TestLintClient() for (fix in fixes) { @@ -51,7 +52,7 @@ class LintFixPerformerTest : TestCase() { var after: String = source var output = "" val printStatistics = expectedOutput != null - val performer = object : LintFixPerformer(client, printStatistics) { + val performer = object : LintFixPerformer(client, printStatistics, includeMarkers = includeMarkers) { override fun writeFile(pendingFile: PendingEditFile, contents: String) { after = contents } @@ -408,4 +409,47 @@ class LintFixPerformerTest : TestCase() { sorted.toString() ) } + + fun testShortenNames() { + // Regression test for b/https://issuetracker.google.com/241573146 + val file = File("Test.java") + @Language("java") + val source = + """ + package test.pkg; + import android.graphics.drawable.Drawable; + import android.graphics.Outline; + + class Test { + static void getOutline() { + } + } + """.trimIndent() + + val range = Location.create(file, source, 0, source.length) + val fix = + fix().replace() + .text("()") + .with("(android.graphics.drawable.Drawable drawable, android.graphics.Outline outline)") + .shortenNames() + .autoFix() + .range(range) + .build() + check( + file, source, fix, + expected = + """ + package test.pkg; + import android.graphics.drawable.Drawable; + import android.graphics.Outline; + + class Test { + static void getOutline(Drawable drawable, Outline outline) { + } + } + """, + expectedOutput = "Applied 1 edits across 1 files for this fix: Replace with (android.graphics.drawable.Drawable drawable, android.graphics.Outline outline)", + includeMarkers = true + ) + } } diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/CheckResultDetectorTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/CheckResultDetectorTest.kt index 8dc665c58f..314c3be162 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/CheckResultDetectorTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/CheckResultDetectorTest.kt @@ -1656,7 +1656,7 @@ class CheckResultDetectorTest : AbstractCheckTest() { public Object getLock() { return Api.class; } public void test() { synchronized (getLock()) { - println("Test"); + System.out.println("Test"); } } } @@ -1675,6 +1675,47 @@ class CheckResultDetectorTest : AbstractCheckTest() { ).run().expectClean() } + fun testSynchronizedUnused() { + // 242305422: CheckResultDetector allows unused results in Java synchronized expressions. + lint().files( + java( + """ + import androidx.annotation.CheckResult; + public class Api { + @CheckResult + public Object getLock() { return Api.class; } + public void test() { + synchronized (getLock()) { + getLock(); // ERROR + System.out.println("test"); + } + } + } + """ + ).indented(), + kotlin( + """ + class Api2 : Api() { + fun test2() { + synchronized(getLock()) { getLock(); println("test") } // ERROR + } + } + """ + ).indented(), + SUPPORT_ANNOTATIONS_JAR + ).run().expect( + """ + src/Api.java:7: Warning: The result of getLock is not used [CheckResult] + getLock(); // ERROR + ~~~~~~~~~ + src/Api2.kt:3: Warning: The result of getLock is not used [CheckResult] + synchronized(getLock()) { getLock(); println("test") } // ERROR + ~~~~~~~~~ + 0 errors, 2 warnings + """ + ) + } + fun testKotlinTest() { lint().files( kotlin( diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/DeprecationDetectorTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/DeprecationDetectorTest.kt index 3bd0495236..03a64dc7af 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/DeprecationDetectorTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/DeprecationDetectorTest.kt @@ -460,4 +460,42 @@ class DeprecationDetectorTest : AbstractCheckTest() { """ ) } + + fun testSharedUserId() { + // Regression test for issue 233388117 + lint().files( + manifest( + """ + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="test.pkg" + android:sharedUserId="0" + android:sharedUserMaxSdkVersion="32"> + </manifest> + """ + ).indented(), + manifest( + """ + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="test.pkg" + android:sharedUserId="0"> + </manifest> + """ + ).to("../app/AndroidManifest.xml") + ).run().expect( + """ + AndroidManifest.xml:4: Warning: Consider removing sharedUserId for new users by adding android:sharedUserMaxSdkVersion="32" to your manifest. See https://developer.android.com/guide/topics/manifest/manifest-element for details. [Deprecated] + android:sharedUserId="0"> + ~~~~~~~~~~~~~~~~~~~~~~~~ + 0 errors, 1 warnings + """ + ).expectFixDiffs( + """ + Fix for AndroidManifest.xml line 4: Set sharedUserMaxSdkVersion="32": + @@ -4 +4 + - android:sharedUserId="0" > + + android:sharedUserId="0" + + android:sharedUserMaxSdkVersion="32" > + """ + ) + } } diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt index 950fd8af68..561f888c40 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GooglePlaySdkIndexTest.kt @@ -15,6 +15,7 @@ */ package com.android.tools.lint.checks +import com.android.ide.common.repository.NetworkCache import com.android.tools.lint.detector.api.LintFix import com.google.common.truth.Truth.assertThat import org.junit.Assert.fail @@ -150,6 +151,7 @@ class GooglePlaySdkIndexTest { } } index.initialize(ByteArrayInputStream(proto.toByteArray())) + assertThat(index.getLastReadSource()).isEqualTo(NetworkCache.DataSourceType.TEST_DATA) } @Test @@ -235,6 +237,21 @@ class GooglePlaySdkIndexTest { } } + @Test + fun `offline snapshot can be used correctly`() { + val offlineIndex = object : GooglePlaySdkIndex() { + override fun readUrlData(url: String, timeout: Int): ByteArray? { + return null + } + + override fun error(throwable: Throwable, message: String?) { + } + } + offlineIndex.initialize() + assertThat(offlineIndex.isReady()).isTrue() + assertThat(offlineIndex.getLastReadSource()).isEqualTo(NetworkCache.DataSourceType.DEFAULT_DATA) + } + private fun hasOutdatedIssues(): Boolean { for (sdk in proto.sdksList) { for (library in sdk.librariesList) { diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GradleDetectorTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GradleDetectorTest.kt index 57a147320c..844ed42e15 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GradleDetectorTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/GradleDetectorTest.kt @@ -507,7 +507,6 @@ class GradleDetectorTest : AbstractCheckTest() { """ ) } - fun testSnapshots() { // Regression test for b/183137869: // Gradle special-cases the SNAPSHOT version; make sure we don't offer updates to/from it except @@ -1083,6 +1082,51 @@ class GradleDetectorTest : AbstractCheckTest() { ).issues(DEPENDENCY).run().expect(expected) } + fun testLargeScreenIncorrectDependencies() { + val expected = "build.gradle:9: Warning: Upgrade androidx.slidingpanelayout for keyboard and mouse support [GradleDependency]\n" + + " compile 'androidx.slidingpanelayout:slidingpanelayout:1.1.0'\n" + + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + "build.gradle:10: Warning: Upgrade androidx.compose.foundation for keyboard and mouse support [GradleDependency]\n" + + " compile 'androidx.compose.foundation:foundation:1.1.1'\n" + + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + + "0 errors, 2 warnings" + lint().files( + gradle( + "" + + "apply plugin: 'com.android.application'\n" + + "\n" + + "android {\n" + + " compileSdkVersion 21\n" + + " buildToolsVersion \"21.1.2\"\n" + + "}\n" + + "\n" + + "dependencies {\n" + + " compile 'androidx.slidingpanelayout:slidingpanelayout:1.1.0'\n" + + " compile 'androidx.compose.foundation:foundation:1.1.1'\n" + + "}\n" + ) + ).issues(DEPENDENCY).run().expect(expected) + } + + fun testLargeScreenCorrectDependencies() { + lint().files( + gradle( + "" + + "apply plugin: 'com.android.application'\n" + + "\n" + + "android {\n" + + " compileSdkVersion 21\n" + + " buildToolsVersion \"21.1.2\"\n" + + "}\n" + + "\n" + + "dependencies {\n" + + " compile 'androidx.slidingpanelayout:slidingpanelayout:1.2'\n" + + " compile 'androidx.compose.foundation:foundation:1.2.1'\n" + + "}\n" + ) + ).issues(DEPENDENCY).run().expectClean() + } + fun testDependenciesMinSdkVersion() { lint().files( gradle( @@ -4443,7 +4487,9 @@ class GradleDetectorTest : AbstractCheckTest() { // SDK distributed via Maven "caches/modules-2/files-2.1/com.android.support/recyclerview-v7/26.0.0/sample", - "caches/modules-2/files-2.1/com.google.firebase/firebase-messaging/11.0.0/sample" + "caches/modules-2/files-2.1/com.google.firebase/firebase-messaging/11.0.0/sample", + "caches/modules-2/files-2.1/androidx.slidingpanelayout/slidingpanelayout/1.2.0/sample", + "caches/modules-2/files-2.1/androidx.compose.foundation/foundation/1.2.1/sample" ) ) } @@ -4464,6 +4510,8 @@ class GradleDetectorTest : AbstractCheckTest() { <com.google.android.gms/> <com.google.android.support/> <androidx.core/> + <androidx.slidingpanelayout/> + <androidx.compose/> </metadata> """.trimIndent() ) @@ -4540,6 +4588,24 @@ class GradleDetectorTest : AbstractCheckTest() { </androidx.core> """.trimIndent() ) + task.networkData( + "https://maven.google.com/androidx/slidingpanelayout/group-index.xml", + """ + <?xml version="1.0" encoding="UTF-8"?> + <androidx.slidingpanelayout> + <slidingpanelayout versions="1.1.0", "1.2.0"/> + </androidx.slidingpanelayout> + """.trimIndent() + ) + task.networkData( + "https://maven.google.com/androidx/compose/foundation/group-index.xml", + """ + <?xml version="1.0" encoding="UTF-8"?> + <androidx.compose.foundation> + <foundation versions="1.1.0", "1.2.0"/> + </androidx.compose.foundation> + """.trimIndent() + ) // Similarly set up the expected SDK Index network output from dl.google.com to // ensure stable SDK library suggestions in the tests diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/PluralsDetectorTest.java b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/PluralsDetectorTest.java index 043815a9f1..e6eec9a303 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/PluralsDetectorTest.java +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/PluralsDetectorTest.java @@ -42,10 +42,10 @@ public class PluralsDetectorTest extends AbstractCheckTest { public void test2() { String expected = "" - + "res/values-fr/plurals.xml:3: Error: For locale \"fr\" (French) the following quantity should also be defined: many (e.g. \"1000000 de jours\") [MissingQuantity]\n" + + "res/values-cs/plurals3.xml:3: Error: For locale \"cs\" (Czech) the following quantities should also be defined: few (e.g. \"2 dny\"), many (e.g. \"10.0 dne\") [MissingQuantity]\n" + " <plurals name=\"draft\">\n" + " ^\n" - + "res/values-cs/plurals3.xml:3: Error: For locale \"cs\" (Czech) the following quantities should also be defined: few (e.g. \"2 dny\"), many (e.g. \"10.0 dne\") [MissingQuantity]\n" + + "res/values-fr/plurals.xml:3: Warning: For locale \"fr\" (French) the following quantity should also be defined: many (e.g. \"1000000 de jours\") [MissingQuantity]\n" + " <plurals name=\"draft\">\n" + " ^\n" + "res/values-zh-rCN/plurals3.xml:3: Warning: For language \"zh\" (Chinese) the following quantities are not relevant: one [UnusedQuantity]\n" @@ -54,7 +54,7 @@ public class PluralsDetectorTest extends AbstractCheckTest { + "res/values-zh-rCN/plurals3.xml:7: Warning: For language \"zh\" (Chinese) the following quantities are not relevant: one [UnusedQuantity]\n" + " <plurals name=\"title_day_dialog_content\">\n" + " ^\n" - + "2 errors, 2 warnings\n"; + + "1 errors, 3 warnings"; lint().files( xml( "res/values-zh-rCN/plurals3.xml", @@ -176,6 +176,47 @@ public class PluralsDetectorTest extends AbstractCheckTest { .expectClean(); } + public void testFrenchMany() { + lint().files( + xml( + "res/values-fr/plurals.xml", + "" + + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + "<resources>\n" + + " <plurals name=\"draft\">\n" + + " <item quantity=\"one\">\"brouillon\"</item>\n" + + " <item quantity=\"other\">\"brouillons\"</item>\n" + + " </plurals>\n" + + "</resources>\n")) + .issues(PluralsDetector.MISSING) + .run() + .expect( + "res/values-fr/plurals.xml:3: Warning: For locale \"fr\" (French) the following quantity should also be defined: many (e.g. \"1000000 de jours\") [MissingQuantity]\n" + + " <plurals name=\"draft\">\n" + + " ^\n" + + "0 errors, 1 warnings"); + } + + public void testFrenchOtherAndMany() { + lint().files( + xml( + "res/values-fr/plurals.xml", + "" + + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + "<resources>\n" + + " <plurals name=\"draft\">\n" + + " <item quantity=\"one\">\"brouillon\"</item>\n" + + " </plurals>\n" + + "</resources>\n")) + .issues(PluralsDetector.MISSING) + .run() + .expect( + "res/values-fr/plurals.xml:3: Warning: For locale \"fr\" (French) the following quantity should also be defined: many (e.g. \"1000000 de jours\") [MissingQuantity]\n" + + " <plurals name=\"draft\">\n" + + " ^\n" + + "0 errors, 1 warnings"); + } + public void testImpliedQuantity() { String expected = "" diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/SdCardDetectorTest.java b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/SdCardDetectorTest.java index 300c7d6352..4835a81c18 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/SdCardDetectorTest.java +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/SdCardDetectorTest.java @@ -16,7 +16,9 @@ package com.android.tools.lint.checks; +import com.android.tools.lint.checks.infrastructure.TestMode; import com.android.tools.lint.detector.api.Detector; +import com.intellij.openapi.util.io.FileUtilRt; import org.intellij.lang.annotations.Language; @SuppressWarnings({"javadoc", "ClassNameDiffersFromFileName"}) @@ -545,8 +547,10 @@ public class SdCardDetectorTest extends AbstractCheckTest { // We've recently removed the large file limit (look for PersistentFSConstants) public void testLargeFiles() { - int max = 2600 * 1024; - StringBuilder large = new StringBuilder(max + 100); // default is 2500 + // default user file size limit = 2500 KiB + // default user content load limit = 20000 KiB + int max = Math.max(FileUtilRt.getUserFileSizeLimit(), FileUtilRt.getUserContentLoadLimit()); + StringBuilder large = new StringBuilder(max + 100); large.append("package test.pkg;\nclass VeryLarge {\n"); for (int i = 0; i < max; i++) { large.append(' '); @@ -559,24 +563,23 @@ public class SdCardDetectorTest extends AbstractCheckTest { lint().files(java("src/test/pkg/VeryLarge.java", javaSource)) .allowSystemErrors(true) .allowCompilationErrors() + .testModes(TestMode.DEFAULT) .run() - /* We've recently removed the large file limit (look for PersistentFSConstants - references) - .expect("src/test/pkg/VeryLarge.java: Error: Source file too large for lint to " + - "process (2600KB); the current max size is 2560000KB. You can increase " + - "the limit by setting this system property: " + - "idea.max.intellisense.filesize=4096 (or even higher) [LintError]\n" + - "1 errors, 0 warnings\n"); - */ - .expectClean(); + .expect( + "src/test/pkg/VeryLarge.java: Error: Source file too large for lint to " + + "process (20480KB); the current max size is 20480KB. You can increase " + + "the limit by setting this system property: " + + "idea.max.intellisense.filesize=32768 (or even higher) [LintError]\n" + + "1 errors, 0 warnings\n"); // Bump up the file limit and make sure it no longer complains! - String prev = System.getProperty("idea.max.intellisense.filesize"); + String prev = System.getProperty(IDEA_MAX_INTELLISENSE_FILESIZE); try { - System.setProperty(IDEA_MAX_INTELLISENSE_FILESIZE, "4096"); + System.setProperty(IDEA_MAX_INTELLISENSE_FILESIZE, Integer.toString(max + 1024)); lint().files(java("src/test/pkg/VeryLarge.java", javaSource)) .allowSystemErrors(true) .allowCompilationErrors() + .testModes(TestMode.DEFAULT) .run() .expectClean(); } finally { diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/infrastructure/SuppressLintTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/infrastructure/SuppressLintTest.kt index 79ef3d4724..f094418f73 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/infrastructure/SuppressLintTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/infrastructure/SuppressLintTest.kt @@ -30,10 +30,14 @@ import com.android.tools.lint.detector.api.Issue import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.android.tools.lint.detector.api.XmlContext +import com.android.tools.lint.detector.api.XmlScanner import com.intellij.psi.PsiMethod import org.jetbrains.uast.UCallExpression import org.jetbrains.uast.UImportStatement import org.junit.Test +import org.w3c.dom.Attr /** * Checks that some lint checks cannot be suppressed with the normal @@ -95,6 +99,7 @@ class SuppressLintTest { import forbidden; @MyOwnAnnotation class Test { + @SuppressWarnings("InfiniteRecursion") public void forbidden() { forbidden(); } @@ -191,6 +196,80 @@ class SuppressLintTest { } @Test + fun checkForbiddenSuppressWithXmlIgnore() { + lint() + .allowCompilationErrors() + .files( + xml( + "res/layout/main.xml", + """ + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" + xmlns:android="http://schemas.android.com/apk/res/android"> + + <androidx.compose.ui.platform.ComposeView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:forbidden="true" + tools:ignore="_SecureIssue"/> + </LinearLayout> + """ + ).indented() + ) + .issues(MySecurityDetector.TEST_ISSUE) + .sdkHome(TestUtils.getSdk().toFile()) + .run() + .expect( + """ + res/layout/main.xml:7: Error: Issue _SecureIssue is not allowed to be suppressed [LintError] + <androidx.compose.ui.platform.ComposeView + ^ + res/layout/main.xml:10: Warning: Some error message here [_SecureIssue] + android:forbidden="true" + ~~~~~~~~~~~~~~~~~~~~~~~~ + 1 errors, 1 warnings + """ + ) + } + + @Test + fun checkForbiddenSuppressWithXmlComment() { + lint() + .allowCompilationErrors() + .files( + xml( + "res/layout/main.xml", + """ + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:android="http://schemas.android.com/apk/res/android"> + + <!--suppress _SecureIssue --> + <androidx.compose.ui.platform.ComposeView android:forbidden="true"/> + </LinearLayout> + """ + ).indented() + ) + .issues(MySecurityDetector.TEST_ISSUE) + .sdkHome(TestUtils.getSdk().toFile()) + .run() + .expect( + """ + res/layout/main.xml:7: Error: Issue _SecureIssue is not allowed to be suppressed [LintError] + <androidx.compose.ui.platform.ComposeView android:forbidden="true"/> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + res/layout/main.xml:7: Warning: Some error message here [_SecureIssue] + <androidx.compose.ui.platform.ComposeView android:forbidden="true"/> + ~~~~~~~~~~~~~~~~~~~~~~~~ + 1 errors, 1 warnings + """ + ) + } + + @Test fun checkForbiddenSuppressWithLintXml() { lint() .allowCompilationErrors() @@ -451,7 +530,7 @@ class SuppressLintTest { // Sample detector which just flags calls to a method called "forbidden" @SuppressWarnings("ALL") - class MySecurityDetector : Detector(), Detector.UastScanner { + class MySecurityDetector : Detector(), SourceCodeScanner, XmlScanner { override fun getApplicableUastTypes() = listOf(UImportStatement::class.java) override fun getApplicableMethodNames(): List<String> { @@ -483,6 +562,15 @@ class SuppressLintTest { } } + override fun getApplicableAttributes(): Collection<String> = listOf("forbidden") + + override fun visitAttribute(context: XmlContext, attribute: Attr) { + val message = "Some error message here" + val location = context.getLocation(attribute) + context.report(TEST_ISSUE, attribute, location, message) + context.report(TEST_ISSUE_NEVER_SUPPRESSIBLE, attribute, location, message) + } + companion object { @Suppress("SpellCheckingInspection") @JvmField @@ -494,7 +582,7 @@ class SuppressLintTest { suppressAnnotations = listOf("foo.bar.MyOwnAnnotation"), implementation = Implementation( MySecurityDetector::class.java, - Scope.JAVA_FILE_SCOPE + Scope.JAVA_AND_RESOURCE_FILES ) ) @@ -510,7 +598,7 @@ class SuppressLintTest { suppressAnnotations = emptyList(), implementation = Implementation( MySecurityDetector::class.java, - Scope.JAVA_FILE_SCOPE + Scope.JAVA_AND_RESOURCE_FILES ) ) } diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/JarFileIssueRegistryTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/JarFileIssueRegistryTest.kt index a965ce2d17..da2cff9467 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/JarFileIssueRegistryTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/JarFileIssueRegistryTest.kt @@ -441,32 +441,7 @@ class JarFileIssueRegistryTest : AbstractCheckTest() { .allowObsoleteLintChecks(false) .issueIds("MyIssueId") .run() - .expectContains( - """ - lint.jar: Warning: Lint found an issue registry (test.pkg.MyIssueRegistry) - which contains code in some of lint's reserved packages. - - This is usually because the lint jar has accidentally - packed in libraries that are part of lint's API surface, - such as the Kotlin standard library (kotlin.*), or - some of the Android tooling libraries (com.android.*) - including lint's own API jars, or some of the third party - libraries that lint depends on, such as UAST. - If you need these and cannot rely on the ones provided - in lint's runtime environment, consider `jarjar`ing your - own versions. - - A second reason is one where you've accidentally placed - your own detector code into one of these package - namespaces, since they are pretty broad (com.android.*). - For Android specifically, you can place them under - com.android.internal.* which is explicitly allowed. - - The first bundled package that is part of lint's API - surface namespace is: - com.android.something [ObsoleteLintCustomCheck] - 0 errors, 1 warnings""" - ) + .expectClean() } fun testNewerLintBroken() { diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/LintJarVerifierTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/LintJarVerifierTest.kt index 15dbfdd67e..bea7987aa1 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/LintJarVerifierTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/client/api/LintJarVerifierTest.kt @@ -138,48 +138,6 @@ class LintJarVerifierTest { } @Test - fun testPackagedDeps() { - val projects = lint().files( - compiled( - "lint.jar", - kotlin( - """ - package com.android.lint.mycheck - - // Not implementing real lint APIs here, just - // including data in a suspicious package - class MyDetector - """ - ).indented(), - 0x6db3a5a1, - """ - META-INF/main.kotlin_module: - H4sIAAAAAAAAAGNgYGBmYGBgBGJWKM2gxKDFAABNj30wGAAAAA== - """, - """ - com/android/lint/mycheck/MyDetector.class: - H4sIAAAAAAAAAI1Ru0oDQRQ9d2I2ukYT3/GBjQhq4arYKYIPhEBUUEmTarI7 - mEmyM7A7Ee3yLf6BlWAhwdKPEu/GgK1THM5juI+Zr+/3DwCHWCNshDYOpIkS - q6Ogq40L4uewpcJOcPV8oZwKnU0KIEK5LR9l0JXmIbhpttkvIEfwjrXR7oSQ - 29quF5GH52MMBcKYa+mUsFn7R/0jwkytYx3HwZVyMpJOsifixxyPSRnkCdRh - 60lnao9ZtE9YH/R9X1SEL8rMBv3KoH8g9ugs//niibLIbh0QV8DUX7PdjuPp - zm2kCKWaNuq6FzdVci+bXXZmazaU3bpMdKZHpn9ne0moLnUmlm97xulY1XWq - OT01xjrptDUp9iF4+ezwtNlbMC6xCoaal9h5w/grE4EKo/drYpmxOOIT8If5 - yhAXsTr8J8IkZ8UGclVMVTHNiFIG5SpmMNsApZjDPOcp/BQLKbwfJ1hjDeQB - AAA= - """ - ) - ).createProjects(temporaryFolder.newFolder()) - - assertEquals(1, projects.size) - val jar = File(projects[0], "lint.jar") - assertTrue(jar.isFile) - val verifier = LintJarVerifier(jar) - assertTrue(verifier.hasPackageConflict()) - assertEquals("com.android.lint.mycheck", verifier.describeFirstPackagedDependency()) - } - - @Test fun checkMavenJars() { // This test downloads ALL the AAR files on maven.google.com and verifies // any lint.jar files found within! diff --git a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/detector/api/VersionChecksTest.kt b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/detector/api/VersionChecksTest.kt index 40ee02922d..a2a1fe0625 100644 --- a/lint/libs/lint-tests/src/test/java/com/android/tools/lint/detector/api/VersionChecksTest.kt +++ b/lint/libs/lint-tests/src/test/java/com/android/tools/lint/detector/api/VersionChecksTest.kt @@ -2321,10 +2321,10 @@ class VersionChecksTest : AbstractCheckTest() { import android.os.Build.VERSION_CODES.N import android.text.Html - fun String.fromHtm() : String + fun String.fromHtml() : String { return when { - false, SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) else -> Html.fromHtml(this) }.toString() }""" @@ -2332,6 +2332,48 @@ class VersionChecksTest : AbstractCheckTest() { ).run().expectClean() } + fun testKotlinWhenStatement_logicalOperatorsWithConstants() { + // Regression test for + // 242479753: false positives when logical operators and constants are combined + lint().files( + manifest().minSdk(4), + kotlin( + """ + import android.os.Build.VERSION.SDK_INT + import android.os.Build.VERSION_CODES.N + import android.text.Html + + fun String.fromHtml() : String + { + return when { + false || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + true || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + false && SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + true && SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + else -> Html.fromHtml(this) + }.toString() + }""" + ).indented() + ).run().expect( + """ + src/test.kt:8: Warning: Field requires API level 24 (current min is 4): android.text.Html#FROM_HTML_MODE_LEGACY [InlinedApi] + false || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + src/test.kt:9: Warning: Field requires API level 24 (current min is 4): android.text.Html#FROM_HTML_MODE_LEGACY [InlinedApi] + true || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + src/test.kt:8: Error: Call requires API level 24 (current min is 4): android.text.Html#fromHtml [NewApi] + false || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + ~~~~~~~~ + src/test.kt:9: Error: Call requires API level 24 (current min is 4): android.text.Html#fromHtml [NewApi] + true || SDK_INT >= N -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY) + ~~~~~~~~ + 2 errors, 2 warnings + """ + ) + //.expectClean() // Should be same as [testKotlinWhenStatement] + } + fun testKotlinWhenStatement2() { // Regression test for issue 69661204 lint().files( diff --git a/sdk-common/src/main/java/com/android/ide/common/attribution/TaskCategoryLabel.kt b/sdk-common/src/main/java/com/android/ide/common/attribution/TaskCategoryLabel.kt index 93e478e5e6..451b812316 100644 --- a/sdk-common/src/main/java/com/android/ide/common/attribution/TaskCategoryLabel.kt +++ b/sdk-common/src/main/java/com/android/ide/common/attribution/TaskCategoryLabel.kt @@ -38,6 +38,7 @@ enum class TaskCategoryLabel { JAVA_RESOURCES, // Tasks that involve Java docs JAVA_DOC, + KOTLIN, // Tasks that invovle AIDL AIDL, // Tasks involving Renderscript framework @@ -62,8 +63,11 @@ enum class TaskCategoryLabel { DEPLOYMENT, // Tasks that helps/gives information to the user HELP, + // Task related to packaging APKs APK_PACKAGING, + // Tasks related to packaging AARs AAR_PACKAGING, + // Tasks related to packaging bundles BUNDLE_PACKAGING, // Tasks that involve the optimization of the project OPTIMIZATION, @@ -71,4 +75,16 @@ enum class TaskCategoryLabel { SOURCE_GENERATION, // Tasks that process sources SOURCE_PROCESSING, + // Tasks related to packaging artifacts + ZIPPING, + LINKING, + MERGING, + FUSING, + // org.gradle tasks - No tasks in AGP should have this annotation label + GRADLE, + // Various tasks that do not fall into any other category + // No tasks in AGP should have this annotation label + MISC, + // Other TP plugins - No task in AGP should have this annotation label + UNKNOWN } diff --git a/sdk-common/src/main/java/com/android/ide/common/repository/GradleVersion.java b/sdk-common/src/main/java/com/android/ide/common/repository/GradleVersion.java index d0750fa8d8..be7db5039a 100644 --- a/sdk-common/src/main/java/com/android/ide/common/repository/GradleVersion.java +++ b/sdk-common/src/main/java/com/android/ide/common/repository/GradleVersion.java @@ -29,18 +29,26 @@ import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jetbrains.annotations.NotNull; /** - * Supports versions in the given formats: <ul> <li>major (e.g. 1)</li> <li>major.minor (e.g. - * 1.0)</li> <li>major.minor.micro (e.g. 1.1.1)</li> </ul> A version can also be a "preview" (e.g. - * 1-alpha1, 1.0.0-rc2) or an unreleased version (or "snapshot") (e.g. 1-SNAPSHOT, - * 1.0.0-alpha1-SNAPSHOT). + * Supports versions in the given formats: + * + * <ul> + * <li>major (e.g. 1) + * <li>major.minor (e.g. 1.0) + * <li>major.minor.micro (e.g. 1.1.1) + * </ul> + * + * A version can also be a "previewType" (e.g. 1-alpha1, 1.0.0-rc2) or an unreleased version (or + * "snapshot") (e.g. 1-SNAPSHOT, 1.0.0-alpha1-SNAPSHOT). */ public class GradleVersion implements Comparable<GradleVersion>, Serializable { private static final String PLUS = "+"; - private static final Pattern PREVIEW_PATTERN = Pattern.compile("([a-zA-z]+)[\\-]?([\\d]+)?(-\\d+)?"); - + // TODO(b/242691473): This pattern is not inclusive for all the possible versions. + private static final Pattern PREVIEW_AND_SNAPSHOT_PATTERN = + Pattern.compile("([a-zA-z]+)[\\-]?([\\d]+)?[\\-]?(\\d+)?[\\-]?([a-zA-z]+)?"); private final String mRawValue; @NonNull @@ -59,10 +67,41 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { private final boolean mSnapshot; - @NonNull - private final List<VersionSegment> mAdditionalSegments; + @NonNull private final List<VersionSegment> mAdditionalSegments; + + private final VersionQualifiers mQualifiers; - private final String mQualifiers; + private static class VersionQualifiers { + @NotNull String previewType; + + int preview; + + // TODO(b/242691473): We could have multiple additional previewType types and should + // consider all of them eventually. + int additionalPreviewType; + + @Nullable String previewChannel; + + private VersionQualifiers( + @NotNull String previewType, + int preview, + int additionalPreviewType, + @Nullable String previewChannel) { + this.previewType = previewType; + this.preview = preview; + this.additionalPreviewType = additionalPreviewType; + this.previewChannel = previewChannel; + } + + @NonNull + @Override + public String toString() { + return previewType + + ((preview != 0) ? "-" + preview : "") + + ((additionalPreviewType != 0) ? "-" + additionalPreviewType : "") + + ((!isNullOrEmpty(previewChannel)) ? "-" + previewChannel : ""); + } + } /** * Parses the given version. This method does the same as {@link #parse(String)}, but it does @@ -93,12 +132,45 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { @NonNull public static GradleVersion parse(@NonNull String value) { String version = value; - String qualifiers = null; + VersionQualifiers qualifiers = null; char dash = '-'; int dashIndex = value.indexOf(dash); if (dashIndex != -1) { if (dashIndex < value.length() - 1) { - qualifiers = value.substring(dashIndex + 1); + String qualifiersText = value.substring(dashIndex + 1); + String qualifierName = null; + int qualifierValue = 0; + int additionalQualifierValue = 0; + String qualifierChannel = null; + Matcher matcher = PREVIEW_AND_SNAPSHOT_PATTERN.matcher(qualifiersText); + if (matcher.matches()) { + qualifierName = matcher.group(1); + if (matcher.groupCount() >= 2) { + String group = matcher.group(2); + if (!isNullOrEmpty(group)) { + qualifierValue = Integer.parseInt(group); + } + String group3 = matcher.group(3); + if (!isNullOrEmpty(group3)) { + additionalQualifierValue = Integer.parseInt(group3); + } + String group4 = matcher.group(4); + if (!isNullOrEmpty(group4)) { + qualifierChannel = group4; + } + } + } + if (!isNullOrEmpty(qualifierName) + || qualifierValue != 0 + || additionalQualifierValue != 0 + || !isNullOrEmpty(qualifierChannel)) { + qualifiers = + new VersionQualifiers( + qualifierName, + qualifierValue, + additionalQualifierValue, + qualifierChannel); + } } version = value.substring(0, dashIndex); } @@ -124,39 +196,25 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { additionalSegments.addAll(parsedVersionSegments.subList(3, segmentCount)); } - int preview = 0; - String previewType = null; boolean snapshot = false; if (qualifiers != null) { - if (isSnapshotQualifier(qualifiers)) { + if (isSnapshotQualifier(qualifiers.toString())) { snapshot = true; qualifiers = null; - } - else { - // find and remove "SNAPSHOT" at the end of the qualifiers. - int lastDashIndex = qualifiers.lastIndexOf(dash); - if (lastDashIndex != -1) { - String mayBeSnapshot = qualifiers.substring(lastDashIndex + 1); - if (isSnapshotQualifier(mayBeSnapshot)) { - snapshot = true; - qualifiers = qualifiers.substring(0, lastDashIndex); - } - } - } - if (!isNullOrEmpty(qualifiers)) { - Matcher matcher = PREVIEW_PATTERN.matcher(qualifiers); - if (matcher.matches()) { - previewType = matcher.group(1); - if (matcher.groupCount() >= 2) { - String group = matcher.group(2); - if (!isNullOrEmpty(group)) { - preview = Integer.parseInt(group); - } - } - } + } else if (!isNullOrEmpty(qualifiers.previewChannel) + && isSnapshotQualifier(qualifiers.previewChannel)) { + snapshot = true; + qualifiers.previewChannel = null; } } + + int preview = (qualifiers != null) ? qualifiers.preview : 0; + String previewType = + (qualifiers != null) + ? qualifiers.previewType + : null; // PreviewType is never null + return new GradleVersion(value, majorSegment, minorSegment, microSegment, additionalSegments, preview, previewType, snapshot, qualifiers); } @@ -235,7 +293,8 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { Collections.emptyList(), 0, null, false, null); } - private GradleVersion(@NonNull String rawValue, + private GradleVersion( + @NonNull String rawValue, @NonNull VersionSegment majorSegment, @Nullable VersionSegment minorSegment, @Nullable VersionSegment microSegment, @@ -243,7 +302,7 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { int preview, @Nullable String previewType, boolean snapshot, - String qualifiers) { + VersionQualifiers qualifiers) { mRawValue = rawValue; mMajorSegment = majorSegment; mMinorSegment = minorSegment; @@ -342,28 +401,37 @@ public class GradleVersion implements Comparable<GradleVersion>, Serializable { delta = mSnapshot == version.mSnapshot ? 0 : (mSnapshot ? -1 : 1); } else if (version.mQualifiers == null) { return -1; - } else if (mQualifiers.startsWith("dev") && version.mQualifiers.startsWith("dev")) { - delta = mQualifiers.compareTo(version.mQualifiers); - } else if (mQualifiers.startsWith("dev") || version.mQualifiers.startsWith("dev")) { - delta = mQualifiers.startsWith("dev") ? -1 : 1; + } else if (mQualifiers.previewType.equals("dev") + && version.mQualifiers.previewType.equals("dev")) { + delta = mQualifiers.preview - version.mQualifiers.preview; + } else if (mQualifiers.previewType.equals("dev") + || version.mQualifiers.previewType.equals("dev")) { + delta = mQualifiers.previewType.equals("dev") ? -1 : 1; + } else if (mQualifiers.previewType.equals(version.mQualifiers.previewType)) { + delta = mQualifiers.preview - version.mQualifiers.preview; + if (delta == 0) { + delta = + mQualifiers.additionalPreviewType + - version.mQualifiers.additionalPreviewType; + } } else { - delta = mQualifiers.compareTo(version.mQualifiers); + // TODO(b/242691473): Fix previewType comparison. + delta = mQualifiers.previewType.compareTo(version.mQualifiers.previewType); } } return delta; } /** - * Is this {@linkplain GradleVersion} at least as high as the given - * major, minor, micro version? + * Is this {@linkplain GradleVersion} at least as high as the given major, minor, micro version? */ public boolean isAtLeast(int major, int minor, int micro) { return isAtLeast(major, minor, micro, null, 0, false); } /** - * Is this {@linkplain GradleVersion} at least as high as the given - * major, minor, micro version? Any preview suffixes are ignored. + * Is this {@linkplain GradleVersion} at least as high as the given major, minor, micro version? + * Any previewType suffixes are ignored. */ public boolean isAtLeastIncludingPreviews(int major, int minor, int micro) { return isAtLeast(major, minor, micro, "", 0, false); diff --git a/sdk-common/src/main/java/com/android/ide/common/repository/NetworkCache.kt b/sdk-common/src/main/java/com/android/ide/common/repository/NetworkCache.kt index c819d49c67..0999f2f3bd 100644 --- a/sdk-common/src/main/java/com/android/ide/common/repository/NetworkCache.kt +++ b/sdk-common/src/main/java/com/android/ide/common/repository/NetworkCache.kt @@ -50,6 +50,7 @@ abstract class NetworkCache constructor( * */ private val networkEnabled: Boolean = true ) { + protected var lastReadSourceType: DataSourceType = DataSourceType.UNKNOWN_SOURCE /** Reads the given query URL in, with the given time out, and returns the bytes found. */ @Slow @@ -66,7 +67,7 @@ abstract class NetworkCache constructor( protected open fun findData(relative: String): InputStream? { if (cacheDir != null) { synchronized(cacheDir) { - val file = cacheDir.resolve(if (relative.isNotEmpty()) relative else cacheKey) + val file = cacheDir.resolve(relative.ifEmpty { cacheKey }) try { val lastModified = CancellableFileIo.getLastModifiedTime(file).toMillis() val now = System.currentTimeMillis() @@ -78,6 +79,15 @@ abstract class NetworkCache constructor( // - Outside the "cache expiry interval" if a network connection is allowed we always try to download the // latest version (code bellow). If a network connection is not allowed, we assume the cache only exists // because it was (or will be) updated on a background task where a network connection is allowed. + lastReadSourceType = if (lastModified != 0L) { + if (now - lastModified > expiryMs) { + DataSourceType.CACHE_FILE_EXPIRED_NO_NETWORK + } else { + DataSourceType.CACHE_FILE_RECENT + } + } else { + DataSourceType.CACHE_FILE_EXPIRED_UNKNOWN + } return CancellableFileIo.newInputStream(file) } } catch (ignore: NoSuchFileException) { @@ -85,6 +95,7 @@ abstract class NetworkCache constructor( if (networkEnabled) { try { + lastReadSourceType = DataSourceType.CACHE_FILE_NEW val data = readUrlData("$baseUrl$relative", networkTimeoutMs) if (data != null) { file.parent?.let { Files.createDirectories(it) } @@ -97,8 +108,9 @@ abstract class NetworkCache constructor( throw e } catch (e: Throwable) { - // timeouts etc: fall through to use "expired" data, if available, otherwise use the Builtin index + // timeouts etc.: fall through to use "expired" data, if available, otherwise use the Builtin index try { + lastReadSourceType = DataSourceType.CACHE_FILE_EXPIRED_NETWORK_ERROR return CancellableFileIo.newInputStream(file) } catch (ignore: NoSuchFileException) { } @@ -108,6 +120,27 @@ abstract class NetworkCache constructor( } // Fallback: Builtin index, used for offline scenarios etc - return readDefaultData(relative) + val result = readDefaultData(relative) + // Assign after reading, so it can be used inside readDefaultData for logging purposes + lastReadSourceType = DataSourceType.DEFAULT_DATA + return result + } + + enum class DataSourceType { + UNKNOWN_SOURCE, + // Test data, not to be used in production + TEST_DATA, + // Cache file is too old but no network is available + CACHE_FILE_EXPIRED_NO_NETWORK, + // Cache file is too old, network is available but was not able to update + CACHE_FILE_EXPIRED_NETWORK_ERROR, + // Cache file exist but cannot tell if too old + CACHE_FILE_EXPIRED_UNKNOWN, + // Cache file exists and has not expired + CACHE_FILE_RECENT, + // Cache file and was just downloaded + CACHE_FILE_NEW, + // Default data was used + DEFAULT_DATA, } } diff --git a/sdk-common/src/main/java/com/android/ide/common/resources/AbstractResourceRepository.java b/sdk-common/src/main/java/com/android/ide/common/resources/AbstractResourceRepository.java index b246ff315a..959002ad14 100644 --- a/sdk-common/src/main/java/com/android/ide/common/resources/AbstractResourceRepository.java +++ b/sdk-common/src/main/java/com/android/ide/common/resources/AbstractResourceRepository.java @@ -55,7 +55,7 @@ public abstract class AbstractResourceRepository implements ResourceRepository { @NonNull String resourceName) { ListMultimap<String, ResourceItem> map = getResourcesInternal(namespace, resourceType); List<ResourceItem> items = map.get(resourceName); - return items == null ? ImmutableList.of() : ImmutableList.copyOf(items); + return items.isEmpty() ? ImmutableList.of() : ImmutableList.copyOf(items); } @Override @@ -93,7 +93,7 @@ public abstract class AbstractResourceRepository implements ResourceRepository { @NonNull String resourceName) { ListMultimap<String, ResourceItem> map = getResourcesInternal(namespace, resourceType); List<ResourceItem> items = map.get(resourceName); - return items != null && !items.isEmpty(); + return !items.isEmpty(); } @Override diff --git a/sdk-common/src/test/java/com/android/ide/common/repository/GradleCoordinateTest.java b/sdk-common/src/test/java/com/android/ide/common/repository/GradleCoordinateTest.java index afda23849b..e12f92d889 100644 --- a/sdk-common/src/test/java/com/android/ide/common/repository/GradleCoordinateTest.java +++ b/sdk-common/src/test/java/com/android/ide/common/repository/GradleCoordinateTest.java @@ -425,4 +425,4 @@ public class GradleCoordinateTest extends BaseTestCase { test = new GradleCoordinate("a.b.c", "foo", 1); assertTrue(actual.matches(test)); } -}
\ No newline at end of file +} diff --git a/sdk-common/src/test/java/com/android/ide/common/repository/GradleVersionTest.java b/sdk-common/src/test/java/com/android/ide/common/repository/GradleVersionTest.java index 2212b01c23..96d0f06e9b 100644 --- a/sdk-common/src/test/java/com/android/ide/common/repository/GradleVersionTest.java +++ b/sdk-common/src/test/java/com/android/ide/common/repository/GradleVersionTest.java @@ -367,6 +367,7 @@ public class GradleVersionTest { assertTrue(GradleVersion.parse("1.0.0-alpha9-1").compareTo("1.0.0-alpha9-2") < 0); assertTrue(GradleVersion.parse("1.0.0-rc1").compareTo("1.0.0-alpha2") > 0); assertTrue(GradleVersion.parse("2.0.0-alpha1").compareTo("1.0.0-alpha1") > 0); + assertTrue(GradleVersion.parse("2.0.0-alpha08").compareTo("2.0.0-alpha6") > 0); // A pure -dev version is larger than a "numbered" preview. So if a piece of DSL was added // in alpha3, projects for 3.0.0-dev will use it. diff --git a/testutils/src/main/java/com/android/testutils/TestUtils.java b/testutils/src/main/java/com/android/testutils/TestUtils.java index 8457db92ae..60639022d3 100644 --- a/testutils/src/main/java/com/android/testutils/TestUtils.java +++ b/testutils/src/main/java/com/android/testutils/TestUtils.java @@ -216,6 +216,16 @@ public class TestUtils { return getWorkspaceRoot().resolve(relativePath); } + /** Gets the path to a specific Bazel workspace. */ + @NonNull + public static Path getWorkspaceRoot(@NonNull String workspaceName) throws IOException { + String pathToParent = runningFromBazel() ? ".." : "bazel-out/../../../external"; + // Canonicalize to get rid of the ".."s or symlinks. + Path canonicalPath = + resolveWorkspacePathUnchecked(pathToParent).toFile().getCanonicalFile().toPath(); + return canonicalPath.resolve(workspaceName); + } + /** Returns true if the file exists in the workspace. */ public static boolean workspaceFileExists(@NonNull String path) { return Files.exists(getWorkspaceRoot().resolve(path)); diff --git a/utp/android-device-provider-gradle-proto/BUILD b/utp/android-device-provider-gradle-proto/BUILD index 1fdfa119f9..63ec88ee5b 100644 --- a/utp/android-device-provider-gradle-proto/BUILD +++ b/utp/android-device-provider-gradle-proto/BUILD @@ -1,4 +1,4 @@ -load("//tools/base/bazel:proto.bzl", "java_proto_library", "maven_proto_library") +load("//tools/base/bazel:proto.bzl", "android_java_proto_library", "maven_proto_library") load("//tools/base/common:version.bzl", "BASE_VERSION") maven_proto_library( @@ -12,10 +12,9 @@ maven_proto_library( visibility = ["//visibility:public"], ) -java_proto_library( - name = "studio.android-device-provider-gradle-proto", +android_java_proto_library( + name = "libstudio.android-device-provider-gradle-proto", srcs = glob(["*.proto"]), - proto_java_runtime_library = ["@maven//:com.google.protobuf.protobuf-java"], resource_strip_prefix = "tools/base/utp/android-device-provider-gradle-proto", visibility = ["//visibility:public"], ) diff --git a/utp/android-test-plugin-host-device-info-proto/BUILD b/utp/android-test-plugin-host-device-info-proto/BUILD index 4621973b6b..82107d0c5a 100644 --- a/utp/android-test-plugin-host-device-info-proto/BUILD +++ b/utp/android-test-plugin-host-device-info-proto/BUILD @@ -1,4 +1,4 @@ -load("//tools/base/bazel:proto.bzl", "java_proto_library", "maven_proto_library") +load("//tools/base/bazel:proto.bzl", "android_java_proto_library", "maven_proto_library") load("//tools/base/common:version.bzl", "BASE_VERSION") maven_proto_library( @@ -11,9 +11,8 @@ maven_proto_library( visibility = ["//visibility:public"], ) -java_proto_library( - name = "studio.android-test-plugin-host-device-info-proto", +android_java_proto_library( + name = "libstudio.android-test-plugin-host-device-info-proto", srcs = glob(["src/main/proto/*.proto"]), - proto_java_runtime_library = ["@maven//:com.google.protobuf.protobuf-java"], visibility = ["//visibility:public"], ) diff --git a/utp/android-test-plugin-host-retention-proto/BUILD b/utp/android-test-plugin-host-retention-proto/BUILD index 40d08872df..cb65301328 100644 --- a/utp/android-test-plugin-host-retention-proto/BUILD +++ b/utp/android-test-plugin-host-retention-proto/BUILD @@ -1,4 +1,4 @@ -load("//tools/base/bazel:proto.bzl", "java_proto_library", "maven_proto_library") +load("//tools/base/bazel:proto.bzl", "android_java_proto_library", "maven_proto_library") load("//tools/base/common:version.bzl", "BASE_VERSION") maven_proto_library( @@ -15,9 +15,8 @@ maven_proto_library( visibility = ["//visibility:public"], ) -java_proto_library( - name = "studio.android-test-plugin-host-retention-proto", +android_java_proto_library( + name = "libstudio.android-test-plugin-host-retention-proto", srcs = glob(["src/main/proto/*.proto"]), - proto_java_runtime_library = ["@maven//:com.google.protobuf.protobuf-java"], visibility = ["//visibility:public"], ) diff --git a/utp/android-test-plugin-result-listener-gradle-proto/BUILD b/utp/android-test-plugin-result-listener-gradle-proto/BUILD index d209772a22..71a7239a80 100644 --- a/utp/android-test-plugin-result-listener-gradle-proto/BUILD +++ b/utp/android-test-plugin-result-listener-gradle-proto/BUILD @@ -1,4 +1,4 @@ -load("//tools/base/bazel:proto.bzl", "java_proto_library", "maven_proto_library") +load("//tools/base/bazel:proto.bzl", "android_java_proto_library", "maven_proto_library") load("//tools/base/common:version.bzl", "BASE_VERSION") maven_proto_library( @@ -22,9 +22,8 @@ maven_proto_library( ) # Android Studio only needs protobuf message without gRPC services. -java_proto_library( - name = "studio.android-test-plugin-result-listener-gradle-proto", +android_java_proto_library( + name = "libstudio.android-test-plugin-result-listener-gradle-proto", srcs = glob(["src/main/proto/*.proto"]), - proto_java_runtime_library = ["@maven//:com.google.protobuf.protobuf-java"], visibility = ["//visibility:public"], ) |