diff --git a/.bazelci/postsubmit.yml b/.bazelci/postsubmit.yml index 8578d0dc9c48fa..9f63194fe4884b 100644 --- a/.bazelci/postsubmit.yml +++ b/.bazelci/postsubmit.yml @@ -41,11 +41,6 @@ tasks: - "-//src/test/shell/bazel:bazel_coverage_cc_released_test_gcc" - "-//src/test/shell/bazel:bazel_coverage_cc_head_test_gcc" - "-//src/test/shell/bazel:bazel_coverage_sh_test" - # Centos7 uses python 2 by default, so these fail: https://github.com/bazelbuild/bazel/issues/18776 - - "-//src/test/shell/bazel/android:android_instrumentation_test_integration_test" - - "-//src/test/shell/bazel/android:android_instrumentation_test_integration_test_with_head_android_tools" - - "-//src/test/shell/bazel/android:aapt_integration_test" - - "-//src/test/shell/bazel/android:aapt_integration_test_with_head_android_tools" include_json_profile: - build - test diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 19b8d00cd198a7..87f520de8e7b0d 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -44,11 +44,6 @@ tasks: - "-//src/test/shell/bazel:bazel_coverage_cc_released_test_gcc" - "-//src/test/shell/bazel:bazel_coverage_cc_head_test_gcc" - "-//src/test/shell/bazel:bazel_coverage_sh_test" - # Centos7 uses python 2 by default, so these fail: https://github.com/bazelbuild/bazel/issues/18776 - - "-//src/test/shell/bazel/android:android_instrumentation_test_integration_test" - - "-//src/test/shell/bazel/android:android_instrumentation_test_integration_test_with_head_android_tools" - - "-//src/test/shell/bazel/android:aapt_integration_test" - - "-//src/test/shell/bazel/android:aapt_integration_test_with_head_android_tools" include_json_profile: - build - test diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index afd2817ed4646c..0e639c742aea31 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.bazel.rules; -import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; @@ -38,14 +37,9 @@ import com.google.devtools.build.lib.bazel.BazelConfiguration; import com.google.devtools.build.lib.bazel.repository.LocalConfigPlatformRule; import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryRule; -import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidBinaryRule; -import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidDeviceScriptFixture; -import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidHostServiceFixture; -import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidLibraryRule; import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidSdkRule; import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidSemantics; import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidToolsDefaultsJarRule; -import com.google.devtools.build.lib.bazel.rules.android.BazelDexArchiveAspect; import com.google.devtools.build.lib.bazel.rules.android.BazelSdkToolchainRule; import com.google.devtools.build.lib.bazel.rules.python.BazelPyBinaryRule; import com.google.devtools.build.lib.bazel.rules.python.BazelPyBuiltins; @@ -60,26 +54,21 @@ import com.google.devtools.build.lib.rules.android.AndroidBinaryNativeLibsInfo; import com.google.devtools.build.lib.rules.android.AndroidCcLinkParamsProvider; import com.google.devtools.build.lib.rules.android.AndroidConfiguration; -import com.google.devtools.build.lib.rules.android.AndroidDeviceScriptFixtureRule; import com.google.devtools.build.lib.rules.android.AndroidDexInfo; import com.google.devtools.build.lib.rules.android.AndroidFeatureFlagSetProvider; -import com.google.devtools.build.lib.rules.android.AndroidHostServiceFixtureRule; import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider; import com.google.devtools.build.lib.rules.android.AndroidIdlProvider; import com.google.devtools.build.lib.rules.android.AndroidInstrumentationInfo; import com.google.devtools.build.lib.rules.android.AndroidLibraryAarInfo; -import com.google.devtools.build.lib.rules.android.AndroidLibraryBaseRule; import com.google.devtools.build.lib.rules.android.AndroidLibraryResourceClassJarProvider; import com.google.devtools.build.lib.rules.android.AndroidManifestInfo; import com.google.devtools.build.lib.rules.android.AndroidNativeLibsInfo; import com.google.devtools.build.lib.rules.android.AndroidNeverLinkLibrariesProvider; -import com.google.devtools.build.lib.rules.android.AndroidNeverlinkAspect; import com.google.devtools.build.lib.rules.android.AndroidOptimizationInfo; import com.google.devtools.build.lib.rules.android.AndroidOptimizedJarInfo; import com.google.devtools.build.lib.rules.android.AndroidPreDexJarProvider; import com.google.devtools.build.lib.rules.android.AndroidProguardInfo; import com.google.devtools.build.lib.rules.android.AndroidResourcesInfo; -import com.google.devtools.build.lib.rules.android.AndroidRuleClasses; import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.AndroidBaseToolsDefaultsJarRule; import com.google.devtools.build.lib.rules.android.AndroidSdkBaseRule; import com.google.devtools.build.lib.rules.android.AndroidSdkProvider; @@ -87,7 +76,6 @@ import com.google.devtools.build.lib.rules.android.ApkInfo; import com.google.devtools.build.lib.rules.android.BaselineProfileProvider; import com.google.devtools.build.lib.rules.android.BazelAndroidConfiguration; -import com.google.devtools.build.lib.rules.android.DexArchiveAspect; import com.google.devtools.build.lib.rules.android.ProguardMappingProvider; import com.google.devtools.build.lib.rules.android.databinding.DataBindingV2Provider; import com.google.devtools.build.lib.rules.config.ConfigRules; @@ -332,33 +320,15 @@ public ImmutableList requires() { new RuleSet() { @Override public void init(ConfiguredRuleClassProvider.Builder builder) { - RepositoryName toolsRepository = checkNotNull(builder.getToolsRepository()); builder.addConfigurationFragment(AndroidConfiguration.class); builder.addConfigurationFragment(BazelAndroidConfiguration.class); - AndroidNeverlinkAspect androidNeverlinkAspect = new AndroidNeverlinkAspect(); - DexArchiveAspect dexArchiveAspect = new BazelDexArchiveAspect(toolsRepository); - builder.addNativeAspectClass(androidNeverlinkAspect); - builder.addNativeAspectClass(dexArchiveAspect); - + builder.addRuleDefinition(new AndroidBaseToolsDefaultsJarRule()); builder.addRuleDefinition(new AndroidSdkBaseRule()); builder.addRuleDefinition(new BazelAndroidSdkRule()); - builder.addRuleDefinition(new AndroidBaseToolsDefaultsJarRule()); builder.addRuleDefinition(new BazelAndroidToolsDefaultsJarRule()); - builder.addRuleDefinition(new AndroidRuleClasses.AndroidBaseRule()); - builder.addRuleDefinition(new AndroidRuleClasses.AndroidResourceSupportRule()); - builder.addRuleDefinition( - new AndroidRuleClasses.AndroidBinaryBaseRule( - androidNeverlinkAspect, dexArchiveAspect)); builder.addRuleDefinition(new BazelSdkToolchainRule()); - builder.addRuleDefinition(new AndroidLibraryBaseRule(androidNeverlinkAspect)); - builder.addRuleDefinition(new BazelAndroidLibraryRule()); - builder.addRuleDefinition(new BazelAndroidBinaryRule()); - builder.addRuleDefinition( - new AndroidDeviceScriptFixtureRule(BazelAndroidDeviceScriptFixture.class)); - builder.addRuleDefinition( - new AndroidHostServiceFixtureRule(BazelAndroidHostServiceFixture.class)); AndroidBootstrap bootstrap = new AndroidBootstrap( diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinary.java deleted file mode 100644 index c419d3a581d751..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinary.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppSemantics; -import com.google.devtools.build.lib.bazel.rules.java.BazelJavaSemantics; -import com.google.devtools.build.lib.rules.android.AndroidBinary; -import com.google.devtools.build.lib.rules.android.AndroidSemantics; -import com.google.devtools.build.lib.rules.cpp.CppSemantics; -import com.google.devtools.build.lib.rules.java.JavaSemantics; - -/** - * Bazel-specific configured target factory for {@code android_binary}. - */ -public class BazelAndroidBinary extends AndroidBinary { - @Override - protected JavaSemantics createJavaSemantics() { - return BazelJavaSemantics.INSTANCE; - } - - @Override - protected AndroidSemantics createAndroidSemantics() { - return BazelAndroidSemantics.INSTANCE; - } - - @Override - protected CppSemantics createCppSemantics() { - return BazelCppSemantics.CPP; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinaryRule.java deleted file mode 100644 index d9d0a5dd970e42..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidBinaryRule.java +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; - -import com.google.devtools.build.lib.analysis.Allowlist; -import com.google.devtools.build.lib.analysis.RuleDefinition; -import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransitionFactory; -import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses.CcToolchainRequiringRule; -import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses; -import com.google.devtools.build.lib.packages.RuleClass; -import com.google.devtools.build.lib.rules.android.AndroidFeatureFlagSetProvider; -import com.google.devtools.build.lib.rules.android.AndroidPlatformsTransition; -import com.google.devtools.build.lib.rules.android.AndroidRuleClasses; -import com.google.devtools.build.lib.rules.config.ConfigFeatureFlagTransitionFactory; - -/** - * Rule class definition for {@code android_binary}. - */ -public class BazelAndroidBinaryRule implements RuleDefinition { - - @Override - public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) { - return builder - .cfg( - ComposingTransitionFactory.of( - new ConfigFeatureFlagTransitionFactory( - AndroidFeatureFlagSetProvider.FEATURE_FLAG_ATTR), - AndroidPlatformsTransition.create())) - /* - - */ - .setImplicitOutputsFunction(AndroidRuleClasses.ANDROID_BINARY_IMPLICIT_OUTPUTS) - .add( - Allowlist.getAttributeFromAllowlistName("export_deps") - .value(environment.getToolsLabel("//tools/android:export_deps_allowlist"))) - .add( - Allowlist.getAttributeFromAllowlistName("allow_deps_without_srcs") - .value( - environment.getToolsLabel( - "//tools/android:allow_android_library_deps_without_srcs_allowlist"))) - .add( - attr("$build_info_translator", LABEL) - .value(environment.getToolsLabel("//tools/build_defs/build_info:java_build_info"))) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("android_binary") - .ancestors( - AndroidRuleClasses.AndroidBinaryBaseRule.class, - BazelJavaRuleClasses.JavaBaseRule.class, - BazelSdkToolchainRule.class, - CcToolchainRequiringRule.class) - .factoryClass(BazelAndroidBinary.class) - .build(); - } -} -/* - -

- Produces Android application package files (.apk). -

- -${IMPLICIT_OUTPUTS} - -

Examples

-

Examples of Android rules can be found in the examples/android directory of the -Bazel source tree. - -*/ diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidDeviceScriptFixture.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidDeviceScriptFixture.java deleted file mode 100644 index 6d40ccd32194f7..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidDeviceScriptFixture.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.rules.android.AndroidDeviceScriptFixture; - -/** Implementation of {@code android_device_script_fixture} with Bazel semantics. */ -public class BazelAndroidDeviceScriptFixture extends AndroidDeviceScriptFixture { - public BazelAndroidDeviceScriptFixture() { - super(BazelAndroidSemantics.INSTANCE); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidHostServiceFixture.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidHostServiceFixture.java deleted file mode 100644 index 61576807830bee..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidHostServiceFixture.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.rules.android.AndroidHostServiceFixture; - -/** Implementation of {@code android_host_service_fixture} with Bazel semantics. */ -public class BazelAndroidHostServiceFixture extends AndroidHostServiceFixture { - public BazelAndroidHostServiceFixture() { - super(BazelAndroidSemantics.INSTANCE); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibrary.java deleted file mode 100644 index a30889652a1b4b..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibrary.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.bazel.rules.java.BazelJavaSemantics; -import com.google.devtools.build.lib.rules.android.AndroidLibrary; -import com.google.devtools.build.lib.rules.android.AndroidSemantics; -import com.google.devtools.build.lib.rules.java.JavaSemantics; - -/** - * Bazel-specific configured target factory for {@code android_library}. - */ -public class BazelAndroidLibrary extends AndroidLibrary { - - @Override - protected JavaSemantics createJavaSemantics() { - return BazelJavaSemantics.INSTANCE; - } - - @Override - protected AndroidSemantics createAndroidSemantics() { - return BazelAndroidSemantics.INSTANCE; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibraryRule.java deleted file mode 100644 index c5dff01ee71ef9..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLibraryRule.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.analysis.Allowlist; -import com.google.devtools.build.lib.analysis.RuleDefinition; -import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses; -import com.google.devtools.build.lib.packages.RuleClass; -import com.google.devtools.build.lib.rules.android.AndroidLibraryBaseRule; -import com.google.devtools.build.lib.rules.android.AndroidRuleClasses; - -/** - * Definition of the {@code android_library} rule for Bazel. - */ -public class BazelAndroidLibraryRule implements RuleDefinition { - - @Override - public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { - return builder - /* -

- */ - .setImplicitOutputsFunction(AndroidRuleClasses.ANDROID_LIBRARY_IMPLICIT_OUTPUTS) - .add( - Allowlist.getAttributeFromAllowlistName("allow_deps_without_srcs") - .value( - env.getToolsLabel( - "//tools/android:allow_android_library_deps_without_srcs_allowlist"))) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("android_library") - .ancestors( - BazelJavaRuleClasses.JavaBaseRule.class, - AndroidLibraryBaseRule.class, - BazelSdkToolchainRule.class) - .factoryClass(BazelAndroidLibrary.class) - .build(); - } -} - -/* - -

This rule compiles and archives its sources into a .jar file. - The Android runtime library android.jar is implicitly put on - the compilation class path. -

- -${IMPLICIT_OUTPUTS} - - -

Examples

-

Examples of Android rules can be found in the examples/android directory of the -Bazel source tree. - -

The following example shows -how to set idl_import_root. -Let //java/bazel/helloandroid/BUILD contain:

-
-android_library(
-    name = "parcelable",
-    srcs = ["MyParcelable.java"], # bazel.helloandroid.MyParcelable
-
-    # MyParcelable.aidl will be used as import for other .aidl
-    # files that depend on it, but will not be compiled.
-    idl_parcelables = ["MyParcelable.aidl"] # bazel.helloandroid.MyParcelable
-
-    # We don't need to specify idl_import_root since the aidl file
-    # which declares bazel.helloandroid.MyParcelable
-    # is present at java/bazel/helloandroid/MyParcelable.aidl
-    # underneath a java root (java/).
-)
-
-android_library(
-    name = "foreign_parcelable",
-    srcs = ["src/android/helloandroid/OtherParcelable.java"], # android.helloandroid.OtherParcelable
-    idl_parcelables = [
-        "src/android/helloandroid/OtherParcelable.aidl" # android.helloandroid.OtherParcelable
-    ],
-
-    # We need to specify idl_import_root because the aidl file which
-    # declares android.helloandroid.OtherParcelable is not positioned
-    # at android/helloandroid/OtherParcelable.aidl under a normal java root.
-    # Setting idl_import_root to "src" in //java/bazel/helloandroid
-    # adds java/bazel/helloandroid/src to the list of roots
-    # the aidl compiler will search for imported types.
-    idl_import_root = "src",
-)
-
-# Here, OtherInterface.aidl has an "import android.helloandroid.CallbackInterface;" statement.
-android_library(
-    name = "foreign_interface",
-    idl_srcs = [
-        "src/android/helloandroid/OtherInterface.aidl" # android.helloandroid.OtherInterface
-        "src/android/helloandroid/CallbackInterface.aidl" # android.helloandroid.CallbackInterface
-    ],
-
-    # As above, idl_srcs which are not correctly positioned under a java root
-    # must have idl_import_root set. Otherwise, OtherInterface (or any other
-    # interface in a library which depends on this one) will not be able
-    # to find CallbackInterface when it is imported.
-    idl_import_root = "src",
-)
-
-# MyParcelable.aidl is imported by MyInterface.aidl, so the generated
-# MyInterface.java requires MyParcelable.class at compile time.
-# Depending on :parcelable ensures that aidl compilation of MyInterface.aidl
-# specifies the correct import roots and can access MyParcelable.aidl, and
-# makes MyParcelable.class available to Java compilation of MyInterface.java
-# as usual.
-android_library(
-    name = "idl",
-    idl_srcs = ["MyInterface.aidl"],
-    deps = [":parcelable"],
-)
-
-# Here, ServiceParcelable uses and thus depends on ParcelableService,
-# when it's compiled, but ParcelableService also uses ServiceParcelable,
-# which creates a circular dependency.
-# As a result, these files must be compiled together, in the same android_library.
-android_library(
-    name = "circular_dependencies",
-    srcs = ["ServiceParcelable.java"],
-    idl_srcs = ["ParcelableService.aidl"],
-    idl_parcelables = ["ServiceParcelable.aidl"],
-)
-
- -*/ diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java index a14938dc047c77..eeff2bd3ca0ea1 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidSemantics.java @@ -15,20 +15,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.cmdline.PackageIdentifier; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.rules.android.AndroidBinary; import com.google.devtools.build.lib.rules.android.AndroidConfiguration; -import com.google.devtools.build.lib.rules.android.AndroidDataContext; import com.google.devtools.build.lib.rules.android.AndroidSemantics; -import com.google.devtools.build.lib.rules.android.ProguardHelper.ProguardOutput; -import com.google.devtools.build.lib.rules.java.JavaCommon; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; /** * Implementation of Bazel-specific behavior in Android rules. @@ -42,8 +33,6 @@ public class BazelAndroidSemantics implements AndroidSemantics { ImmutableSet.builder() .add(PackageIdentifier.createUnchecked("bazel_tools", "tools/android")) .build(); - private static final String BAZEL_TEST_RUNNER_MAIN_CLASS = - "com.google.testing.junit.runner.BazelTestRunner"; private BazelAndroidSemantics() {} @@ -61,54 +50,6 @@ public ImmutableList getCompatibleJavacOptions(RuleContext ruleContext) return javacArgs.build(); } - @Override - public void addMainDexListActionArguments( - RuleContext ruleContext, - SpawnAction.Builder builder, - CustomCommandLine.Builder commandLine, - Artifact proguardMap) {} - - @Override - public ImmutableList getProguardSpecsForManifest( - AndroidDataContext context, Artifact manifest) { - return ImmutableList.of(); - } - - @Override - public void addCoverageSupport( - RuleContext ruleContext, boolean forAndroidTest, JavaTargetAttributes.Builder attributes) {} - - @Override - public ImmutableList getAttributesWithJavaRuntimeDeps(RuleContext ruleContext) { - return switch (ruleContext.getRule().getRuleClass()) { - case "android_binary" -> ImmutableList.of("application_resources", "deps"); - default -> throw new UnsupportedOperationException("Only supported for top-level binaries"); - }; - } - - @Override - public Artifact getProguardOutputMap(RuleContext ruleContext) throws InterruptedException { - return ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_MAP); - } - - /** Bazel does not currently support any dex postprocessing. */ - @Override - public boolean postprocessClassesRewritesMap(RuleContext ruleContext) { - return false; - } - - @Override - public AndroidBinary.DexPostprocessingOutput postprocessClassesDexZip( - RuleContext ruleContext, - NestedSetBuilder filesBuilder, - Artifact classesDexZip, - ProguardOutput proguardOutput, - Artifact proguardMapOutput, - Artifact mainDexList) - throws InterruptedException { - return AndroidBinary.DexPostprocessingOutput.create(classesDexZip, proguardOutput.getMapping()); - } - @Override public void registerMigrationRuleError(RuleContext ruleContext) throws RuleErrorException { if (STARLARK_MIGRATION_NATIVE_USAGE_ALLOW_LIST.contains( @@ -124,67 +65,4 @@ public void registerMigrationRuleError(RuleContext ruleContext) throws RuleError + ruleContext.getRule().getRuleClass() + "\"). See http://github.com/bazelbuild/rules_android."); } - - /* Bazel does not currently support baseline profiles in the final apk. */ - @Override - public Artifact getArtProfileForApk( - RuleContext ruleContext, - Artifact finalClassesDex, - Artifact proguardOutputMap, - String baselineProfileDir) { - return null; - } - - /* Bazel does not currently support baseline profiles in the final apk. */ - @Override - public Artifact compileBaselineProfile( - RuleContext ruleContext, - Artifact finalClassesDex, - Artifact proguardOutputMap, - Artifact mergedStaticProfile, - String baselineProfileDir) { - return null; - } - - /* Bazel does not currently support baseline profiles in the final apk. */ - @Override - public Artifact mergeBaselineProfiles( - RuleContext ruleContext, String baselineProfileDir, boolean includeStartupProfiles) { - return null; - } - - /* Bazel does not currently support baseline profiles in the final apk. */ - @Override - public Artifact mergeStartupProfiles(RuleContext ruleContext, String baselineProfileDir) { - return null; - } - - /* Bazel does not currently support baseline profiles in the final apk. */ - @Override - public Artifact expandBaselineProfileWildcards( - RuleContext ruleContext, - Artifact deployJar, - Artifact mergedStaticProfile, - String baselineProfileDir) { - return null; - } - - @Override - public Artifact getProtoMapping(RuleContext ruleContext) throws InterruptedException { - return null; - } - - @Override - public Artifact getObfuscatedConstantStringMap(RuleContext ruleContext) - throws InterruptedException { - return null; - } - - @Override - public void checkRule(RuleContext ruleContext, JavaCommon javaCommon) {} - - @Override - public String getTestRunnerMainClass() { - return BAZEL_TEST_RUNNER_MAIN_CLASS; - } } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelDexArchiveAspect.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelDexArchiveAspect.java deleted file mode 100644 index e93983bce9b714..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelDexArchiveAspect.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2021 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.bazel.rules.android; - -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.lib.rules.android.DexArchiveAspect; - -/** Fills {@link DexArchiveAspect} with appropriate Android tools and toolchain references. */ -public class BazelDexArchiveAspect extends DexArchiveAspect { - public BazelDexArchiveAspect(RepositoryName toolsRepository) { - super(toolsRepository, BazelSdkToolchainRule.TOOLCHAIN_LABEL); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java deleted file mode 100644 index c17a562d1eb221..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java +++ /dev/null @@ -1,2740 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; -import static com.google.devtools.build.lib.packages.Type.STRING; - -import com.google.auto.value.AutoValue; -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.actions.ActionConflictException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact; -import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; -import com.google.devtools.build.lib.actions.CommandLine; -import com.google.devtools.build.lib.actions.FailAction; -import com.google.devtools.build.lib.actions.ParamFileInfo; -import com.google.devtools.build.lib.actions.ParameterFile; -import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; -import com.google.devtools.build.lib.analysis.Allowlist; -import com.google.devtools.build.lib.analysis.AnalysisUtils; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FileProvider; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; -import com.google.devtools.build.lib.analysis.OutputGroupInfo; -import com.google.devtools.build.lib.analysis.RequiredConfigFragmentsProvider; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.RunfilesProvider; -import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; -import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate; -import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate.OutputPathMapper; -import com.google.devtools.build.lib.analysis.actions.SymlinkAction; -import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.packages.AttributeMap; -import com.google.devtools.build.lib.packages.BuildType; -import com.google.devtools.build.lib.packages.RuleClass; -import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.packages.TriState; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode; -import com.google.devtools.build.lib.rules.android.ProguardHelper.ProguardOutput; -import com.google.devtools.build.lib.rules.android.ZipFilterBuilder.CheckHashMismatchMode; -import com.google.devtools.build.lib.rules.android.databinding.DataBinding; -import com.google.devtools.build.lib.rules.cpp.CppSemantics; -import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder; -import com.google.devtools.build.lib.rules.java.JavaCommon; -import com.google.devtools.build.lib.rules.java.JavaConfiguration; -import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel; -import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; -import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; -import com.google.devtools.build.lib.rules.java.OneVersionCheckActionBuilder; -import com.google.devtools.build.lib.rules.java.ProguardSpecProvider; -import com.google.devtools.build.lib.server.FailureDetails.FailAction.Code; -import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import javax.annotation.Nullable; -import net.starlark.java.eval.StarlarkInt; - -/** An implementation for the "android_binary" rule. */ -public abstract class AndroidBinary implements RuleConfiguredTargetFactory { - - private static final String DX_MINIMAL_MAIN_DEX_OPTION = "--minimal-main-dex"; - - protected abstract JavaSemantics createJavaSemantics(); - - protected abstract AndroidSemantics createAndroidSemantics(); - - protected abstract CppSemantics createCppSemantics(); - - @Override - @Nullable - public final ConfiguredTarget create(RuleContext ruleContext) - throws InterruptedException, RuleErrorException, ActionConflictException { - CppSemantics cppSemantics = createCppSemantics(); - JavaSemantics javaSemantics = createJavaSemantics(); - AndroidSemantics androidSemantics = createAndroidSemantics(); - androidSemantics.checkForMigrationTag(ruleContext); - androidSemantics.validateAndroidBinaryRuleContext(ruleContext); - AndroidSdkProvider.verifyPresence(ruleContext); - - NestedSetBuilder filesBuilder = NestedSetBuilder.stableOrder(); - RuleConfiguredTargetBuilder builder = - init(ruleContext, filesBuilder, cppSemantics, javaSemantics, androidSemantics); - return builder.build(); - } - - @Override - public final void addRuleImplSpecificRequiredConfigFragments( - RequiredConfigFragmentsProvider.Builder requiredFragments, - AttributeMap attributes, - BuildConfigurationValue configuration) { - requiredFragments.addStarlarkOptions(AndroidFeatureFlagSetProvider.getFeatureFlags(attributes)); - } - - /** Checks expected rule invariants, throws rule errors if anything is set wrong. */ - private static void validateRuleContext(RuleContext ruleContext, AndroidDataContext dataContext) - throws RuleErrorException { - if (getMultidexMode(ruleContext) != MultidexMode.LEGACY - && ruleContext - .attributes() - .isAttributeValueExplicitlySpecified("main_dex_proguard_specs")) { - ruleContext.throwWithAttributeError( - "main_dex_proguard_specs", - "The 'main_dex_proguard_specs' attribute is only allowed if 'multidex' is" - + " set to 'legacy'"); - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("proguard_apply_mapping")) { - if (dataContext.throwOnProguardApplyMapping()) { - ruleContext.throwWithAttributeError( - "proguard_apply_mapping", "This attribute is not supported"); - } - if (ruleContext - .attributes() - .get(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST) - .isEmpty()) { - ruleContext.throwWithAttributeError( - "proguard_apply_mapping", - "'proguard_apply_mapping' can only be used when 'proguard_specs' is also set"); - } - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("proguard_apply_dictionary")) { - if (dataContext.throwOnProguardApplyDictionary()) { - ruleContext.throwWithAttributeError( - "proguard_apply_dictionary", "This attribute is not supported"); - } - if (ruleContext - .attributes() - .get(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST) - .isEmpty()) { - ruleContext.throwWithAttributeError( - "proguard_apply_dictionary", - "'proguard_apply_dictionary' can only be used when 'proguard_specs' is also set"); - } - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("shrink_resources") - && dataContext.throwOnShrinkResources()) { - ruleContext.throwWithAttributeError("shrink_resources", "This attribute is not supported"); - } - - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("min_sdk_version") - && Allowlist.hasAllowlist(ruleContext, "allow_min_sdk_version") - && !Allowlist.isAvailable(ruleContext, "allow_min_sdk_version")) { - ruleContext.attributeError( - "min_sdk_version", "Target is not permitted to set min_sdk_version"); - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("startup_profiles") - && Allowlist.hasAllowlist(ruleContext, "allow_baseline_profiles_optimizer_integration") - && !Allowlist.isAvailable(ruleContext, "allow_baseline_profiles_optimizer_integration")) { - ruleContext.attributeError( - "startup_profiles", "Target is not permitted to use startup_profiles."); - } - if (ruleContext.getFragment(JavaConfiguration.class).enforceProguardFileExtension() - && ruleContext.attributes().has(ProguardHelper.PROGUARD_SPECS)) { - List pathsWithUnexpectedExtension = - ruleContext.getPrerequisiteArtifacts(ProguardHelper.PROGUARD_SPECS).list().stream() - .filter(Artifact::isSourceArtifact) - .map(Artifact::getRootRelativePath) - .filter( - // This checks the filename directly instead of using FileType because we want to - // exclude third_party/, but FileType is generally only given the basename. - // - // See e.g. RuleContext#validateDirectPrerequisiteType and - // PrerequisiteArtifacts#filter. - path -> - !path.getFileExtension().equals("pgcfg") - && !path.startsWith(RuleClass.THIRD_PARTY_PREFIX) - && !path.startsWith(RuleClass.EXPERIMENTAL_PREFIX)) - .collect(toImmutableList()); - if (!pathsWithUnexpectedExtension.isEmpty()) { - ruleContext.throwWithAttributeError( - ProguardHelper.PROGUARD_SPECS, - "Proguard spec files must use the .pgcfg extension. These files do not end in .pgcfg: " - + pathsWithUnexpectedExtension); - } - } - } - - private static RuleConfiguredTargetBuilder init( - RuleContext ruleContext, - NestedSetBuilder filesBuilder, - CppSemantics cppSemantics, - JavaSemantics javaSemantics, - AndroidSemantics androidSemantics) - throws InterruptedException, RuleErrorException { - - ResourceDependencies resourceDeps = - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink= */ false); - - AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext); - validateRuleContext(ruleContext, dataContext); - - // Retrieve and compile the resources defined on the android_binary rule. - AndroidResources.validateRuleContext(ruleContext); - - Map manifestValues = StampedAndroidManifest.getManifestValues(ruleContext); - - StampedAndroidManifest manifest; - if (isInstrumentation(ruleContext) - && dataContext.getAndroidConfig().disableInstrumentationManifestMerging()) { - manifest = - AndroidManifest.fromAttributes(ruleContext, dataContext, androidSemantics) - .stamp(dataContext); - } else { - manifest = - AndroidManifest.fromAttributes(ruleContext, dataContext, androidSemantics) - .mergeWithDeps( - dataContext, - androidSemantics, - ruleContext, - resourceDeps, - manifestValues, - ruleContext.getRule().isAttrDefined("manifest_merger", STRING) - ? ruleContext.attributes().get("manifest_merger", STRING) - : null); - } - - boolean shrinkResourceCycles = - dataContext.shouldShrinkResourceCycles( - ruleContext, dataContext.isResourceShrinkingEnabled()); - ProcessedAndroidData processedAndroidData = - ProcessedAndroidData.processBinaryDataFrom( - dataContext, - ruleContext, - manifest, - /* conditionalKeepRules= */ shrinkResourceCycles, - manifestValues, - AndroidResources.from(ruleContext, "resource_files"), - AndroidAssets.from(ruleContext), - resourceDeps, - AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false), - ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext), - ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"), - ruleContext.attributes().get("crunch_png", Type.BOOLEAN), - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig())); - - AndroidApplicationResourceInfo androidApplicationResourceInfo = - ruleContext.getPrerequisite( - "application_resources", AndroidApplicationResourceInfo.PROVIDER); - - final ResourceApk resourceApk; - boolean shouldCompileJavaSrcs = true; - if (androidApplicationResourceInfo == null) { - resourceApk = - new RClassGeneratorActionBuilder() - .withDependencies(resourceDeps) - .finalFields(!shrinkResourceCycles) - .setClassJarOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR)) - .build(dataContext, processedAndroidData); - } else { - resourceApk = - ResourceApk.fromAndroidApplicationResourceInfo( - ruleContext, dataContext.getAndroidConfig(), androidApplicationResourceInfo); - shouldCompileJavaSrcs = androidApplicationResourceInfo.shouldCompileJavaSrcs(); - } - - if (dataContext.useResourcePathShortening()) { - filesBuilder.add( - ruleContext.getImplicitOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_PATH_SHORTENING_MAP)); - } - - ruleContext.assertNoErrors(); - - JavaCommon javaCommon = - AndroidCommon.createJavaCommonWithAndroidDataBinding( - ruleContext, - javaSemantics, - resourceApk.asDataBindingContext(), - /* isLibrary */ false, - shouldCompileJavaSrcs); - androidSemantics.checkRule(ruleContext, javaCommon); - javaSemantics.checkForProtoLibraryAndJavaProtoLibraryOnSameProto(ruleContext, javaCommon); - - AndroidCommon androidCommon = new AndroidCommon(javaCommon, /* asNeverLink= */ true); - - // Remove the library resource JARs from the binary's runtime classpath. - // Resource classes from android_library dependencies are replaced by the binary's resource - // class. We remove them only at the top level so that resources included by a library that is - // a dependency of a java_library are still included, since these resources are propagated via - // android-specific providers and won't show up when we collect the library resource JARs. - // TODO(b/69552500): Instead, handle this properly so R JARs aren't put on the classpath for - // both binaries and libraries. - NestedSet excludedRuntimeArtifacts = getLibraryResourceJars(ruleContext); - - JavaTargetAttributes resourceClasses = - androidCommon.init( - javaSemantics, - androidSemantics, - resourceApk, - ruleContext.getConfiguration().isCodeCoverageEnabled(), - /* collectJavaCompilationArgs= */ true, - /* isBinary= */ true, - shouldCompileJavaSrcs, - excludedRuntimeArtifacts, - /* generateExtensionRegistry= */ true); - ruleContext.assertNoErrors(); - - Function derivedJarFunction = - collectDesugaredJars(ruleContext, androidCommon, androidSemantics, resourceClasses); - Artifact deployJar = - createDeployJar( - ruleContext, - javaSemantics, - androidCommon, - resourceClasses, - AndroidCommon.getAndroidConfig(ruleContext).checkDesugarDeps(), - derivedJarFunction); - - boolean isBinaryJarFiltered = isInstrumentation(ruleContext); - if (isBinaryJarFiltered) { - deployJar = getFilteredDeployJar(ruleContext, deployJar); - } - - OneVersionEnforcementLevel oneVersionEnforcementLevel = - ruleContext.getFragment(JavaConfiguration.class).oneVersionEnforcementLevel(); - Artifact oneVersionOutputArtifact = null; - if (oneVersionEnforcementLevel != OneVersionEnforcementLevel.OFF) { - NestedSet transitiveDependencies = - NestedSetBuilder.stableOrder() - .addAll( - Iterables.transform( - resourceClasses.getRuntimeClassPath().toList(), derivedJarFunction)) - .addAll( - Iterables.transform( - androidCommon.getJarsProducedForRuntime().toList(), derivedJarFunction)) - .build(); - - oneVersionOutputArtifact = - OneVersionCheckActionBuilder.newBuilder() - .withEnforcementLevel(oneVersionEnforcementLevel) - .useToolchain(JavaToolchainProvider.from(ruleContext)) - .checkJars(transitiveDependencies) - .build(ruleContext); - } - - Artifact proguardMapping = ruleContext.getPrerequisiteArtifact("proguard_apply_mapping"); - - Artifact manifestValidation = null; - boolean shouldValidateMinSdk = getMinSdkVersion(ruleContext) > 0; - if (ruleContext.isAttrDefined("$validate_manifest", LABEL) && shouldValidateMinSdk) { - manifestValidation = - ruleContext.getPackageRelativeArtifact( - ruleContext.getLabel().getName() + "_manifest_validation_output", - ruleContext.getBinOrGenfilesDirectory()); - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .setExecutable(ruleContext.getExecutablePrerequisite("$validate_manifest")) - .setProgressMessage("Validating %{input}") - .setMnemonic("ValidateManifest") - .addInput(manifest.getManifest()) - .addOutput(manifestValidation) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath("--manifest", manifest.getManifest()) - .addExecPath("--output", manifestValidation) - .add( - "--expected_min_sdk_version", - Integer.toString(getMinSdkVersion(ruleContext))) - .build()) - .build(ruleContext)); - } - - AndroidBinaryNativeLibsInfo nativeLibsInfo = - ruleContext.getPrerequisite("application_resources", AndroidBinaryNativeLibsInfo.PROVIDER); - - NativeLibs nativeLibs; - if (nativeLibsInfo != null && nativeLibsInfo.getNativeLibs() != null) { - nativeLibs = nativeLibsInfo.getNativeLibs(); - } else { - nativeLibs = - NativeLibs.fromLinkedNativeDeps( - ruleContext, - ImmutableList.of("deps"), - androidSemantics.getNativeDepsFileName(), - cppSemantics); - } - - final NestedSet nativeLibsAar; - if (nativeLibsInfo != null && nativeLibsInfo.getTransitiveNativeLibs() != null) { - nativeLibsAar = nativeLibsInfo.getTransitiveNativeLibs(); - } else { - nativeLibsAar = getTransitiveNativeLibs(ruleContext); - } - - return createAndroidBinary( - ruleContext, - dataContext, - filesBuilder, - deployJar, - derivedJarFunction, - isBinaryJarFiltered, - androidCommon, - javaSemantics, - androidSemantics, - nativeLibs, - resourceApk, - resourceClasses, - ImmutableList.of(), - ImmutableList.of(), - proguardMapping, - oneVersionOutputArtifact, - manifestValidation, - nativeLibsAar); - } - - public static RuleConfiguredTargetBuilder createAndroidBinary( - RuleContext ruleContext, - AndroidDataContext dataContext, - NestedSetBuilder filesBuilder, - Artifact binaryJar, - Function derivedJarFunction, - boolean isBinaryJarFiltered, - AndroidCommon androidCommon, - JavaSemantics javaSemantics, - AndroidSemantics androidSemantics, - NativeLibs nativeLibs, - ResourceApk resourceApk, - JavaTargetAttributes resourceClasses, - ImmutableList apksUnderTest, - ImmutableList additionalMergedManifests, - Artifact proguardMapping, - @Nullable Artifact oneVersionEnforcementArtifact, - @Nullable Artifact manifestValidation, - NestedSet nativeLibsAar) - throws InterruptedException, RuleErrorException { - - AndroidOptimizationInfo optimizationInfo = - ruleContext.getPrerequisite("application_resources", AndroidOptimizationInfo.PROVIDER); - AndroidDexInfo androidDexInfo = - ruleContext.getPrerequisite("application_resources", AndroidDexInfo.PROVIDER); - String baselineProfileDir = ruleContext.getLabel().getName() + "-baseline-profile/"; - ProguardOutput proguardOutput = null; - Artifact postProcessingOutputMap = null; - Artifact finalProguardOutputMap = null; - Artifact startupProfile = null; - Artifact baselineProfile = null; - - List proguardDeps = new ArrayList<>(); - Iterables.addAll( - proguardDeps, ruleContext.getPrerequisites("deps", ProguardSpecProvider.PROVIDER)); - Iterables.addAll( - proguardDeps, - ruleContext.getPrerequisites("application_resources", ProguardSpecProvider.PROVIDER)); - if (ruleContext.getConfiguration().isCodeCoverageEnabled() - && ruleContext.attributes().has("$jacoco_runtime", BuildType.LABEL)) { - proguardDeps.add( - ruleContext.getPrerequisite("$jacoco_runtime", ProguardSpecProvider.PROVIDER)); - } - ImmutableList proguardSpecs = - getProguardSpecs( - dataContext, - androidSemantics, - resourceApk.getResourceProguardConfig(), - resourceApk.getManifest(), - ruleContext.attributes().has(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST) - ? ruleContext.getPrerequisiteArtifacts(ProguardHelper.PROGUARD_SPECS).list() - : ImmutableList.of(), - proguardDeps); - boolean hasProguardSpecs = !proguardSpecs.isEmpty(); - - // TODO(bazel-team): Verify that proguard spec files don't contain -printmapping directions - // which this -printmapping command line flag will override. - Artifact proguardOutputMap = null; - boolean generateProguardMap = - ProguardHelper.genProguardMapping(ruleContext.attributes()) - || dataContext.isResourceShrinkingEnabled(); - boolean postprocessingRewritesMap = androidSemantics.postprocessClassesRewritesMap(ruleContext); - boolean desugarJava8LibsGeneratesMap = - AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs(); - boolean optimizingDexing = ruleContext.getExecutablePrerequisite(":optimizing_dexer") != null; - - BaselineProfileProvider baselineprofileProvider = - ruleContext.getPrerequisite("application_resources", BaselineProfileProvider.PROVIDER); - if (baselineprofileProvider == null - && Allowlist.hasAllowlist(ruleContext, "allow_baseline_profiles_optimizer_integration") - && Allowlist.isAvailable(ruleContext, "allow_baseline_profiles_optimizer_integration")) { - baselineProfile = - androidSemantics.mergeBaselineProfiles( - ruleContext, - baselineProfileDir, - // Include startup profiles if the optimizer is disabled since profiles won't be - // merged in the optimizer. - proguardSpecs.isEmpty()); - if (!proguardSpecs.isEmpty()) { - // This is only needed for optimized builds since otherwise the dexer doesn't process this. - startupProfile = androidSemantics.mergeStartupProfiles(ruleContext, baselineProfileDir); - // Wildcards only need to be expanded for optimized builds since if these aren't consumed by - // the optimizer, they can just be expanded during profile compilation instead. - // Start-up profiles are not expanded because it shouldn't be necessary as these should - // contain profiles generated by devices on start-up. - baselineProfile = - androidSemantics.expandBaselineProfileWildcards( - ruleContext, binaryJar, baselineProfile, baselineProfileDir); - } - } - - if (optimizationInfo == null) { - if (generateProguardMap) { - // Determine the output of the Proguard map from shrinking the app. This depends on the - // additional steps which can process the map before the final Proguard map artifact is - // generated. - if (!hasProguardSpecs && !postprocessingRewritesMap) { - // When no shrinking happens a generating rule for the output map artifact is still - // needed. - proguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext); - } else if (optimizingDexing) { - proguardOutputMap = ProguardHelper.getProguardTempArtifact(ruleContext, "pre_dexing.map"); - } else if (postprocessingRewritesMap) { - // Proguard map from shrinking goes to postprocessing. - proguardOutputMap = - ProguardHelper.getProguardTempArtifact(ruleContext, "proguard_output_for_rex.map"); - } else if (desugarJava8LibsGeneratesMap) { - // Proguard map from shrinking will be merged with desugared library proguard map. - proguardOutputMap = - getDxArtifact(ruleContext, "_proguard_output_for_desugared_library.map"); - } else { - // Proguard map from shrinking is the final output. - proguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext); - } - } - - proguardOutput = - applyProguard( - ruleContext, - androidCommon, - androidSemantics, - javaSemantics, - binaryJar, - proguardSpecs, - proguardMapping, - proguardOutputMap, - startupProfile, - baselineProfile, - baselineProfileDir); - - // Determine the outputs for the proguard map transition through post-processing and adding of - // desugared library map. - if (proguardOutput.hasMapping()) { - // Determine the Proguard map artifacts for the additional steps (if any) if shrinking of - // the app is enabled. - if ((optimizingDexing || postprocessingRewritesMap) && desugarJava8LibsGeneratesMap) { - // Proguard map from preprocessing will be merged with Proguard map for desugared - // library. - postProcessingOutputMap = - getDxArtifact(ruleContext, "_proguard_output_for_desugared_library.map"); - finalProguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext); - } else if (optimizingDexing || postprocessingRewritesMap) { - // No desugared library, Proguard map from preprocessing is the final Proguard map. - postProcessingOutputMap = androidSemantics.getProguardOutputMap(ruleContext); - finalProguardOutputMap = postProcessingOutputMap; - } else if (desugarJava8LibsGeneratesMap) { - // No postprocessing, Proguard map from merging with the desugared library map is the - // final Proguard map. - postProcessingOutputMap = proguardOutputMap; - finalProguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext); - } else { - // No postprocessing, no desugared library, the final Proguard map is the Proguard map - // from shrinking - postProcessingOutputMap = proguardOutputMap; - finalProguardOutputMap = proguardOutputMap; - } - } - - if (dataContext.useResourceShrinking(hasProguardSpecs)) { - resourceApk = - shrinkResources( - ruleContext, - androidSemantics.makeContextForNative(ruleContext), - resourceApk, - proguardOutput, - filesBuilder); - } - - resourceApk = maybeOptimizeResources(dataContext, resourceApk, hasProguardSpecs); - } else { - proguardOutput = - new ProguardOutput( - optimizationInfo.getOptimizedJar(), - optimizationInfo.getMapping(), - optimizationInfo.getProtoMapping(), - optimizationInfo.getSeeds(), - optimizationInfo.getUsage(), - /* constantStringObfuscatedMapping= */ null, - optimizationInfo.getLibraryJar(), - optimizationInfo.getConfig(), - optimizationInfo.getRewrittenStartupProfile(), - optimizationInfo.getRewrittenMergedBaselineProfile()); - if (optimizationInfo.getOptimizedResourceApk() != null) { - resourceApk = resourceApk.withApk(optimizationInfo.getOptimizedResourceApk()); - } else if (optimizationInfo.getShrunkResourceApk() != null) { - resourceApk = resourceApk.withApk(optimizationInfo.getShrunkResourceApk()); - } - symlinkOptimizationOutputs( - ruleContext, - androidSemantics, - dataContext, - filesBuilder, - hasProguardSpecs, - proguardOutput, - androidDexInfo.getFinalProguardOutputMap(), - optimizationInfo.getOptimizedResourceApk(), - optimizationInfo.getShrunkResourceApk(), - optimizationInfo.getShrunkResourceZip(), - optimizationInfo.getResourceShrinkerLog(), - optimizationInfo.getResourceOptimizationConfig(), - optimizationInfo.getResourcePathShorteningMap()); - } - - Artifact jarToDex = proguardOutput.getOutputJar(); - DexingOutput dexingOutput = null; - DexPostprocessingOutput dexPostprocessingOutput = null; - ImmutableList finalShardDexZips = null; - Java8LegacyDexOutput java8LegacyDexOutput = null; - // Compute the final DEX files by appending Java 8 legacy .dex if used. - final Artifact finalClassesDex; - - if (androidDexInfo != null) { - finalClassesDex = androidDexInfo.getFinalClassesDexZip(); - finalShardDexZips = ImmutableList.of(); - if (androidDexInfo.getShuffledJavaResourceJar() != null) { - // Symlink to the java resource jar created by this android_binary's android_binary_internal - // target to satisfy its implicit output of android_binary. - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - androidDexInfo.getShuffledJavaResourceJar(), // target - ruleContext.getImplicitOutputArtifact( - AndroidRuleClasses.JAVA_RESOURCES_JAR), // symlink - "Symlinking Android shuffled java resources jar")); - } - if (androidDexInfo.getRexOutputPackageMap() != null) { - // Symlink to the Android rex output package map created by this android_binary's - // android_binary_internal - // target to satisfy its implicit output of android_binary. - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - androidDexInfo.getRexOutputPackageMap(), // target - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.REX_OUTPUT_PACKAGE_MAP), - "Symlinking Android rex output package map")); - } - } else { - dexingOutput = - dex( - ruleContext, - androidSemantics, - binaryJar, - jarToDex, - isBinaryJarFiltered, - androidCommon, - resourceApk.getMainDexProguardConfig(), - resourceClasses, - derivedJarFunction, - proguardOutputMap, - postProcessingOutputMap, - proguardOutput.getLibraryJar(), - proguardOutput.getStartupProfileRewritten(), - !proguardSpecs.isEmpty()); - - dexPostprocessingOutput = - androidSemantics.postprocessClassesDexZip( - ruleContext, - filesBuilder, - dexingOutput.classesDexZip, - proguardOutput, - postProcessingOutputMap, - dexingOutput.mainDexList); - - finalShardDexZips = dexingOutput.shardDexZips; - if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs() - && dexPostprocessingOutput.classesDexZip().getFilename().endsWith(".zip")) { - if (binaryJar.equals(jarToDex)) { - // No shrinking: use canned Java 8 legacy .dex file - java8LegacyDexOutput = Java8LegacyDexOutput.getCanned(ruleContext); - } else { - // Shrinking is used: build custom Java 8 legacy .dex file - java8LegacyDexOutput = buildJava8LegacyDex(ruleContext, jarToDex); - - // Merge the mapping files from shrinking the program and Java 8 legacy .dex file. - if (finalProguardOutputMap != null) { - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite("$merge_proguard_maps")) - .addInput(dexPostprocessingOutput.proguardMap()) - .addInput(java8LegacyDexOutput.getMap()) - .addOutput(finalProguardOutputMap) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath("--pg-map", dexPostprocessingOutput.proguardMap()) - .addExecPath("--pg-map", java8LegacyDexOutput.getMap()) - .addExecPath("--pg-map-output", finalProguardOutputMap) - .build()) - .setMnemonic("MergeProguardMaps") - .setProgressMessage( - "Merging app and desugared library Proguard maps for %{label}") - .build(ruleContext)); - } - } - - // Append legacy .dex library to app's .dex files - finalClassesDex = getDxArtifact(ruleContext, "_final_classes.dex.zip"); - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setMnemonic("AppendJava8LegacyDex") - .setProgressMessage("Adding Java 8 legacy library for %{label}") - .setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips")) - .addInput(dexPostprocessingOutput.classesDexZip()) - .addInput(java8LegacyDexOutput.getDex()) - .addOutput(finalClassesDex) - // Order matters here: we want java8LegacyDex to be the highest-numbered - // classesN.dex - .addCommandLine( - CustomCommandLine.builder() - .addExecPath("--input_zip", dexPostprocessingOutput.classesDexZip()) - .addExecPath("--input_zip", java8LegacyDexOutput.getDex()) - .addExecPath("--output_zip", finalClassesDex) - .build()) - .build(ruleContext)); - finalShardDexZips = - ImmutableList.builder() - .addAll(finalShardDexZips) - .add(java8LegacyDexOutput.getDex()) - .build(); - - } else { - finalClassesDex = dexPostprocessingOutput.classesDexZip(); - } - } - - if (hasProguardSpecs && optimizationInfo == null) { - proguardOutput.addAllToSet(filesBuilder, finalProguardOutputMap); - } - - Artifact artProfileZip = null; - if (baselineprofileProvider != null) { - // This happens when baseline profiles are provided via starlark. - artProfileZip = baselineprofileProvider.getArtProfileZip(); - } else if (baselineProfile == null && startupProfile == null) { - // This happens when optimizer profile rewriting isn't enabled. - artProfileZip = - androidSemantics.getArtProfileForApk( - ruleContext, finalClassesDex, finalProguardOutputMap, baselineProfileDir); - } else { - // This happens when optimizer profile rewriting is enabled. - artProfileZip = - androidSemantics.compileBaselineProfile( - ruleContext, - finalClassesDex, - // Minified symbols are emitted when rewriting, so only use map for symbols which - // weren't passed to bytecode optimizer (if it exists). - java8LegacyDexOutput == null ? null : java8LegacyDexOutput.getMap(), - // At this point, either baseline profile here also contains startup-profiles, if any. - proguardOutput.getMergedBaselineProfileRewritten() == null - ? baselineProfile - : proguardOutput.getMergedBaselineProfileRewritten(), - baselineProfileDir); - } - - Artifact unsignedApk = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_UNSIGNED_APK); - Artifact zipAlignedApk = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_APK); - Artifact v4Signature = - (dataContext.getAndroidConfig().apkSigningMethodV4() != null - && dataContext.getAndroidConfig().apkSigningMethodV4()) - ? ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_V4_SIGNATURE) - : null; - ImmutableList signingKeys = AndroidCommon.getApkDebugSigningKeys(ruleContext); - Artifact signingLineage = ruleContext.getPrerequisiteArtifact("debug_signing_lineage_file"); - String keyRotationMinSdk = ruleContext.attributes().get("key_rotation_min_sdk", Type.STRING); - FilesToRunProvider resourceExtractor = - ruleContext.getExecutablePrerequisite("$resource_extractor"); - - ApkActionsBuilder actionsBuilder = - ApkActionsBuilder.create("apk") - .setClassesDex(finalClassesDex) - .addInputZip(resourceApk.getArtifact()) - .setJavaResourceZip( - androidDexInfo == null - ? dexingOutput.javaResourceJar - : androidDexInfo.getJavaResourceJar(), - resourceExtractor) - .addInputZips(nativeLibsAar.toList()) - .setNativeLibs(nativeLibs) - .setUnsignedApk(unsignedApk) - .setSignedApk(zipAlignedApk) - .setSigningKeys(signingKeys) - .setSigningLineageFile(signingLineage) - .setSigningKeyRotationMinSdk(keyRotationMinSdk) - .setV4Signature(v4Signature) - .setZipalignApk(true) - .setDeterministicSigning(androidSemantics.deterministicSigning()); - - if (artProfileZip != null) { - actionsBuilder.addInputZip(artProfileZip); - } - actionsBuilder.registerActions(ruleContext); - - filesBuilder.add(binaryJar); - filesBuilder.add(unsignedApk); - filesBuilder.add(zipAlignedApk); - if (v4Signature != null) { - filesBuilder.add(v4Signature); - } - NestedSet filesToBuild = filesBuilder.build(); - - Artifact deployInfo = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.DEPLOY_INFO); - ImmutableList.Builder listBuilder = - ImmutableList.builder().add(zipAlignedApk).addAll(apksUnderTest); - if (v4Signature != null) { - listBuilder.add(v4Signature); - } - AndroidDeployInfoAction.createDeployInfoAction( - ruleContext, - deployInfo, - resourceApk.getManifest(), - additionalMergedManifests, - listBuilder.build()); - - RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext); - - // If this is an instrumentation APK, create the provider for android_instrumentation_test. - if (isInstrumentation(ruleContext)) { - ApkInfo targetApkProvider = ruleContext.getPrerequisite("instruments", ApkInfo.PROVIDER); - - AndroidInstrumentationInfo instrumentationProvider = - new AndroidInstrumentationInfo(targetApkProvider); - - builder.addNativeDeclaredProvider(instrumentationProvider); - - // At this point, the Android manifests of both target and instrumentation APKs are finalized. - FilesToRunProvider checker = - ruleContext.getExecutablePrerequisite("$instrumentation_test_check"); - Artifact targetManifest = targetApkProvider.getMergedManifest(); - Artifact instrumentationManifest = resourceApk.getManifest(); - Artifact checkOutput = - ruleContext.getImplicitOutputArtifact( - AndroidRuleClasses.INSTRUMENTATION_TEST_CHECK_RESULTS); - - SpawnAction.Builder checkAction = - createSpawnActionBuilder(ruleContext) - .setExecutable(checker) - .addInput(targetManifest) - .addInput(instrumentationManifest) - .addOutput(checkOutput) - .setProgressMessage( - "Validating the merged manifests of the target and instrumentation APKs") - .setMnemonic("AndroidManifestInstrumentationCheck"); - - CustomCommandLine commandLine = - CustomCommandLine.builder() - .addExecPath("--instrumentation_manifest", instrumentationManifest) - .addExecPath("--target_manifest", targetManifest) - .addExecPath("--output", checkOutput) - .build(); - - builder.addOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL, checkOutput); - checkAction.addCommandLine(commandLine); - ruleContext.registerAction(checkAction.build(ruleContext)); - } - - OutputGroupInfo androidApplicationOutputGroupInfo = - ruleContext.getPrerequisite("application_resources", OutputGroupInfo.STARLARK_CONSTRUCTOR); - if (androidApplicationOutputGroupInfo != null) { - for (String key : androidApplicationOutputGroupInfo.getFieldNames()) { - builder.addOutputGroup(key, androidApplicationOutputGroupInfo.getOutputGroup(key)); - } - } - - androidCommon.addTransitiveInfoProviders( - builder, - /* aar= */ null, - resourceApk, - zipAlignedApk, - apksUnderTest, - nativeLibs, - androidCommon.isNeverLink(), - /* isLibrary = */ false); - - ProguardMappingProvider proguardMappingProvider = - ruleContext.getPrerequisite("application_resources", ProguardMappingProvider.PROVIDER); - - if (proguardMappingProvider != null) { - builder.addNativeDeclaredProvider(proguardMappingProvider); - } else if (dexPostprocessingOutput != null && dexPostprocessingOutput.proguardMap() != null) { - builder.addNativeDeclaredProvider( - new ProguardMappingProvider(dexPostprocessingOutput.proguardMap())); - } - - if (oneVersionEnforcementArtifact != null) { - builder.addOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL, oneVersionEnforcementArtifact); - } - - if (manifestValidation != null) { - builder.addOutputGroup( - OutputGroupInfo.VALIDATION, NestedSetBuilder.create(STABLE_ORDER, manifestValidation)); - } - - // First propagate validations from most rule attributes as usual; then handle "deps" separately - // to propagate validations from each config split but avoid known-redundant Android Lint - // validations (b/168038145, b/180746622). - // TODO(b/180746622): remove custom filtering once semantically identical actions with - // different configurations are deduped (while still propagating actions from all splits) - RuleConfiguredTargetBuilder.collectTransitiveValidationOutputGroups( - ruleContext, - attr -> !"deps".equals(attr), - validations -> builder.addOutputGroup(OutputGroupInfo.VALIDATION_TRANSITIVE, validations)); - boolean filterSplitValidations = false; // propagate validations from first split unfiltered - for (List deps : - ruleContext.getRulePrerequisitesCollection().getSplitPrerequisites("deps").values()) { - for (OutputGroupInfo provider : - AnalysisUtils.getProviders( - getConfiguredTargets(deps), OutputGroupInfo.STARLARK_CONSTRUCTOR)) { - NestedSet validations = provider.getOutputGroup(OutputGroupInfo.VALIDATION); - if (filterSplitValidations) { - // Filter out Android Lint validations by name: we know these validations are expensive - // and duplicative between splits, so arbitrarily only propagate them from the first split - // (b/180746622). While it's cheesy to rely on naming patterns, more semantic filtering - // requires a lot of work (e.g., using an aspect that observes actions by mnemonic). - NestedSetBuilder filtered = NestedSetBuilder.stableOrder(); - validations.toList().stream() - .filter(Artifact::hasKnownGeneratingAction) - .filter(a -> !a.getFilename().endsWith("android_lint_output.xml")) - .forEach(filtered::add); - validations = filtered.build(); - } - if (!validations.isEmpty()) { - builder.addOutputGroup(OutputGroupInfo.VALIDATION_TRANSITIVE, validations); - } - } - // Filter out Android Lint Validations from any subsequent split, - // because they're redundant with those in the first split. - filterSplitValidations = true; - } - - AndroidPreDexJarProvider androidPreDexJarProvider = - ruleContext.getPrerequisite("application_resources", AndroidPreDexJarProvider.PROVIDER); - - if (androidPreDexJarProvider != null) { - builder.addNativeDeclaredProvider(androidPreDexJarProvider); - } else { - builder.addNativeDeclaredProvider(new AndroidPreDexJarProvider(jarToDex)); - } - - return builder - .setFilesToBuild(filesToBuild) - .addProvider( - RunfilesProvider.class, - RunfilesProvider.simple( - new Runfiles.Builder( - ruleContext.getWorkspaceName(), - ruleContext.getConfiguration().legacyExternalRunfiles()) - .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES) - .addTransitiveArtifacts(filesToBuild) - .build())) - .addNativeDeclaredProvider( - new ApkInfo( - zipAlignedApk, - unsignedApk, - binaryJar, - getCoverageInstrumentationJarForApk(ruleContext), - resourceApk.getManifest(), - signingKeys, - signingLineage, - keyRotationMinSdk)) - .addNativeDeclaredProvider( - AndroidFeatureFlagSetProvider.create( - AndroidFeatureFlagSetProvider.getAndValidateFlagMapFromRuleContext(ruleContext))) - .addOutputGroup("android_deploy_info", deployInfo) - .addOutputGroup("android_deploy_info", resourceApk.getManifest()); - } - - public static NestedSet getTransitiveNativeLibs(RuleContext ruleContext) { - // Collect all native shared libraries across split transitions. Some AARs contain shared - // libraries across multiple architectures, e.g. x86 and armeabi-v7a, and need to be packed - // into the APK. - NestedSetBuilder transitiveNativeLibs = NestedSetBuilder.naiveLinkOrder(); - for (List deps : - ruleContext.getRulePrerequisitesCollection().getSplitPrerequisites("deps").values()) { - for (AndroidNativeLibsInfo provider : - AnalysisUtils.getProviders(getConfiguredTargets(deps), AndroidNativeLibsInfo.PROVIDER)) { - transitiveNativeLibs.addTransitive(provider.getNativeLibs()); - } - } - return transitiveNativeLibs.build(); - } - - private static ImmutableList getConfiguredTargets( - List prerequisitesList) { - return prerequisitesList.stream() - .map(ConfiguredTargetAndData::getConfiguredTarget) - .collect(toImmutableList()); - } - - static class Java8LegacyDexOutput { - private final Artifact dex; - private final Artifact map; - - private Java8LegacyDexOutput(Artifact dex, Artifact map) { - this.dex = dex; - this.map = map; - } - - static Java8LegacyDexOutput getCanned(RuleContext ruleContext) { - return new Java8LegacyDexOutput( - ruleContext.getPrerequisiteArtifact("$java8_legacy_dex"), null); - } - - boolean isEmpty() { - return dex == null; - } - - public Artifact getDex() { - return dex; - } - - public Artifact getMap() { - return map; - } - } - - private static void symlinkOptimizationOutputs( - RuleContext ruleContext, - AndroidSemantics androidSemantics, - AndroidDataContext dataContext, - NestedSetBuilder filesBuilder, - boolean hasProguardSpecs, - ProguardOutput proguardOutput, - @Nullable Artifact finalProguardOutputMap, - @Nullable Artifact optimizedResourceApk, - @Nullable Artifact shrunkResourceApk, - @Nullable Artifact shrunkResourceZip, - @Nullable Artifact resourceShrinkerLog, - @Nullable Artifact resourceOptimizationConfig, - @Nullable Artifact resourcePathShorteningMap) - throws InterruptedException { - - if (proguardOutput.getOutputJar() != null) { - Artifact proguardedJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_JAR); - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - proguardOutput.getOutputJar(), - proguardedJar, - "Symlinking proguard output jar")); - - if (hasProguardSpecs) { - filesBuilder.add(proguardedJar); - } - } - - if (proguardOutput.getSeeds() != null) { - Artifact proguardSeeds = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_SEEDS); - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - proguardOutput.getSeeds(), - proguardSeeds, - "Symlinking proguard seeds")); - - if (hasProguardSpecs) { - filesBuilder.add(proguardSeeds); - } - } - - if (proguardOutput.getConfig() != null) { - Artifact proguardConfig = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_CONFIG); - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - proguardOutput.getConfig(), - proguardConfig, - "Symlinking proguard config")); - - if (hasProguardSpecs) { - filesBuilder.add(proguardConfig); - } - } - - if (proguardOutput.getUsage() != null) { - Artifact proguardUsage = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_USAGE); - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - proguardOutput.getUsage(), - proguardUsage, - "Symlinking proguard usage")); - - if (hasProguardSpecs) { - filesBuilder.add(proguardUsage); - } - } - - if (proguardOutput.getProtoMapping() != null - && androidSemantics.getProtoMapping(ruleContext) != null) { - Artifact proguardProtoMapping = androidSemantics.getProtoMapping(ruleContext); - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - proguardOutput.getProtoMapping(), - proguardProtoMapping, - "Symlinking proguard proto mapping")); - - if (hasProguardSpecs) { - filesBuilder.add(proguardProtoMapping); - } - } - - // Conditionally select which output map to symlink. In the case where a select() resolves to - // an empty list we should pull the fail action artifact from the proguard processor. Otherwise - // we should prefer the final output map from dexing. - Artifact outputMap = null; - if (finalProguardOutputMap != null) { - outputMap = finalProguardOutputMap; - } else if (proguardOutput.getMapping() != null) { - outputMap = proguardOutput.getMapping(); - } - if (outputMap != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - outputMap, - androidSemantics.getProguardOutputMap(ruleContext), - "Symlinking final proguard output map")); - - if (hasProguardSpecs) { - filesBuilder.add(androidSemantics.getProguardOutputMap(ruleContext)); - } - } - - if (optimizedResourceApk != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - optimizedResourceApk, - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_OPTIMIZED_APK), - "Symlinking optimized resource apk")); - } - - if (shrunkResourceApk != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - shrunkResourceApk, - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_APK), - "Symlinking shrunk resource apk")); - } - - if (shrunkResourceZip != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - shrunkResourceZip, - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_ZIP), - "Symlinking shrunk resource zip")); - } - - if (resourceShrinkerLog != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - resourceShrinkerLog, - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG), - "Symlinking resource shrinker log")); - filesBuilder.add( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG)); - } - - if (resourceOptimizationConfig != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - resourceOptimizationConfig, - dataContext.createOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_OPTIMIZATION_CONFIG), - "Symlinking resource optimization config")); - } - - if (resourcePathShorteningMap != null) { - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - resourcePathShorteningMap, - dataContext.createOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_PATH_SHORTENING_MAP), - "Symlinking resource path shortening map")); - } - } - - static Java8LegacyDexOutput buildJava8LegacyDex(RuleContext ruleContext, Artifact jarToDex) - throws RuleErrorException { - Artifact java8LegacyDexRules = getDxArtifact(ruleContext, "_java8_legacy.dex.pgcfg"); - Artifact java8LegacyDex = getDxArtifact(ruleContext, "_java8_legacy.dex.zip"); - Artifact java8LegacyDexMap = getDxArtifact(ruleContext, "_java8_legacy.dex.map"); - Artifact androidJar = AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar(); - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .setExecutable(ruleContext.getExecutablePrerequisite("$build_java8_legacy_dex")) - .addInput(jarToDex) - .addInput(androidJar) - .addOutput(java8LegacyDexRules) - .addOutput(java8LegacyDex) - .addOutput(java8LegacyDexMap) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath("--rules", java8LegacyDexRules) - .addExecPath("--binary", jarToDex) - .addExecPath("--android_jar", androidJar) - .addExecPath("--output", java8LegacyDex) - .addExecPath("--output_map", java8LegacyDexMap) - .build()) - .setMnemonic("BuildLegacyDex") - .setProgressMessage("Building Java 8 legacy library for %{label}") - .build(ruleContext)); - return new Java8LegacyDexOutput(java8LegacyDex, java8LegacyDexMap); - } - /** - * For coverage builds, this returns a Jar containing uninstrumented bytecode for the - * coverage reporter's consumption. This method simply returns the deploy Jar. Note the deploy Jar - * is built anyway for Android binaries. - * - * @return A Jar containing uninstrumented bytecode or {@code null} for non-coverage builds - */ - @Nullable - private static Artifact getCoverageInstrumentationJarForApk(RuleContext ruleContext) - throws InterruptedException { - return ruleContext.getConfiguration().isCodeCoverageEnabled() - ? ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR) - : null; - } - - public static NestedSet getLibraryResourceJars(RuleContext ruleContext) { - Iterable libraryResourceJarProviders = - AndroidCommon.getTransitivePrerequisites( - ruleContext, AndroidLibraryResourceClassJarProvider.PROVIDER); - - NestedSetBuilder libraryResourceJarsBuilder = NestedSetBuilder.naiveLinkOrder(); - for (AndroidLibraryResourceClassJarProvider provider : libraryResourceJarProviders) { - libraryResourceJarsBuilder.addTransitive(provider.getResourceClassJars()); - } - return libraryResourceJarsBuilder.build(); - } - - /** - * Generates an uncompressed _deploy.jar of all the runtime jars, or creates a link to the deploy - * jar created by this android_binary's android_binary_internal target if it is provided. - */ - public static Artifact createDeployJar( - RuleContext ruleContext, - JavaSemantics javaSemantics, - AndroidCommon common, - JavaTargetAttributes attributes, - boolean checkDesugarDeps, - Function derivedJarFunction) - throws InterruptedException, RuleErrorException { - - Artifact deployJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR); - - AndroidDexInfo androidDexInfo = - ruleContext.getPrerequisite("application_resources", AndroidDexInfo.PROVIDER); - - if (androidDexInfo != null && androidDexInfo.getDeployJar() != null) { - // Symlink to the deploy jar created by this android_binary's android_binary_internal target - // to satisfy the deploy jar implicit output of android_binary. - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - androidDexInfo.getDeployJar(), // target - deployJar, // symlink - "Symlinking Android deploy jar")); - } else { - new DeployArchiveBuilder(javaSemantics, ruleContext) - .setOutputJar(deployJar) - .setAttributes(attributes) - .addRuntimeJars(common.getRuntimeJars()) - .setDerivedJarFunction(derivedJarFunction) - .setCheckDesugarDeps(checkDesugarDeps) - .build(); - } - - return deployJar; - } - - /** - * Applies the proguard specifications, and creates a ProguardedJar. Proguard's output artifacts - * are added to the given {@code filesBuilder}. - */ - private static ProguardOutput applyProguard( - RuleContext ruleContext, - AndroidCommon common, - AndroidSemantics androidSemantics, - JavaSemantics javaSemantics, - Artifact deployJarArtifact, - ImmutableList proguardSpecs, - Artifact proguardMapping, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact startupProfile, - @Nullable Artifact baselineProfile, - String baselineProfileDir) - throws InterruptedException, RuleErrorException { - Artifact proguardOutputJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_JAR); - - // Proguard will be only used for binaries which specify a proguard_spec - if (proguardSpecs.isEmpty()) { - // Although normally the Proguard jar artifact is not needed for binaries which do not specify - // proguard_specs, targets which use a select to provide an empty list to proguard_specs will - // still have a Proguard jar implicit output, as it is impossible to tell what a select will - // produce at the time of implicit output determination. As a result, this artifact must - // always be created. - return createEmptyProguardAction( - ruleContext, androidSemantics, proguardOutputJar, deployJarArtifact, proguardOutputMap); - } - - AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); - NestedSetBuilder libraryJars = - NestedSetBuilder.naiveLinkOrder().add(sdk.getAndroidJar()); - if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()) { - // Proguard sees the desugared app, so it needs legacy APIs to resolve symbols - libraryJars.addTransitive( - ruleContext - .getPrerequisite("$desugared_java8_legacy_apis") - .getProvider(FileProvider.class) - .getFilesToBuild()); - } - libraryJars.addTransitive(common.getTransitiveNeverLinkLibraries()); - - Artifact proguardSeeds = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_SEEDS); - Artifact proguardUsage = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_USAGE); - Artifact proguardDictionary = ruleContext.getPrerequisiteArtifact("proguard_apply_dictionary"); - return ProguardHelper.createOptimizationActions( - ruleContext, - sdk.getProguard(), - deployJarArtifact, - proguardSpecs, - proguardSeeds, - proguardUsage, - proguardMapping, - proguardDictionary, - libraryJars.build(), - proguardOutputJar, - androidSemantics, - javaSemantics, - getProguardOptimizationPasses(ruleContext), - proguardOutputMap, - startupProfile, - baselineProfile, - baselineProfileDir); - } - - @Nullable - private static Integer getProguardOptimizationPasses(RuleContext ruleContext) { - if (ruleContext.attributes().has("proguard_optimization_passes", Type.INTEGER)) { - StarlarkInt i = ruleContext.attributes().get("proguard_optimization_passes", Type.INTEGER); - if (i != null) { - return i.toIntUnchecked(); - } - } - return null; - } - - private static ProguardOutput createEmptyProguardAction( - RuleContext ruleContext, - AndroidSemantics androidSemantics, - Artifact proguardOutputJar, - Artifact deployJarArtifact, - Artifact proguardOutputMap) - throws InterruptedException { - NestedSetBuilder failures = NestedSetBuilder.stableOrder(); - ProguardOutput outputs = - ProguardHelper.getProguardOutputs( - proguardOutputJar, - /* proguardSeeds= */ null, - /* proguardUsage= */ null, - ruleContext, - androidSemantics, - proguardOutputMap, - /* libraryJar= */ null, - /* startupProfileRewritten= */ null, - /* mergedBaselineProfileRewritten= */ null); - outputs.addAllToSet(failures); - ruleContext.registerAction( - new FailAction( - ruleContext.getActionOwner(), - failures.build().toSet(), - "Can't run Proguard without proguard_specs", - Code.PROGUARD_SPECS_MISSING)); - return ProguardOutput.createEmpty(deployJarArtifact); - } - - static ImmutableList getProguardSpecs( - AndroidDataContext dataContext, - AndroidSemantics androidSemantics, - Artifact resourceProguardConfig, - Artifact mergedManifest, - ImmutableList localProguardSpecs, - Iterable proguardDeps) { - - ImmutableList proguardSpecs = - ProguardHelper.collectTransitiveProguardSpecs( - dataContext.getLabel(), - dataContext.getActionConstructionContext(), - ImmutableList.of(resourceProguardConfig), - localProguardSpecs, - proguardDeps); - - boolean assumeMinSdkVersion = dataContext.getAndroidConfig().assumeMinSdkVersion(); - if (!proguardSpecs.isEmpty() && assumeMinSdkVersion) { - // NB: Order here is important. We're including generated Proguard specs before the user's - // specs so that they can override values. - proguardSpecs = - ImmutableList.builder() - .addAll(androidSemantics.getProguardSpecsForManifest(dataContext, mergedManifest)) - .addAll(proguardSpecs) - .build(); - } - - return proguardSpecs; - } - - private static ResourceApk shrinkResources( - RuleContext ruleContext, - AndroidDataContext dataContext, - ResourceApk resourceApk, - ProguardOutput proguardOutput, - NestedSetBuilder filesBuilder) - throws RuleErrorException, InterruptedException { - - Artifact shrunkApk = - shrinkResources( - dataContext, - resourceApk.getRTxt(), - resourceApk.getResourcesZip(), - proguardOutput.getOutputJar(), - proguardOutput.getMapping(), - ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext), - ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions")); - - filesBuilder.add( - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG)); - return resourceApk.withApk(shrunkApk); - } - - static Artifact shrinkResources( - AndroidDataContext dataContext, - ValidatedAndroidResources validatedResources, - Artifact proguardOutputJar, - Artifact proguardMapping, - ResourceFilterFactory resourceFilterFactory, - List noCompressExtensions) - throws InterruptedException { - return shrinkResources( - dataContext, - Preconditions.checkNotNull(validatedResources).getRTxt(), - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP), - proguardOutputJar, - proguardMapping, - resourceFilterFactory, - noCompressExtensions); - } - - private static Artifact shrinkResources( - AndroidDataContext dataContext, - Artifact rTxt, - Artifact resourcesZip, - Artifact proguardOutputJar, - Artifact proguardMapping, - ResourceFilterFactory resourceFilterFactory, - List noCompressExtensions) - throws InterruptedException { - - ResourceShrinkerActionBuilder resourceShrinkerActionBuilder = - new ResourceShrinkerActionBuilder() - .setResourceApkOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_APK)) - .setShrunkResourcesOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_ZIP)) - .setLogOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG)) - .withResourceFiles(resourcesZip) - .withShrunkJar(proguardOutputJar) - .withProguardMapping(proguardMapping) - .withRTxt(rTxt) - .setResourceFilterFactory(resourceFilterFactory) - .setUncompressedExtensions(noCompressExtensions) - .setResourceOptimizationConfigOut( - dataContext.createOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_OPTIMIZATION_CONFIG)); - return resourceShrinkerActionBuilder.build(dataContext); - } - - private static ResourceApk maybeOptimizeResources( - AndroidDataContext dataContext, ResourceApk resourceApk, boolean hasProguardSpecs) - throws InterruptedException { - boolean useResourcePathShortening = dataContext.useResourcePathShortening(); - boolean useResourceNameObfuscation = dataContext.useResourceNameObfuscation(hasProguardSpecs); - if (!useResourcePathShortening && !useResourceNameObfuscation) { - return resourceApk; - } - - Artifact optimizedApk = - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_OPTIMIZED_APK); - - Aapt2OptimizeActionBuilder.Builder builder = - Aapt2OptimizeActionBuilder.builder() - .setResourceApk(resourceApk.getArtifact()) - .setOptimizedApkOut(optimizedApk); - if (useResourcePathShortening) { - builder.setResourcePathShorteningMapOut( - dataContext.createOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_PATH_SHORTENING_MAP)); - } - if (useResourceNameObfuscation) { - builder.setResourceOptimizationConfig( - dataContext.createOutputArtifact( - AndroidRuleClasses.ANDROID_RESOURCE_OPTIMIZATION_CONFIG)); - } - builder.build().registerAction(dataContext); - - return resourceApk.withApk(optimizedApk); - } - - @Immutable - static final class DexingOutput { - private final Artifact classesDexZip; - final Artifact javaResourceJar; - final ImmutableList shardDexZips; - // This is not technically and output of dexing, but the processed main dex list that was used - // in dexing. - final Artifact mainDexList; - - private DexingOutput( - Artifact classesDexZip, - Artifact javaResourceJar, - ImmutableList shardDexZips, - Artifact mainDexList) { - this.classesDexZip = classesDexZip; - this.javaResourceJar = javaResourceJar; - this.shardDexZips = Preconditions.checkNotNull(shardDexZips); - this.mainDexList = mainDexList; - } - } - - /** All artifacts modified by any dex post-processing steps. */ - @AutoValue - public abstract static class DexPostprocessingOutput { - - public static DexPostprocessingOutput create(Artifact classesDexZip, Artifact proguardMap) { - return new AutoValue_AndroidBinary_DexPostprocessingOutput(classesDexZip, proguardMap); - } - - /** A .zip of .dex files to include in the APK. */ - abstract Artifact classesDexZip(); - - /** - * The proguard mapping corresponding to the post-processed dex files. This may be null if - * proguard was not run. - */ - @Nullable - abstract Artifact proguardMap(); - } - - /** Creates one or more classes.dex files that correspond to {@code proguardedJar}. */ - private static DexingOutput dex( - RuleContext ruleContext, - AndroidSemantics androidSemantics, - Artifact binaryJar, - Artifact proguardedJar, - boolean isBinaryJarFiltered, - AndroidCommon common, - @Nullable Artifact mainDexProguardSpec, - JavaTargetAttributes attributes, - Function derivedJarFunction, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact postProcessingOutputMap, - @Nullable Artifact libraryJar, - @Nullable Artifact startupProfile, - boolean isOptimizedBuild) - throws InterruptedException, RuleErrorException { - FilesToRunProvider optimizingDexer = ruleContext.getExecutablePrerequisite(":optimizing_dexer"); - List dexopts = ruleContext.getExpander().withDataLocations().tokenized("dexopts"); - MultidexMode multidexMode = getMultidexMode(ruleContext); - if (!supportsMultidexMode(ruleContext, multidexMode)) { - ruleContext.throwWithRuleError( - "Multidex mode \"" - + multidexMode.getAttributeValue() - + "\" not supported by this version of the Android SDK"); - } - - int minSdkVersion = getMinSdkVersion(ruleContext); - - int dexShards = ruleContext.attributes().get("dex_shards", Type.INTEGER).toIntUnchecked(); - if (dexShards > 1) { - if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) { - ruleContext.throwWithRuleError(".dex sharding is not available in manual multidex mode"); - } - } - - Artifact mainDexList = ruleContext.getPrerequisiteArtifact("main_dex_list"); - if ((mainDexList != null && multidexMode != MultidexMode.MANUAL_MAIN_DEX) - || (mainDexList == null && multidexMode == MultidexMode.MANUAL_MAIN_DEX)) { - ruleContext.throwWithRuleError( - "Both \"main_dex_list\" and \"multidex='manual_main_dex'\" must be specified."); - } - - boolean usesDexArchives = - getEffectiveIncrementalDexing( - ruleContext, dexopts, !Objects.equals(binaryJar, proguardedJar)); - Artifact inclusionFilterJar = - isBinaryJarFiltered && Objects.equals(binaryJar, proguardedJar) ? binaryJar : null; - Artifact singleJarToDex = !Objects.equals(binaryJar, proguardedJar) ? proguardedJar : null; - Artifact javaResourceSourceJar = - AndroidCommon.getAndroidConfig(ruleContext).getJavaResourcesFromOptimizedJar() - ? proguardedJar - : binaryJar; - - // Multidex mode: generate classes.dex.zip, where the zip contains [classes.dex, - // classes2.dex, ... classesN.dex]. - - if (multidexMode == MultidexMode.LEGACY) { - // For legacy multidex, we need to generate a list for the dexer's --main-dex-list flag. - mainDexList = - createMainDexListAction( - ruleContext, androidSemantics, proguardedJar, mainDexProguardSpec, proguardOutputMap); - } else if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) { - mainDexList = - transformDexListThroughProguardMapAction(ruleContext, proguardOutputMap, mainDexList); - } - - Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip"); - if (dexShards > 1) { - ImmutableList shards = - makeShardArtifacts(ruleContext, dexShards, usesDexArchives ? ".jar.dex.zip" : ".jar"); - - Artifact javaResourceJar = - createShuffleJarActions( - ruleContext, - usesDexArchives, - singleJarToDex, - shards, - common, - inclusionFilterJar, - dexopts, - minSdkVersion, - androidSemantics, - attributes, - derivedJarFunction, - mainDexList); - - ImmutableList.Builder shardDexesBuilder = ImmutableList.builder(); - for (int i = 1; i <= dexShards; i++) { - Artifact shard = shards.get(i - 1); - Artifact shardDex = getDxArtifact(ruleContext, "shard" + i + ".dex.zip"); - shardDexesBuilder.add(shardDex); - if (usesDexArchives) { - // If there's a main dex list then the first shard contains exactly those files. - // To work with devices that lack native multi-dex support we need to make sure that - // the main dex list becomes one dex file if at all possible. - // Note shard here (mostly) contains of .class.dex files from shuffled dex archives, - // instead of being a conventional Jar file with .class files. - createDexMergerAction( - ruleContext, - mainDexList != null && i == 1 ? "minimal" : "best_effort", - ImmutableList.of(shard), - shardDex, - /*mainDexList=*/ null, - dexopts); - } else { - AndroidCommon.createDexAction( - ruleContext, shard, shardDex, dexopts, minSdkVersion, /*mainDexList=*/ null); - } - } - ImmutableList shardDexes = shardDexesBuilder.build(); - - CommandLine mergeCommandLine = - CustomCommandLine.builder() - .addExecPaths(VectorArg.addBefore("--input_zip").each(shardDexes)) - .addExecPath("--output_zip", classesDex) - .build(); - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setMnemonic("MergeDexZips") - .setProgressMessage("Merging dex shards for %s", ruleContext.getLabel()) - .setExecutable(ruleContext.getExecutablePrerequisite("$merge_dexzips")) - .addInputs(shardDexes) - .addOutput(classesDex) - .addCommandLine(mergeCommandLine) - .build(ruleContext)); - if (usesDexArchives) { - // Using the deploy jar for java resources gives better "bazel mobile-install" performance - // with incremental dexing b/c bazel can create the "incremental" and "split resource" - // APKs earlier (b/c these APKs don't depend on code being dexed here). This is also done - // for other multidex modes. - javaResourceJar = javaResourceSourceJar; - } - return new DexingOutput(classesDex, javaResourceJar, shardDexes, mainDexList); - } else { - if (usesDexArchives) { - boolean optimizeDex = optimizingDexer != null && isOptimizedBuild; - createIncrementalDexingActions( - ruleContext, - singleJarToDex, - common, - inclusionFilterJar, - dexopts, - minSdkVersion, - androidSemantics, - attributes, - derivedJarFunction, - mainDexList, - classesDex, - proguardOutputMap, - postProcessingOutputMap, - libraryJar, - startupProfile, - optimizeDex); - } else { - // Because the dexer also places resources into this zip, we also need to create a cleanup - // action that removes all non-.dex files before staging for apk building. - // Create an artifact for the intermediate zip output that includes non-.dex files. - Artifact classesDexIntermediate = - AndroidBinary.getDxArtifact(ruleContext, "intermediate_classes.dex.zip"); - // Have the dexer generate the intermediate file and the "cleaner" action consume this to - // generate the final archive with only .dex files. - AndroidCommon.createDexAction( - ruleContext, - proguardedJar, - classesDexIntermediate, - dexopts, - minSdkVersion, - mainDexList); - createCleanDexZipAction(ruleContext, classesDexIntermediate, classesDex); - } - return new DexingOutput( - classesDex, javaResourceSourceJar, ImmutableList.of(classesDex), mainDexList); - } - } - - /** Helper that sets up dexbuilder/dexmerger actions when dex_shards attribute is not set. */ - private static void createIncrementalDexingActions( - RuleContext ruleContext, - @Nullable Artifact proguardedJar, - AndroidCommon common, - @Nullable Artifact inclusionFilterJar, - List dexopts, - int minSdkVersion, - AndroidSemantics androidSemantics, - JavaTargetAttributes attributes, - Function derivedJarFunction, - @Nullable Artifact mainDexList, - Artifact classesDex, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact postProcessingOutputMap, - @Nullable Artifact libraryJar, - @Nullable Artifact startupProfile, - boolean optimizeDex) - throws InterruptedException, RuleErrorException { - ImmutableList dexArchives; - if (proguardedJar == null - && AndroidCommon.getAndroidConfig(ruleContext).incrementalDexingUseDexSharder()) { - dexArchives = - toDexedClasspath( - ruleContext, - collectRuntimeJars(common, attributes), - collectDexArchives( - ruleContext, - common, - dexopts, - minSdkVersion, - androidSemantics, - derivedJarFunction)); - } else { - if (proguardedJar != null - && AndroidCommon.getAndroidConfig(ruleContext).incrementalDexingShardsAfterProguard() - > 1) { - String suffix = optimizeDex ? ".zip" : ".jar.dex.zip"; - // TODO(b/69816569): Also use this logic if #shards > #Jars on runtime classpath - dexArchives = - makeShardArtifacts( - ruleContext, - AndroidCommon.getAndroidConfig(ruleContext).incrementalDexingShardsAfterProguard(), - suffix); - } else { - dexArchives = ImmutableList.of(AndroidBinary.getDxArtifact(ruleContext, "classes.jar")); - } - - if (proguardedJar != null && dexArchives.size() == 1) { - // No need to shuffle, just run proguarded Jar through dexbuilder - DexArchiveAspect.createDexArchiveAction( - ruleContext, - "$dexbuilder_after_proguard", - proguardedJar, - DexArchiveAspect.topLevelDexbuilderDexopts(dexopts), - minSdkVersion, - dexArchives.get(0)); - } else { - createShuffleJarActions( - ruleContext, - /*makeDexArchives=*/ true, - proguardedJar, - dexArchives, - common, - inclusionFilterJar, - dexopts, - minSdkVersion, - androidSemantics, - attributes, - derivedJarFunction, - null); - inclusionFilterJar = null; - } - } - - if (dexArchives.size() == 1) { - checkState(inclusionFilterJar == null); - createDexMergerAction(ruleContext, "minimal", dexArchives, classesDex, mainDexList, dexopts); - } else if (optimizeDex) { - createOptimizedDexMergerAction( - ruleContext, - dexArchives, - classesDex, - mainDexList, - dexopts, - proguardOutputMap, - postProcessingOutputMap, - libraryJar, - startupProfile); - } else { - SpecialArtifact shardsToMerge = - createSharderAction(ruleContext, dexArchives, mainDexList, dexopts, inclusionFilterJar); - SpecialArtifact multidexShards = - ruleContext.getTreeArtifact( - ruleContext.getUniqueDirectory("dexfiles"), ruleContext.getBinOrGenfilesDirectory()); - FilesToRunProvider dexMerger = ruleContext.getExecutablePrerequisite("$dexmerger"); - createTemplatedMergerActions( - ruleContext, - multidexShards, - shardsToMerge, - dexopts, - dexMerger, - minSdkVersion, - null /* desugarGlobals */); - // TODO(b/69431301): avoid this action and give the files to apk build action directly - createZipMergeAction(ruleContext, multidexShards, classesDex); - } - } - - private static ImmutableList makeShardArtifacts( - RuleContext ruleContext, int shardCount, String suffix) { - ImmutableList.Builder shardsBuilder = ImmutableList.builder(); - for (int i = 1; i <= shardCount; i++) { - shardsBuilder.add(getDxArtifact(ruleContext, "shard" + i + suffix)); - } - return shardsBuilder.build(); - } - - /** - * Returns whether incremental dexing should actually be used based on the --incremental_dexing - * flag, the incremental_dexing attribute and the target's dexopts. - */ - private static boolean getEffectiveIncrementalDexing( - RuleContext ruleContext, List dexopts, boolean isBinaryProguarded) { - TriState override = ruleContext.attributes().get("incremental_dexing", BuildType.TRISTATE); - AndroidConfiguration config = AndroidCommon.getAndroidConfig(ruleContext); - // Ignore --incremental_dexing if the incremental_dexing attribute is set, but require the - // attribute to be YES for proguarded binaries and binaries with forbidden dexopts. - if (isBinaryProguarded - && override == TriState.YES - && config.incrementalDexingShardsAfterProguard() <= 0) { - ruleContext.attributeError( - "incremental_dexing", "target cannot be incrementally dexed because it uses Proguard"); - return false; - } - - if (override == TriState.NO) { - return false; - } - if (override == TriState.YES || config.useIncrementalDexing()) { - if (isBinaryProguarded) { - return override == TriState.YES || config.incrementalDexingAfterProguardByDefault(); - } - Iterable forbiddenDexopts = DexArchiveAspect.forbiddenDexopts(ruleContext, dexopts); - if (Iterables.isEmpty(forbiddenDexopts)) { - // target's dexopts are all compatible with incremental dexing. - return true; - } else if (override == TriState.YES) { - // target's dexopts include forbidden flags with --non_incremental_per_target_dexopts. If - // incremental_dexing attribute is explicitly set for this target then we'll warn and - // incrementally dex anyway. Otherwise, just don't incrementally dex. - Iterable ignored = - Iterables.filter( - forbiddenDexopts, - Predicates.not(Predicates.in(config.getDexoptsSupportedInIncrementalDexing()))); - ruleContext.attributeWarning( - "incremental_dexing", - String.format( - "Using incremental dexing even though dexopts %s indicate this target " - + "may be unsuitable for incremental dexing for the moment.%s", - forbiddenDexopts, - Iterables.isEmpty(ignored) ? "" : " Ignored dexopts: " + ignored)); - return true; - } else { - // If there are incompatible dexopts and the attribute is not set, we silently don't run - // incremental dexing. - return false; - } - } else { - // attribute is auto and flag is false - return false; - } - } - - /** - * Sets up a {@code $dexsharder} action for the given {@code dexArchives} and returns the output - * tree artifact. - * - * @return Tree artifact containing dex archives to merge into exactly one .dex file each - */ - private static SpecialArtifact createSharderAction( - RuleContext ruleContext, - ImmutableList dexArchives, - @Nullable Artifact mainDexList, - Collection dexopts, - @Nullable Artifact inclusionFilterJar) { - SpecialArtifact outputTree = - ruleContext.getTreeArtifact( - ruleContext.getUniqueDirectory("dexsplits"), ruleContext.getBinOrGenfilesDirectory()); - - SpawnAction.Builder shardAction = - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setMnemonic("ShardForMultidex") - .setProgressMessage( - "Assembling dex files for %s", ruleContext.getLabel().getCanonicalForm()) - .setExecutable(ruleContext.getExecutablePrerequisite("$dexsharder")) - .addInputs(dexArchives) - .addOutput(outputTree); - - CustomCommandLine.Builder shardCommandLine = - CustomCommandLine.builder() - .addExecPaths(VectorArg.addBefore("--input").each(dexArchives)) - .addExecPath("--output", outputTree); - - if (mainDexList != null) { - shardAction.addInput(mainDexList); - shardCommandLine.addExecPath("--main-dex-list", mainDexList); - } - shardCommandLine.addAll(DexArchiveAspect.sharderDexopts(ruleContext, dexopts)); - if (inclusionFilterJar != null) { - shardCommandLine.addExecPath("--inclusion_filter_jar", inclusionFilterJar); - shardAction.addInput(inclusionFilterJar); - } - ruleContext.registerAction( - shardAction - .addCommandLine( - shardCommandLine.build(), - // Classpaths can be long--overflow into @params file if necessary - ParamFileInfo.builder(ParameterFile.ParameterFileType.SHELL_QUOTED).build()) - .build(ruleContext)); - - return outputTree; - } - - /** - * Sets up a monodex {@code $dexmerger} actions for each dex archive in the given tree artifact - * and puts the outputs in a tree artifact. - */ - private static void createTemplatedMergerActions( - RuleContext ruleContext, - SpecialArtifact outputTree, - SpecialArtifact inputTree, - List dexopts, - FilesToRunProvider executable, - int minSdkVersion, - Object desugarGlobals) { - SpawnActionTemplate.Builder dexmerger = - new SpawnActionTemplate.Builder(inputTree, outputTree) - .setExecutable(executable) - .setMnemonics("DexShardsToMerge", "DexMerger") - .setOutputPathMapper( - (OutputPathMapper & Serializable) TreeFileArtifact::getParentRelativePath); - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .addPlaceholderTreeArtifactExecPath("--input", inputTree) - .addPlaceholderTreeArtifactExecPath("--output", outputTree) - .add("--multidex=given_shard") - .addAll( - DexArchiveAspect.mergerDexopts( - ruleContext, - Iterables.filter( - dexopts, Predicates.not(Predicates.equalTo(DX_MINIMAL_MAIN_DEX_OPTION))))); - if (minSdkVersion > 0) { - commandLine.add("--min_sdk_version", Integer.toString(minSdkVersion)); - } - Artifact desugarGlobalsArtifact = - AndroidStarlarkData.fromNoneable(desugarGlobals, Artifact.class); - if (desugarGlobalsArtifact != null) { - dexmerger.addCommonInputs(ImmutableList.of(desugarGlobalsArtifact)); - commandLine.addPath("--global_synthetics_path", desugarGlobalsArtifact.getExecPath()); - } - dexmerger.setCommandLineTemplate(commandLine.build()); - ruleContext.registerAction(dexmerger.build(ruleContext.getActionOwner())); - } - - private static void createZipMergeAction( - RuleContext ruleContext, Artifact inputTree, Artifact outputZip) throws RuleErrorException { - CustomCommandLine args = - CustomCommandLine.builder() - .add("--normalize") - .add("--exclude_build_data") - .add("--dont_change_compression") - .add("--sources") - .addExpandedTreeArtifactExecPaths(inputTree) - .addExecPath("--output", outputZip) - .add("--no_duplicates") // safety: expect distinct entry names in all inputs - .build(); - - ParamFileInfo paramFileInfo = - ParamFileInfo.builder(ParameterFile.ParameterFileType.SHELL_QUOTED) - .setFlagFormatString("@%s") - .setUseAlways(true) - .build(); - - ruleContext.registerAction( - singleJarSpawnActionBuilder(ruleContext) - .setMnemonic("MergeDexZips") - .setProgressMessage("Merging dex shards for %s", ruleContext.getLabel()) - .addInput(inputTree) - .addOutput(outputZip) - .addCommandLine(args, paramFileInfo) - .build(ruleContext)); - } - - private static void createDexMergerAction( - RuleContext ruleContext, - String multidexStrategy, - ImmutableList dexArchives, - Artifact classesDex, - @Nullable Artifact mainDexList, - Collection dexopts) { - SpawnAction.Builder dexmerger = - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite("$dexmerger")) - .setMnemonic("DexMerger") - .setProgressMessage("Assembling dex files into %s", classesDex.getRootRelativePath()) - .addInputs(dexArchives) - .addOutput(classesDex); - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .addExecPaths(VectorArg.addBefore("--input").each(dexArchives)) - .addExecPath("--output", classesDex) - .addAll(DexArchiveAspect.mergerDexopts(ruleContext, dexopts)) - .addPrefixed("--multidex=", multidexStrategy); - if (mainDexList != null) { - dexmerger.addInput(mainDexList); - commandLine.addExecPath("--main-dex-list", mainDexList); - } - dexmerger.addCommandLine( - commandLine.build(), - // Classpaths can be long--overflow into @params file if necessary - ParamFileInfo.builder(ParameterFile.ParameterFileType.SHELL_QUOTED).build()); - ruleContext.registerAction(dexmerger.build(ruleContext)); - } - - private static void createOptimizedDexMergerAction( - RuleContext ruleContext, - ImmutableList dexArchives, - Artifact classesDex, - @Nullable Artifact mainDexList, - Collection dexopts, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact postProcessingOutputMap, - @Nullable Artifact libraryJar, - @Nullable Artifact startupProfile) { - // Use a param file to pass through all flags with paths that might get large. We need - // to use our own param file here (rather than the built-in param file handling) as D8 - // does not understand the blaze format. - Artifact paramFile = - ruleContext.getDerivedArtifact( - ParameterFile.derivePath( - classesDex.getOutputDirRelativePath( - ruleContext.getConfiguration().isSiblingRepositoryLayout())), - classesDex.getRoot()); - CustomCommandLine.Builder paramFileCommand = - CustomCommandLine.builder().addExecPaths(dexArchives).addExecPath("--output", classesDex); - NestedSetBuilder paramFileInputs = NestedSetBuilder.stableOrder(); - paramFileInputs.addAll(dexArchives); - SpawnAction.Builder dexAction = - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite(":optimizing_dexer")) - .setMnemonic("OptimizingDex") - .setProgressMessage("Optimized dexing for %{label}") - .addInput(paramFile) - .addInputs(dexArchives) - .addOutput(classesDex); - if (libraryJar != null) { - paramFileCommand.addExecPath("--lib", libraryJar); - dexAction.addInput(libraryJar); - } - if (proguardOutputMap != null) { - dexAction.addInput(proguardOutputMap); - paramFileCommand.addExecPath("--pg-map", proguardOutputMap); - } - if (postProcessingOutputMap != null) { - dexAction.addOutput(postProcessingOutputMap); - paramFileCommand.addExecPath("--pg-map-output", postProcessingOutputMap); - } - boolean nativeMultidex = getMultidexMode(ruleContext) == MultidexMode.NATIVE; - if (startupProfile != null && nativeMultidex) { - dexAction.addInput(startupProfile); - paramFileCommand.addExecPath("--startup-profile", startupProfile); - } - // TODO(b/261110876): Pass min SDK through here based on the value in the merged manifest. - // The current value is statically defined for the entire depot. - // We currently set the minimum SDK version to 21 if you are doing native multidex as that - // is required for native multidex to work in the first place and as a result is required - // for correct behavior from the dexer. - int minSdkVersion = getMinSdkVersion(ruleContext); - int sdk = nativeMultidex ? Math.max(21, minSdkVersion) : minSdkVersion; - if (sdk != 0) { - paramFileCommand.add("--min-api", Integer.toString(sdk)); - } - if (mainDexList != null) { - paramFileCommand.addExecPath("--main-dex-list", mainDexList); - dexAction.addInput(mainDexList); - } - ruleContext.registerAction( - new ParameterFileWriteAction( - ruleContext.getActionOwner(), - paramFileInputs.build(), - paramFile, - paramFileCommand.build(), - ParameterFile.ParameterFileType.SHELL_QUOTED)); - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .add("--release") - .add("--no-desugaring") - .addPrefixedExecPath("@", paramFile) - .addAll(DexArchiveAspect.mergerDexopts(ruleContext, dexopts)); - dexAction.addCommandLine(commandLine.build()); - ruleContext.registerAction(dexAction.build(ruleContext)); - } - - /** - * Returns a {@link DexArchiveProvider} of all transitively generated dex archives as well as dex - * archives for the Jars produced by the binary target itself. - */ - public static Function collectDesugaredJars( - RuleContext ruleContext, - AndroidCommon common, - AndroidSemantics semantics, - JavaTargetAttributes attributes) - throws RuleErrorException { - if (!AndroidCommon.getAndroidConfig(ruleContext).desugarJava8()) { - return Functions.identity(); - } - if (Allowlist.hasAllowlist(ruleContext, "enable_starlark_dex_desugar_proguard") - && Allowlist.isAvailable(ruleContext, "enable_starlark_dex_desugar_proguard")) { - return Functions.identity(); - } - AndroidRuntimeJarProvider.Builder result = - collectDesugaredJarsFromAttributes( - ruleContext, semantics.getAttributesWithJavaRuntimeDeps(ruleContext)); - for (Artifact jar : common.getJarsProducedForRuntime().toList()) { - // Create dex archives next to all Jars produced by AndroidCommon for this rule. We need to - // do this (instead of placing dex archives into the _dx subdirectory like DexArchiveAspect) - // because for "legacy" ResourceApks, AndroidCommon produces Jars per resource dependency that - // can theoretically have duplicate basenames, so they go into special directories, and we - // piggyback on that naming scheme here by placing dex archives into the same directories. - PathFragment jarPath = - jar.getOutputDirRelativePath(ruleContext.getConfiguration().isSiblingRepositoryLayout()); - Artifact desugared = - DexArchiveAspect.desugar( - ruleContext, - jar, - attributes.getBootClassPath().bootclasspath(), - attributes.getCompileTimeClassPath(), - getMinSdkVersion(ruleContext), - ruleContext.getDerivedArtifact( - jarPath.replaceName(jarPath.getBaseName() + "_desugared.jar"), jar.getRoot())); - result.addDesugaredJar(jar, desugared); - } - return result.build().collapseToFunction(); - } - - static AndroidRuntimeJarProvider.Builder collectDesugaredJarsFromAttributes( - RuleContext ruleContext, ImmutableList attributes) { - AndroidRuntimeJarProvider.Builder result = new AndroidRuntimeJarProvider.Builder(); - for (String attr : attributes) { - // Use all available AndroidRuntimeJarProvider from attributes that carry runtime dependencies - result.addTransitiveProviders( - ruleContext.getPrerequisites(attr, AndroidRuntimeJarProvider.class)); - } - return result; - } - - /** - * Returns a {@link Map} of all transitively generated dex archives as well as dex archives for - * the Jars produced by the binary target itself. - */ - private static Map collectDexArchives( - RuleContext ruleContext, - AndroidCommon common, - List dexopts, - int minSdkVersion, - AndroidSemantics semantics, - Function derivedJarFunction) { - DexArchiveProvider.Builder result = new DexArchiveProvider.Builder(); - for (String attr : semantics.getAttributesWithJavaRuntimeDeps(ruleContext)) { - // Use all available DexArchiveProviders from attributes that carry runtime dependencies - result.addTransitiveProviders(ruleContext.getPrerequisites(attr, DexArchiveProvider.class)); - } - ImmutableSet incrementalDexopts = - DexArchiveAspect.incrementalDexopts(ruleContext, dexopts); - for (Artifact jar : common.getJarsProducedForRuntime().toList()) { - // Create dex archives next to all Jars produced by AndroidCommon for this rule. We need to - // do this (instead of placing dex archives into the _dx subdirectory like DexArchiveAspect) - // because for "legacy" ResourceApks, AndroidCommon produces Jars per resource dependency that - // can theoretically have duplicate basenames, so they go into special directories, and we - // piggyback on that naming scheme here by placing dex archives into the same directories. - PathFragment jarPath = - jar.getOutputDirRelativePath(ruleContext.getConfiguration().isSiblingRepositoryLayout()); - Artifact dexArchive = - DexArchiveAspect.createDexArchiveAction( - ruleContext, - "$dexbuilder", - derivedJarFunction.apply(jar), - incrementalDexopts, - minSdkVersion, - ruleContext.getDerivedArtifact( - jarPath.replaceName(jarPath.getBaseName() + ".dex.zip"), jar.getRoot())); - result.addDexArchive(incrementalDexopts, dexArchive, jar); - } - return result.build().archivesForDexopts(incrementalDexopts); - } - - private static Artifact createShuffleJarActions( - RuleContext ruleContext, - boolean makeDexArchives, - @Nullable Artifact proguardedJar, - ImmutableList shards, - AndroidCommon common, - @Nullable Artifact inclusionFilterJar, - List dexopts, - int minSdkVersion, - AndroidSemantics semantics, - JavaTargetAttributes attributes, - Function derivedJarFunction, - @Nullable Artifact mainDexList) - throws InterruptedException, RuleErrorException { - checkArgument(!shards.isEmpty()); - checkArgument(mainDexList == null || shards.size() > 1); - checkArgument(proguardedJar == null || inclusionFilterJar == null); - - FilesToRunProvider optimizingDexer = ruleContext.getExecutablePrerequisite(":optimizing_dexer"); - boolean optimizeDex = optimizingDexer != null && proguardedJar != null; - Artifact javaResourceJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.JAVA_RESOURCES_JAR); - ImmutableList shuffleOutputs; - if (makeDexArchives && proguardedJar != null) { - checkArgument(shards.size() > 1); - // Split proguardedJar into N shards and run dexbuilder over each one below - shuffleOutputs = makeShardArtifacts(ruleContext, shards.size(), ".jar"); - } else { - shuffleOutputs = shards; - } - - SpawnAction.Builder shardAction = - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .setMnemonic("ShardClassesToDex") - .setProgressMessage("Sharding classes for dexing for %s", ruleContext.getLabel()) - .setExecutable(ruleContext.getExecutablePrerequisite("$shuffle_jars")) - .addOutputs(shuffleOutputs) - .addOutput(javaResourceJar); - - CustomCommandLine.Builder shardCommandLine = - CustomCommandLine.builder() - .addExecPaths(VectorArg.addBefore("--output_jar").each(shuffleOutputs)) - .addExecPath("--output_resources", javaResourceJar); - - if (mainDexList != null) { - shardCommandLine.addExecPath("--main_dex_filter", mainDexList); - shardAction.addInput(mainDexList); - } - - // If we need to run Proguard, all the class files will be in the Proguarded jar, which has to - // be converted to dex. Otherwise we can use the transitive classpath directly and can leverage - // incremental dexing outputs for classpath Jars if applicable. - if (proguardedJar != null) { - shardCommandLine.addExecPath("--input_jar", proguardedJar); - shardAction.addInput(proguardedJar); - } else { - ImmutableList classpath = collectRuntimeJars(common, attributes); - // Check whether we can use dex archives. Besides the --incremental_dexing flag, also - // make sure the "dexopts" attribute on this target doesn't mention any problematic flags. - if (makeDexArchives) { - // Use dex archives instead of their corresponding Jars wherever we can. At this point - // there should be very few or no Jar files that still end up in shards. The dexing - // step below will have to deal with those in addition to merging .dex files together. - Map dexArchives = - collectDexArchives( - ruleContext, common, dexopts, minSdkVersion, semantics, derivedJarFunction); - classpath = toDexedClasspath(ruleContext, classpath, dexArchives); - shardCommandLine.add("--split_dexed_classes"); - } else { - classpath = classpath.stream().map(derivedJarFunction).collect(toImmutableList()); - } - shardCommandLine.addExecPaths(VectorArg.addBefore("--input_jar").each(classpath)); - shardAction.addInputs(classpath); - - if (inclusionFilterJar != null) { - shardCommandLine.addExecPath("--inclusion_filter_jar", inclusionFilterJar); - shardAction.addInput(inclusionFilterJar); - } - } - - shardAction.addCommandLine( - shardCommandLine.build(), ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED).build()); - ruleContext.registerAction(shardAction.build(ruleContext)); - - if (makeDexArchives && proguardedJar != null) { - for (int i = 0; i < shards.size(); ++i) { - checkState(!shuffleOutputs.get(i).equals(shards.get(i))); - if (optimizeDex) { - DexArchiveAspect.createShardedOptimizedDexArchiveAction( - ruleContext, - shuffleOutputs.get(i), - DexArchiveAspect.topLevelDexbuilderDexopts(dexopts), - minSdkVersion, - shards.get(i)); - } else { - DexArchiveAspect.createDexArchiveAction( - ruleContext, - "$dexbuilder_after_proguard", - shuffleOutputs.get(i), - DexArchiveAspect.topLevelDexbuilderDexopts(dexopts), - minSdkVersion, - shards.get(i)); - } - } - } - return javaResourceJar; - } - - private static ImmutableList collectRuntimeJars( - AndroidCommon common, JavaTargetAttributes attributes) { - return ImmutableList.builder() - .addAll(common.getRuntimeJars()) - .addAll(attributes.getRuntimeClassPathForArchive().toList()) - .build(); - } - - private static ImmutableList toDexedClasspath( - RuleContext ruleContext, - ImmutableList classpath, - Map dexArchives) - throws RuleErrorException { - // This is a simple Iterables.transform but with useful error message in case of missed Jars. - ImmutableList.Builder dexedClasspath = ImmutableList.builder(); - for (Artifact jar : classpath) { - Artifact dexArchive = dexArchives.get(jar); - if (dexArchive == null) { - // Users can create this situation by directly depending on a .jar artifact (checked in - // or coming from a genrule or similar, b/11285003). This will also catch new implicit - // dependencies that incremental dexing would need to be extended to (b/34949364). - // Typically the fix for the latter involves propagating DexArchiveAspect along the - // attribute defining the new implicit dependency. - ruleContext.throwWithAttributeError( - "deps", - "Dependencies on .jar artifacts are not " - + "allowed in Android binaries, please use a java_import to depend on " - + jar.prettyPrint() - + ". If this is an implicit dependency then the rule that " - + "introduces it will need to be fixed to account for it correctly."); - } - dexedClasspath.add(dexArchive); - } - return dexedClasspath.build(); - } - - /** Adds execution info by propagating tags from the target */ - private static SpawnAction.Builder createSpawnActionBuilder(RuleContext ruleContext) { - return new SpawnAction.Builder() - .setExecutionInfo( - TargetUtils.getExecutionInfo( - ruleContext.getRule(), ruleContext.isAllowTagsPropagation())); - } - - private static SpawnAction.Builder singleJarSpawnActionBuilder(RuleContext ruleContext) - throws RuleErrorException { - FilesToRunProvider singleJar = JavaToolchainProvider.from(ruleContext).getSingleJar(); - SpawnAction.Builder builder = - createSpawnActionBuilder(ruleContext).useDefaultShellEnvironment(); - builder.setExecutable(singleJar); - return builder; - } - - /** - * Creates an action that copies a .zip file to a specified path, filtering all non-.dex files out - * of the output. - */ - private static void createCleanDexZipAction( - RuleContext ruleContext, Artifact inputZip, Artifact outputZip) throws RuleErrorException { - ruleContext.registerAction( - singleJarSpawnActionBuilder(ruleContext) - .setProgressMessage("Trimming %s", inputZip.getExecPath().getBaseName()) - .setMnemonic("TrimDexZip") - .addInput(inputZip) - .addOutput(outputZip) - .addCommandLine( - CustomCommandLine.builder() - .add("--exclude_build_data") - .add("--dont_change_compression") - .addExecPath("--sources", inputZip) - .addExecPath("--output", outputZip) - .add("--include_prefixes") - .add("classes") - .build()) - .build(ruleContext)); - } - - /** - * Creates an action that generates a list of classes to be passed to the dexer's --main-dex-list - * flag (which specifies the classes that need to be directly in classes.dex). Returns the file - * containing the list. - */ - private static Artifact createMainDexListAction( - RuleContext ruleContext, - AndroidSemantics androidSemantics, - Artifact jar, - @Nullable Artifact mainDexProguardSpec, - @Nullable Artifact proguardOutputMap) - throws InterruptedException, RuleErrorException { - AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); - // Create the main dex classes list. - Artifact mainDexList = AndroidBinary.getDxArtifact(ruleContext, "main_dex_list.txt"); - - List proguardSpecs = - new ArrayList<>(ruleContext.getPrerequisiteArtifacts("main_dex_proguard_specs").list()); - if (proguardSpecs.isEmpty()) { - proguardSpecs.add(sdk.getMainDexClasses()); - } - if (mainDexProguardSpec != null) { - proguardSpecs.add(mainDexProguardSpec); - } - - // Use the legacy_main_dex_list_generator provided by the --legacy_main_dex_list_generator flag - // if present. If not, fall back to the one provided by the SDK. - FilesToRunProvider legacyMainDexListGenerator = - ruleContext.getExecutablePrerequisite(":legacy_main_dex_list_generator"); - if (legacyMainDexListGenerator == null) { - legacyMainDexListGenerator = sdk.getLegacyMainDexListGenerator(); - } - // If legacy_main_dex_list_generator is not set by either the SDK or the flag, use ProGuard and - // the main dext list creator specified by the android_sdk rule. If - // legacy_main_dex_list_generator is provided, use that tool instead. - // TODO(b/147692286): Remove the old main-dex list generation that relied on ProGuard. - if (legacyMainDexListGenerator == null) { - if (sdk.getShrinkedAndroidJar() == null) { - ruleContext.throwWithRuleError( - "In \"legacy\" multidex mode, either legacy_main_dex_list_generator or " - + "shrinked_android_jar must be set in the android_sdk."); - } - // Process the input jar through Proguard into an intermediate, streamlined jar. - Artifact strippedJar = AndroidBinary.getDxArtifact(ruleContext, "main_dex_intermediate.jar"); - SpawnAction.Builder streamlinedBuilder = - createSpawnActionBuilder(ruleContext) - .useDefaultShellEnvironment() - .addOutput(strippedJar) - .setExecutable(sdk.getProguard()) - .setProgressMessage("Generating streamlined input jar for main dex classes list") - .setMnemonic("MainDexClassesIntermediate") - .addInput(jar) - .addInput(sdk.getShrinkedAndroidJar()); - CustomCommandLine.Builder streamlinedCommandLine = - CustomCommandLine.builder() - .add("-forceprocessing") - .addExecPath("-injars", jar) - .addExecPath("-libraryjars", sdk.getShrinkedAndroidJar()) - .addExecPath("-outjars", strippedJar) - .add("-dontwarn") - .add("-dontnote") - .add("-dontoptimize") - .add("-dontobfuscate"); - - for (Artifact spec : proguardSpecs) { - streamlinedBuilder.addInput(spec); - streamlinedCommandLine.addExecPath("-include", spec); - } - - androidSemantics.addMainDexListActionArguments( - ruleContext, streamlinedBuilder, streamlinedCommandLine, proguardOutputMap); - - streamlinedBuilder.addCommandLine(streamlinedCommandLine.build()); - ruleContext.registerAction(streamlinedBuilder.build(ruleContext)); - - SpawnAction.Builder builder = - createSpawnActionBuilder(ruleContext) - .setMnemonic("MainDexClasses") - .setProgressMessage("Generating main dex classes list"); - - ruleContext.registerAction( - builder - .setExecutable(sdk.getMainDexListCreator()) - .addOutput(mainDexList) - .addInput(strippedJar) - .addInput(jar) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath(mainDexList) - .addExecPath(strippedJar) - .addExecPath(jar) - .addAll( - ruleContext - .getExpander() - .withDataLocations() - .tokenized("main_dex_list_opts")) - .build()) - .build(ruleContext)); - } else { - // Use the newer legacy multidex main-dex list generation. - SpawnAction.Builder actionBuilder = - createSpawnActionBuilder(ruleContext) - .setMnemonic("MainDexClasses") - .setProgressMessage("Generating main dex classes list"); - - CustomCommandLine.Builder commandLineBuilder = - CustomCommandLine.builder() - .addExecPath("--main-dex-list-output", mainDexList) - .addExecPath("--lib", sdk.getAndroidJar()); - if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()) { - NestedSet legacyApis = - ruleContext - .getPrerequisite("$desugared_java8_legacy_apis") - .getProvider(FileProvider.class) - .getFilesToBuild(); - for (Artifact lib : legacyApis.toList()) { - actionBuilder.addInput(lib); - commandLineBuilder.addExecPath("--lib", lib); - } - } - for (Artifact spec : proguardSpecs) { - actionBuilder.addInput(spec); - commandLineBuilder.addExecPath("--main-dex-rules", spec); - } - - commandLineBuilder.addExecPath(jar); - - ruleContext.registerAction( - actionBuilder - .setExecutable(legacyMainDexListGenerator) - .addOutput(mainDexList) - .addInput(jar) - .addInput(sdk.getAndroidJar()) - .addCommandLine(commandLineBuilder.build()) - .build(ruleContext)); - } - return mainDexList; - } - - /** Transforms manual main_dex_list through proguard obfuscation map. */ - private static Artifact transformDexListThroughProguardMapAction( - RuleContext ruleContext, @Nullable Artifact proguardOutputMap, Artifact mainDexList) { - if (proguardOutputMap == null - || !ruleContext.attributes().get("proguard_generate_mapping", Type.BOOLEAN)) { - return mainDexList; - } - Artifact obfuscatedMainDexList = - AndroidBinary.getDxArtifact(ruleContext, "main_dex_list_obfuscated.txt"); - SpawnAction.Builder actionBuilder = - createSpawnActionBuilder(ruleContext) - .setMnemonic("MainDexProguardClasses") - .setProgressMessage("Obfuscating main dex classes list") - .setExecutable(ruleContext.getExecutablePrerequisite("$dex_list_obfuscator")) - .addInput(mainDexList) - .addInput(proguardOutputMap) - .addOutput(obfuscatedMainDexList) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath("--input", mainDexList) - .addExecPath("--output", obfuscatedMainDexList) - .addExecPath("--obfuscation_map", proguardOutputMap) - .build()); - ruleContext.registerAction(actionBuilder.build(ruleContext)); - return obfuscatedMainDexList; - } - - public static Artifact createMainDexProguardSpec(Label label, ActionConstructionContext context) { - return ProguardHelper.getProguardConfigArtifact(label, context, "main_dex"); - } - - /** Returns the multidex mode to apply to this target. */ - public static MultidexMode getMultidexMode(RuleContext ruleContext) { - return Preconditions.checkNotNull( - MultidexMode.fromValue(ruleContext.attributes().get("multidex", Type.STRING))); - } - - private static int getMinSdkVersion(RuleContext ruleContext) { - if (ruleContext.getRule().isAttrDefined("min_sdk_version", Type.INTEGER)) { - return ruleContext.attributes().get("min_sdk_version", Type.INTEGER).toIntUnchecked(); - } - return 0; - } - - /** - * List of Android SDKs that contain runtimes that do not support the native multidexing - * introduced in Android L. If someone tries to build an android_binary that has multidex=native - * set with an old SDK, we will exit with an error to alert the developer that their application - * might not run on devices that the used SDK still supports. - */ - private static final ImmutableSet RUNTIMES_THAT_DONT_SUPPORT_NATIVE_MULTIDEXING = - ImmutableSet.of( - "/android_sdk_linux/platforms/android_10/", "/android_sdk_linux/platforms/android_13/", - "/android_sdk_linux/platforms/android_15/", "/android_sdk_linux/platforms/android_16/", - "/android_sdk_linux/platforms/android_17/", "/android_sdk_linux/platforms/android_18/", - "/android_sdk_linux/platforms/android_19/", "/android_sdk_linux/platforms/android_20/"); - - /** - * Returns true if the runtime contained in the Android SDK used to build this rule supports the - * given version of multidex mode specified, false otherwise. - */ - private static boolean supportsMultidexMode(RuleContext ruleContext, MultidexMode mode) - throws RuleErrorException { - if (mode == MultidexMode.NATIVE) { - // Native mode is not supported by Android devices running Android before v21. - String runtime = - AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar().getExecPathString(); - for (String forbiddenRuntime : RUNTIMES_THAT_DONT_SUPPORT_NATIVE_MULTIDEXING) { - if (runtime.contains(forbiddenRuntime)) { - return false; - } - } - } - return true; - } - - /** Returns an intermediate artifact used to support dex generation. */ - static Artifact getDxArtifact(RuleContext ruleContext, String baseName) { - return ruleContext.getUniqueDirectoryArtifact( - "_dx", baseName, ruleContext.getBinOrGenfilesDirectory()); - } - - /** Returns true if this android_binary target is an instrumentation binary */ - private static boolean isInstrumentation(RuleContext ruleContext) { - return ruleContext.attributes().isAttributeValueExplicitlySpecified("instruments"); - } - - /** - * Perform class filtering using the target APK's predexed JAR. Filter duplicate .class and - * R.class files based on name. Prevents runtime crashes on ART. See b/19713845 for details. - */ - private static Artifact getFilteredDeployJar(RuleContext ruleContext, Artifact deployJar) - throws InterruptedException { - Artifact filterJar = - ruleContext - .getPrerequisite("instruments") - .get(AndroidPreDexJarProvider.PROVIDER) - .getPreDexJar(); - Artifact filteredDeployJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_TEST_FILTERED_JAR); - - AndroidDexInfo androidDexInfo = - ruleContext.getPrerequisite("application_resources", AndroidDexInfo.PROVIDER); - - if (androidDexInfo != null && androidDexInfo.getFilteredDeployJar() != null) { - // Symlink to the filtered deploy jar created by this android_binary's android_binary_internal - // target to satisfy the filtered deploy jar implicit output of android_binary. - ruleContext.registerAction( - SymlinkAction.toArtifact( - ruleContext.getActionOwner(), - androidDexInfo.getFilteredDeployJar(), // target - filteredDeployJar, // symlink - "Symlinking Android filtered deploy jar")); - } else { - AndroidCommon.createZipFilterAction( - ruleContext, - deployJar, - filterJar, - filteredDeployJar, - CheckHashMismatchMode.NONE, - ruleContext - .getFragment(AndroidConfiguration.class) - .removeRClassesFromInstrumentationTestJar()); - } - return filteredDeployJar; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java index fc8b51c1c8231a..cc9187c2b9ee04 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java @@ -22,17 +22,10 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Streams; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ResourceSet; import com.google.devtools.build.lib.analysis.AnalysisUtils; import com.google.devtools.build.lib.analysis.FileProvider; -import com.google.devtools.build.lib.analysis.OutputGroupInfo; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector.InstrumentationSpec; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; @@ -46,28 +39,15 @@ import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.android.ZipFilterBuilder.CheckHashMismatchMode; import com.google.devtools.build.lib.rules.android.databinding.DataBindingContext; -import com.google.devtools.build.lib.rules.android.databinding.DataBindingV2Provider; import com.google.devtools.build.lib.rules.cpp.CcInfo; import com.google.devtools.build.lib.rules.cpp.CcLinkingContext; import com.google.devtools.build.lib.rules.cpp.CcLinkingContext.LinkOptions; -import com.google.devtools.build.lib.rules.java.BootClassPathInfo; -import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment; import com.google.devtools.build.lib.rules.java.JavaCommon; -import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType; -import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts; -import com.google.devtools.build.lib.rules.java.JavaCompilationHelper; -import com.google.devtools.build.lib.rules.java.JavaCompileOutputs; import com.google.devtools.build.lib.rules.java.JavaInfo; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; import com.google.devtools.build.lib.rules.java.JavaUtil; -import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Collection; @@ -97,10 +77,6 @@ public class AndroidCommon { private static final ImmutableSet TRANSITIVE_ATTRIBUTES = ImmutableSet.of("application_resources", "deps", "exports"); - private static final int DEX_THREADS = 5; - private static final ResourceSet DEX_RESOURCE_SET = - ResourceSet.createWithRamCpu(/* memoryMb= */ 4096.0, /* cpu= */ DEX_THREADS); - static Iterable getTransitivePrerequisites( RuleContext ruleContext, BuiltinProvider key) { ImmutableList.Builder> builder = ImmutableList.builder(); @@ -120,22 +96,9 @@ static Iterable getTransitivePrerequisites( private final JavaCommon javaCommon; private final boolean asNeverLink; - private NestedSet filesToBuild; private NestedSet transitiveNeverlinkLibraries = NestedSetBuilder.emptySet(Order.STABLE_ORDER); - private JavaCompilationArgsProvider javaCompilationArgs = JavaCompilationArgsProvider.EMPTY; - private NestedSet jarsProducedForRuntime; private Artifact classJar; - private JavaCompileOutputs outputs; - private Artifact iJar; - private Artifact srcJar; - private Artifact resourceSourceJar; - private GeneratedExtensionRegistryProvider generatedExtensionRegistryProvider; - private final JavaSourceJarsProvider.Builder javaSourceJarsProviderBuilder = - JavaSourceJarsProvider.builder(); - private final JavaRuleOutputJarsProvider.Builder javaRuleOutputJarsProviderBuilder = - JavaRuleOutputJarsProvider.builder(); - private AndroidIdlHelper idlHelper; public AndroidCommon(JavaCommon javaCommon) { this(javaCommon, JavaCommon.isNeverLink(javaCommon.getRuleContext())); @@ -182,88 +145,6 @@ public static NestedSet collectTransitiveNeverlinkLibraries( return neverlinkedRuntimeJars.build(); } - /** - * Creates an action that converts {@code jarToDex} to a dex file. The output will be stored in - * the {@link com.google.devtools.build.lib.actions.Artifact} {@code dxJar}. - */ - public static void createDexAction( - RuleContext ruleContext, - Artifact jarToDex, - Artifact classesDex, - List dexOptions, - int minSdkVersion, - Artifact mainDexList) - throws RuleErrorException { - CustomCommandLine.Builder commandLine = CustomCommandLine.builder(); - commandLine.add("--dex"); - - commandLine.addAll(dexOptions); - if (minSdkVersion > 0) { - commandLine.add("--min_sdk_version", Integer.toString(minSdkVersion)); - } - commandLine.add("--multi-dex"); - if (mainDexList != null) { - commandLine.addPrefixedExecPath("--main-dex-list=", mainDexList); - } - commandLine.addPrefixedExecPath("--output=", classesDex); - commandLine.addExecPath(jarToDex); - - SpawnAction.Builder builder = - new SpawnAction.Builder() - .useDefaultShellEnvironment() - .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getDx()) - .addInput(jarToDex) - .addOutput(classesDex) - .setProgressMessage("Converting %s to dex format", jarToDex.getExecPathString()) - .setMnemonic("AndroidDexer") - .addCommandLine(commandLine.build()) - // TODO(ulfjack): Use 1 CPU if multidex is true? - .setResources(DEX_RESOURCE_SET); - if (mainDexList != null) { - builder.addInput(mainDexList); - } - ruleContext.registerAction(builder.build(ruleContext)); - } - - public static AndroidIdeInfoProvider createAndroidIdeInfoProvider( - RuleContext ruleContext, - AndroidIdlHelper idlHelper, - JavaOutput resourceJarJavaOutput, - Artifact aar, - ResourceApk resourceApk, - Artifact zipAlignedApk, - Iterable apksUnderTest, - NativeLibs nativeLibs) { - AndroidIdeInfoProvider.Builder ideInfoProviderBuilder = - new AndroidIdeInfoProvider.Builder() - .setIdlClassJar(idlHelper.getIdlClassJar()) - .setIdlSourceJar(idlHelper.getIdlSourceJar()) - .setResourceJarJavaOutput(resourceJarJavaOutput) - .setAar(aar) - .setNativeLibs(nativeLibs.getMap()) - .addIdlImportRoot(idlHelper.getIdlImportRoot()) - .addIdlSrcs(idlHelper.getIdlSources()) - .addIdlGeneratedJavaFiles(idlHelper.getIdlGeneratedJavaSources()) - .addAllApksUnderTest(apksUnderTest); - - if (zipAlignedApk != null) { - ideInfoProviderBuilder.setApk(zipAlignedApk); - } - - // If the rule defines resources, put those in the IDE info. - if (AndroidResources.definesAndroidResources(ruleContext.attributes())) { - ideInfoProviderBuilder - .setDefinesAndroidResources(true) - // Sets the possibly merged manifest and the raw manifest. - .setGeneratedManifest(resourceApk.getManifest()) - .setManifest(ruleContext.getPrerequisiteArtifact("manifest")) - .setJavaPackage(getJavaPackage(ruleContext)) - .setResourceApk(resourceApk.getArtifact()); - } - - return ideInfoProviderBuilder.build(); - } - /** * Gets the Java package for the current target. * @@ -393,427 +274,6 @@ static ImmutableList getApkDebugSigningKeys(RuleContext ruleContext) { return ImmutableList.of(ruleContext.getPrerequisiteArtifact("debug_key")); } - private void compileResources( - JavaSemantics javaSemantics, - Artifact resourceJavaClassJar, - Artifact resourceJavaSrcJar, - JavaCompilationArtifacts.Builder artifactsBuilder, - JavaTargetAttributes.Builder attributes, - NestedSetBuilder filesBuilder) - throws InterruptedException, RuleErrorException { - - packResourceSourceJar(javaSemantics, resourceJavaSrcJar); - - // Add the compiled resource jar to the classpath of the main compilation. - attributes.addDirectJars(NestedSetBuilder.create(Order.STABLE_ORDER, resourceJavaClassJar)); - // Add the compiled resource jar to the classpath of consuming targets. - // We don't actually use the ijar. That is almost the same as the resource class jar - // except for , but it takes time to build and waiting for that to build would - // just delay building the rest of the library. - artifactsBuilder.addCompileTimeJarAsFullJar(resourceJavaClassJar); - - // Add the compiled resource jar as a declared output of the rule. - filesBuilder.add(resourceSourceJar); - filesBuilder.add(resourceJavaClassJar); - } - - private void packResourceSourceJar(JavaSemantics javaSemantics, Artifact resourcesJavaSrcJar) - throws InterruptedException, RuleErrorException { - - resourceSourceJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_SOURCE_JAR); - - JavaTargetAttributes.Builder javacAttributes = - new JavaTargetAttributes.Builder(javaSemantics).addSourceJar(resourcesJavaSrcJar); - JavaCompilationHelper javacHelper = - new JavaCompilationHelper(ruleContext, javaSemantics, getJavacOpts(), javacAttributes); - javacHelper.createSourceJarAction(resourceSourceJar, null); - } - - @Nullable - public JavaTargetAttributes init( - JavaSemantics javaSemantics, - AndroidSemantics androidSemantics, - ResourceApk resourceApk, - boolean addCoverageSupport, - boolean collectJavaCompilationArgs, - boolean isBinary, - boolean shouldCompileJavaSrcs, - NestedSet excludedRuntimeArtifacts, - boolean generateExtensionRegistry) - throws InterruptedException, RuleErrorException { - - if (shouldCompileJavaSrcs) { - classJar = - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR); - } else { - // When java compilation happens in application_resources, grab the class jar from its - // JavaInfo. - classJar = - Iterables.getOnlyElement( - JavaInfo.getJavaInfo(ruleContext.getPrerequisite("application_resources")) - .getOutputJars() - .getJavaOutputs()) - .getClassJar(); - } - idlHelper = new AndroidIdlHelper(ruleContext, classJar); - - BootClassPathInfo bootClassPathInfo = androidSemantics.getBootClassPathInfo(ruleContext); - - ImmutableList.Builder javacopts = ImmutableList.builder(); - javacopts.addAll(androidSemantics.getCompatibleJavacOptions(ruleContext)); - - if (shouldCompileJavaSrcs) { - resourceApk - .asDataBindingContext() - .supplyJavaCoptsUsing(ruleContext, isBinary, javacopts::addAll); - } - JavaTargetAttributes.Builder attributesBuilder = - javaCommon - .initCommon(idlHelper.getIdlGeneratedJavaSources(), javacopts.build()) - .setBootClassPath(bootClassPathInfo); - - if (shouldCompileJavaSrcs) { - resourceApk - .asDataBindingContext() - .supplyAnnotationProcessor( - ruleContext, - (plugin, additionalOutputs) -> { - attributesBuilder.addPlugin(plugin); - attributesBuilder.addAdditionalOutputs(additionalOutputs); - }); - } - - if (excludedRuntimeArtifacts != null) { - attributesBuilder.addExcludedArtifacts(excludedRuntimeArtifacts); - } - - JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder(); - NestedSetBuilder jarsProducedForRuntime = NestedSetBuilder.stableOrder(); - NestedSetBuilder filesBuilder = NestedSetBuilder.stableOrder(); - - Artifact resourceJavaSrcJar = resourceApk.getResourceJavaSrcJar(); - if (resourceJavaSrcJar != null) { - filesBuilder.add(resourceJavaSrcJar); - - compileResources( - javaSemantics, - resourceApk.getResourceJavaClassJar(), - resourceJavaSrcJar, - artifactsBuilder, - attributesBuilder, - filesBuilder); - - // Combined resource constants needs to come even before our own classes that may contain - // local resource constants. - artifactsBuilder.addRuntimeJar(resourceApk.getResourceJavaClassJar()); - jarsProducedForRuntime.add(resourceApk.getResourceJavaClassJar()); - } - - ImmutableList additionalJavaInputsFromDatabinding = null; - if (shouldCompileJavaSrcs) { - // Databinding metadata that the databinding annotation processor reads. - additionalJavaInputsFromDatabinding = - resourceApk.asDataBindingContext().processDeps(ruleContext, isBinary); - } else { - ImmutableList.Builder outputs = ImmutableList.builder(); - DataBindingV2Provider p = - ruleContext.getPrerequisite("application_resources", DataBindingV2Provider.PROVIDER); - outputs.addAll(p.getSetterStores().toList()); - outputs.addAll(p.getTransitiveBRFiles().toList()); - additionalJavaInputsFromDatabinding = outputs.build(); - } - - JavaCompilationHelper helper = - initAttributes(attributesBuilder, javaSemantics, additionalJavaInputsFromDatabinding); - if (ruleContext.hasErrors()) { - return null; - } - - if (addCoverageSupport) { - androidSemantics.addCoverageSupport(ruleContext, true, attributesBuilder); - if (ruleContext.hasErrors()) { - return null; - } - } - - JavaTargetAttributes attributes = attributesBuilder.build(); - if (shouldCompileJavaSrcs) { - initJava( - javaSemantics, - helper, - attributes, - artifactsBuilder, - collectJavaCompilationArgs, - filesBuilder, - generateExtensionRegistry); - if (ruleContext.hasErrors()) { - return null; - } - if (generatedExtensionRegistryProvider != null) { - jarsProducedForRuntime.add(generatedExtensionRegistryProvider.getClassJar()); - } - this.jarsProducedForRuntime = jarsProducedForRuntime.add(classJar).build(); - } else { - // Getting java artifacts from application_resources - JavaInfo javaInfo = - JavaInfo.getJavaInfo(ruleContext.getPrerequisite("application_resources")); - JavaOutput javaOutput = Iterables.getOnlyElement(javaInfo.getOutputJars().getJavaOutputs()); - outputs = helper.createOutputs(javaOutput); - - // The macro creating both the Starlark android_binary_internal and android_binary ensures - // that they share the same attributes, which is why we can still check the android_binary - // attributes when Javac happens in android_binary_internal. - if (attributes.hasSources() || attributes.hasResources()) { - // We only want to add a jar to the classpath of a dependent rule if it has content. - artifactsBuilder.addRuntimeJar(classJar); - } - - artifactsBuilder.addCompileTimeJarAsFullJar(classJar); - javaSourceJarsProviderBuilder - .addAllSourceJars(javaInfo.getSourceJars()) - .addAllTransitiveSourceJars( - javaCommon.collectTransitiveSourceJars(javaInfo.getSourceJars())); - - if (generateExtensionRegistry) { - generatedExtensionRegistryProvider = - javaSemantics.createGeneratedExtensionRegistry( - ruleContext, - javaCommon, - filesBuilder, - artifactsBuilder, - javaRuleOutputJarsProviderBuilder, - javaSourceJarsProviderBuilder); - } - - JavaCompilationArtifacts javaArtifacts = artifactsBuilder.build(); - javaCommon.setJavaCompilationArtifacts(javaArtifacts); - filesToBuild = filesBuilder.build(); - NestedSetBuilder runtimeJars = - NestedSetBuilder.naiveLinkOrder().addAll(javaInfo.getDirectRuntimeJars()); - if (generatedExtensionRegistryProvider != null) { - jarsProducedForRuntime.add(generatedExtensionRegistryProvider.getClassJar()); - runtimeJars.add(generatedExtensionRegistryProvider.getClassJar()); - } - transitiveNeverlinkLibraries = - collectTransitiveNeverlinkLibraries( - ruleContext, javaCommon.getDependencies(), runtimeJars.build()); - this.jarsProducedForRuntime = jarsProducedForRuntime.add(classJar).build(); - if (collectJavaCompilationArgs) { - this.javaCompilationArgs = javaCommon.collectJavaCompilationArgs(asNeverLink); - } - } - return attributes; - } - - private JavaCompilationHelper initAttributes( - JavaTargetAttributes.Builder attributes, - JavaSemantics semantics, - ImmutableList additionalArtifacts) - throws RuleErrorException { - JavaCompilationHelper helper = - new JavaCompilationHelper( - ruleContext, semantics, javaCommon.getJavacOpts(), attributes, additionalArtifacts); - - helper.addLibrariesToAttributes(javaCommon.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)); - attributes.setTargetLabel(ruleContext.getLabel()); - - ruleContext.checkSrcsSamePackage(true); - return helper; - } - - private void initJava( - JavaSemantics javaSemantics, - JavaCompilationHelper helper, - JavaTargetAttributes attributes, - JavaCompilationArtifacts.Builder javaArtifactsBuilder, - boolean collectJavaCompilationArgs, - NestedSetBuilder filesBuilder, - boolean generateExtensionRegistry) - throws InterruptedException, RuleErrorException { - if (ruleContext.hasErrors()) { - // Avoid leaving filesToBuild set to null, otherwise we'll get a NullPointerException masking - // the real error. - filesToBuild = filesBuilder.build(); - return; - } - - Artifact jar = null; - if (attributes.hasSources() || attributes.hasResources()) { - // We only want to add a jar to the classpath of a dependent rule if it has content. - javaArtifactsBuilder.addRuntimeJar(classJar); - jar = classJar; - } - - filesBuilder.add(classJar); - - outputs = helper.createOutputs(classJar); - javaArtifactsBuilder.setCompileTimeDependencies(outputs.depsProto()); - - srcJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_SOURCE_JAR); - javaSourceJarsProviderBuilder - .addSourceJar(srcJar) - .addAllTransitiveSourceJars(javaCommon.collectTransitiveSourceJars(srcJar)); - helper.createSourceJarAction(srcJar, outputs.genSource()); - - helper.createCompileAction(outputs); - - if (generateExtensionRegistry) { - generatedExtensionRegistryProvider = - javaSemantics.createGeneratedExtensionRegistry( - ruleContext, - javaCommon, - filesBuilder, - javaArtifactsBuilder, - javaRuleOutputJarsProviderBuilder, - javaSourceJarsProviderBuilder); - } - - filesToBuild = filesBuilder.build(); - - if (attributes.hasSources() && jar != null) { - iJar = helper.createCompileTimeJarAction(jar, javaArtifactsBuilder); - } - - JavaCompilationArtifacts javaArtifacts = javaArtifactsBuilder.build(); - javaCommon.setJavaCompilationArtifacts(javaArtifacts); - - javaCommon.setClassPathFragment( - new ClasspathConfiguredFragment( - javaCommon.getJavaCompilationArtifacts(), - attributes, - asNeverLink, - helper.getBootclasspathOrDefault().bootclasspath())); - - transitiveNeverlinkLibraries = - collectTransitiveNeverlinkLibraries( - ruleContext, - javaCommon.getDependencies(), - NestedSetBuilder.naiveLinkOrder() - .addAll(javaCommon.getJavaCompilationArtifacts().getRuntimeJars()) - .build()); - if (collectJavaCompilationArgs) { - this.javaCompilationArgs = javaCommon.collectJavaCompilationArgs(asNeverLink); - } - } - - public RuleConfiguredTargetBuilder addTransitiveInfoProviders( - RuleConfiguredTargetBuilder builder, - Artifact aar, - ResourceApk resourceApk, - Artifact zipAlignedApk, - Iterable apksUnderTest, - NativeLibs nativeLibs, - boolean isNeverlink, - boolean isLibrary) - throws RuleErrorException { - - idlHelper.addTransitiveInfoProviders(builder, classJar, outputs.manifestProto()); - - if (generatedExtensionRegistryProvider != null) { - builder.addNativeDeclaredProvider(generatedExtensionRegistryProvider); - } - JavaOutput resourceJarJavaOutput = null; - if (resourceApk.getResourceJavaClassJar() != null && resourceSourceJar != null) { - resourceJarJavaOutput = - JavaOutput.builder() - .setClassJar(resourceApk.getResourceJavaClassJar()) - .addSourceJar(resourceSourceJar) - .build(); - javaRuleOutputJarsProviderBuilder.addJavaOutput(resourceJarJavaOutput); - } - - JavaRuleOutputJarsProvider ruleOutputJarsProvider = - javaRuleOutputJarsProviderBuilder - .addJavaOutput( - JavaOutput.builder() - .fromJavaCompileOutputs(outputs) - .setCompileJar(iJar) - .setCompileJdeps( - javaCommon.getJavaCompilationArtifacts().getCompileTimeDependencyArtifact()) - .addSourceJar(srcJar) - .build()) - .build(); - JavaSourceJarsProvider sourceJarsProvider = javaSourceJarsProviderBuilder.build(); - JavaCompilationArgsProvider compilationArgsProvider = javaCompilationArgs; - - JavaInfo.Builder javaInfoBuilder = JavaInfo.Builder.create(); - - javaCommon.addTransitiveInfoProviders( - builder, javaInfoBuilder, filesToBuild, classJar, ANDROID_COLLECTION_SPEC); - - javaCommon.addGenJarsProvider( - builder, javaInfoBuilder, outputs.genClass(), outputs.genSource()); - - resourceApk.asDataBindingContext().addProvider(builder, ruleContext); - - JavaInfo javaInfo = - javaInfoBuilder - .javaCompilationArgs(compilationArgsProvider) - .javaRuleOutputs(ruleOutputJarsProvider) - .javaSourceJars(sourceJarsProvider) - .javaPluginInfo(JavaCommon.getTransitivePlugins(ruleContext)) - .setRuntimeJars(javaCommon.getJavaCompilationArtifacts().getRuntimeJars()) - .setJavaConstraints(ImmutableList.of("android")) - .setNeverlink(isNeverlink) - .build(); - - // Do not convert the ResourceApk into builtin providers when it is created from - // Starlark via AndroidApplicationResourceInfo, because native dependency providers are not - // created in the Starlark pipeline. - if (resourceApk.isFromAndroidApplicationResourceInfo() - || (ruleContext - .getFragment(AndroidConfiguration.class) - .omitResourcesInfoProviderFromAndroidBinary() - && !isLibrary)) { - // Binary rule; allow extracting merged manifest from Starlark via - // ctx.attr.android_binary.android.merged_manifest, but not much more. - builder.addStarlarkTransitiveInfo( - AndroidStarlarkApiProvider.NAME, new AndroidStarlarkApiProvider(/*resourceInfo=*/ null)); - } else { - resourceApk.addToConfiguredTargetBuilder( - builder, ruleContext.getLabel(), /* includeStarlarkApiProvider = */ true, isLibrary); - } - - return builder - .setFilesToBuild(filesToBuild) - .addStarlarkDeclaredProvider(javaInfo) - .addProvider(RunfilesProvider.class, RunfilesProvider.simple(getRunfiles())) - .addNativeDeclaredProvider( - createAndroidIdeInfoProvider( - ruleContext, - idlHelper, - resourceJarJavaOutput, - aar, - resourceApk, - zipAlignedApk, - apksUnderTest, - nativeLibs)) - .addOutputGroup( - OutputGroupInfo.HIDDEN_TOP_LEVEL, collectHiddenTopLevelArtifacts(ruleContext)) - .addOutputGroup( - JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, sourceJarsProvider.getTransitiveSourceJars()) - .addOutputGroup( - JavaSemantics.DIRECT_SOURCE_JARS_OUTPUT_GROUP, - NestedSetBuilder.wrap(Order.STABLE_ORDER, sourceJarsProvider.getSourceJars())); - } - - private Runfiles getRunfiles() { - // TODO(bazel-team): why return any Runfiles in the neverlink case? - if (asNeverLink) { - return new Runfiles.Builder( - ruleContext.getWorkspaceName(), - ruleContext.getConfiguration().legacyExternalRunfiles()) - .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES) - .build(); - } - return JavaCommon.getRunfiles( - ruleContext, - javaCommon.getJavaSemantics(), - javaCommon.getJavaCompilationArtifacts(), - asNeverLink); - } - public ImmutableList getJavacOpts() { return javaCommon.getJavacOpts(); } @@ -822,15 +282,6 @@ public ImmutableList getRuntimeJars() { return javaCommon.getJavaCompilationArtifacts().getRuntimeJars(); } - /** - * Returns Jars produced by this rule that may go into the runtime classpath. By contrast {@link - * #getRuntimeJars()} returns the complete runtime classpath needed by this rule, including - * dependencies. - */ - public NestedSet getJarsProducedForRuntime() { - return jarsProducedForRuntime; - } - public Artifact getClassJar() { return classJar; } @@ -884,15 +335,6 @@ public static AndroidConfiguration getAndroidConfig(RuleContext context) { return context.getConfiguration().getFragment(AndroidConfiguration.class); } - private NestedSet collectHiddenTopLevelArtifacts(RuleContext ruleContext) { - NestedSetBuilder builder = NestedSetBuilder.stableOrder(); - for (OutputGroupInfo provider : - getTransitivePrerequisites(ruleContext, OutputGroupInfo.STARLARK_CONSTRUCTOR)) { - builder.addTransitive(provider.getOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL)); - } - return builder.build(); - } - /** * Returns a {@link JavaCommon} instance with Android data binding support. * @@ -979,40 +421,6 @@ static NestedSet getSupportApks(RuleContext ruleContext) { return supportApks.build(); } - /** - * Used for instrumentation tests. Filter out classes from the instrumentation JAR that are also - * present in the target JAR. During an instrumentation test, ART will load jars from both APKs - * into the same classloader. If the same class exists in both jars, there will be runtime - * crashes. - * - *

R.class files that share the same package are also filtered out to prevent - * surprising/incorrect references to resource IDs. - */ - public static void createZipFilterAction( - RuleContext ruleContext, - Artifact in, - Artifact filter, - Artifact out, - CheckHashMismatchMode checkHashMismatch, - boolean removeAllRClasses) { - ZipFilterBuilder builder = - new ZipFilterBuilder(ruleContext) - .setInputZip(in) - .addFilterZips(ImmutableList.of(filter)) - .setOutputZip(out) - .addFileTypeToFilter(".class") - .setCheckHashMismatchMode(checkHashMismatch) - // These files are generated by databinding in both the target and the instrumentation - // app with different contents. We want to keep the one from the target app. - .addExplicitFilter("/BR\\.class$") - .addExplicitFilter("/databinding/[^/]+Binding\\.class$"); - if (removeAllRClasses) { - builder.addExplicitFilter("(^|/)R\\.class").addExplicitFilter("(^|/)R\\$.*\\.class"); - } - - builder.build(); - } - private static class FlagMatcher implements Predicate { private final ImmutableList matching; diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java index 4591bcae02bb09..8e21c88c209b81 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java @@ -26,11 +26,9 @@ import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.starlarkbuildapi.android.AndroidDataContextApi; import com.google.devtools.build.lib.vfs.PathFragment; import javax.annotation.Nullable; @@ -57,10 +55,6 @@ public class AndroidDataContext implements AndroidDataContextApi { private static final String OMIT_TRANSITIVE_RESOURCES_FROM_ANDROID_R_CLASSES = "android_resources_strict_deps"; - // Feature which would enable AAPT2's resource name obfuscation optimization for android_binary - // rules with resource shrinking and ProGuard/AppReduce enabled. - private static final String FEATURE_RESOURCE_NAME_OBFUSCATION = "resource_name_obfuscation"; - private final RuleContext ruleContext; private final FilesToRunProvider busybox; private final AndroidSdkProvider sdk; @@ -250,65 +244,4 @@ public boolean annotateRFieldsFromTransitiveDeps() { boolean omitTransitiveResourcesFromAndroidRClasses() { return ruleContext.getFeatures().contains(OMIT_TRANSITIVE_RESOURCES_FROM_ANDROID_R_CLASSES); } - - /** Returns true if the context dictates that resource shrinking should be performed. */ - boolean useResourceShrinking(boolean hasProguardSpecs) { - return isResourceShrinkingEnabled() && hasProguardSpecs; - } - - /** - * Returns true if the context dictates that resource shrinking is enabled. This doesn't - * necessarily mean that shrinking should be performed - for that, use {@link - * #useResourceShrinking(boolean)}, which calls this. - */ - boolean isResourceShrinkingEnabled() { - if (!ruleContext.attributes().has("shrink_resources")) { - return false; - } - - TriState state = ruleContext.attributes().get("shrink_resources", BuildType.TRISTATE); - if (state == TriState.AUTO) { - state = getAndroidConfig().useAndroidResourceShrinking() ? TriState.YES : TriState.NO; - } - - return state == TriState.YES; - } - - /** - * Returns {@code true} if resource shrinking should be performed. This should be true when the - * resource cycle shrinking flag is enabled, resource shrinking itself is enabled, and the build - * is ProGuarded/optimized. The last condition is important because resource cycle shrinking - * generates non-final fields that are not inlined by javac. In non-optimized builds, these can - * noticeably increase Apk size. - */ - boolean shouldShrinkResourceCycles(RuleErrorConsumer errorConsumer, boolean shrinkResources) { - boolean isProguarded = - ruleContext.attributes().has(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST) - && !ruleContext - .getPrerequisiteArtifacts(ProguardHelper.PROGUARD_SPECS) - .list() - .isEmpty(); - return isProguarded && getAndroidConfig().useAndroidResourceCycleShrinking() && shrinkResources; - } - - boolean useResourcePathShortening() { - // Use resource path shortening iff: - // 1) --experimental_android_resource_path_shortening - // 2) -c opt - // 3) Not opting out by being on allowlist named allow_raw_access_to_resource_paths - return getAndroidConfig().useAndroidResourcePathShortening() - && getActionConstructionContext().getConfiguration().getCompilationMode() == OPT - && !optOutOfResourcePathShortening; - } - - boolean useResourceNameObfuscation(boolean hasProguardSpecs) { - // Use resource name obfuscation iff: - // 1) --experimental_android_resource_name_obfuscation or feature enabled for rule's package - // 2) resource shrinking is on (implying proguard specs are present) - // 3) Not opting out by being on allowlist named allow_resource_name_obfuscation_opt_out - return (getAndroidConfig().useAndroidResourceNameObfuscation() - || ruleContext.getFeatures().contains(FEATURE_RESOURCE_NAME_OBFUSCATION)) - && useResourceShrinking(hasProguardSpecs) - && !optOutOfResourceNameObfuscation; - } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java deleted file mode 100644 index 4924b60ec30f63..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import com.google.devtools.build.lib.actions.ActionConflictException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FileProvider; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.RunfilesProvider; -import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.actions.FileWriteAction; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.Type; -import javax.annotation.Nullable; - -/** An implementation of the {@code android_device_script_fixture} rule. */ -public class AndroidDeviceScriptFixture implements RuleConfiguredTargetFactory { - - private final AndroidSemantics androidSemantics; - - protected AndroidDeviceScriptFixture(AndroidSemantics androidSemantics) { - this.androidSemantics = androidSemantics; - } - - @Override - @Nullable - public ConfiguredTarget create(RuleContext ruleContext) - throws InterruptedException, RuleErrorException, ActionConflictException { - androidSemantics.checkForMigrationTag(ruleContext); - Artifact fixtureScript = getFixtureScript(ruleContext); - return new RuleConfiguredTargetBuilder(ruleContext) - .setFilesToBuild(NestedSetBuilder.stableOrder().add(fixtureScript).build()) - .addProvider( - RunfilesProvider.class, - RunfilesProvider.simple( - new Runfiles.Builder(ruleContext.getWorkspaceName()) - .addArtifact(fixtureScript) - .build())) - .addNativeDeclaredProvider( - new AndroidDeviceScriptFixtureInfoProvider( - fixtureScript, - AndroidCommon.getSupportApks(ruleContext), - ruleContext.attributes().get("daemon", Type.BOOLEAN), - ruleContext.attributes().get("strict_exit", Type.BOOLEAN))) - .build(); - } - - /** - * Gets the fixture script from the {@code script} attribute if set or else writes a file - * containing the contents of the {@code cmd} attribute. Also, checks that exactly one of {@code - * script} and {@code cmd} is set. - */ - private static Artifact getFixtureScript(RuleContext ruleContext) - throws RuleErrorException, InterruptedException { - String cmd = null; - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("cmd")) { - cmd = ruleContext.attributes().get("cmd", Type.STRING); - } - TransitiveInfoCollection script = ruleContext.getPrerequisite("script"); - - if (((cmd == null) && (script == null)) || ((cmd != null) && (script != null))) { - ruleContext.throwWithRuleError( - "android_host_service_fixture requires that exactly one of the script and cmd attributes " - + "be specified"); - } - - if (cmd == null) { - // The fact that there is only one file and that it has the right extension is enforced by the - // rule definition. - return script.getProvider(FileProvider.class).getFilesToBuild().getSingleton(); - } else { - return writeFixtureScript(ruleContext, cmd); - } - } - - private static Artifact writeFixtureScript(RuleContext ruleContext, String cmd) - throws InterruptedException { - Artifact output = - ruleContext.getUniqueDirectoryArtifact( - "cmd_device_fixtures", "cmd.sh", ruleContext.getBinOrGenfilesDirectory()); - ruleContext.registerAction(FileWriteAction.create(ruleContext, output, cmd, false)); - return output; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java deleted file mode 100644 index 59fd60bdbd3777..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import static com.google.devtools.build.lib.packages.Type.STRING; - -import com.google.devtools.build.lib.analysis.BaseRuleClasses; -import com.google.devtools.build.lib.analysis.RuleDefinition; -import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.packages.RuleClass; -import com.google.devtools.build.lib.util.FileType; - -/** Rule definition for the {@code android_device_script_fixture} rule. */ -public class AndroidDeviceScriptFixtureRule implements RuleDefinition { - - static final FileType DEVICE_SCRIPT_FIXTURE = FileType.of(".sh"); - - private final Class factoryClass; - - public AndroidDeviceScriptFixtureRule(Class factoryClass) { - this.factoryClass = factoryClass; - } - - @Override - public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) { - return builder - .setUndocumented() - .add( - attr("script", LABEL) - .exec() - .allowedFileTypes(DEVICE_SCRIPT_FIXTURE) - .allowedRuleClasses()) - .add(attr("cmd", STRING)) - .add( - attr("support_apks", LABEL_LIST) - .allowedFileTypes(AndroidRuleClasses.APK) - .allowedRuleClasses("android_binary")) - .add(attr("daemon", BOOLEAN).value(Boolean.FALSE)) - .add(attr("strict_exit", BOOLEAN).value(Boolean.TRUE)) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("android_device_script_fixture") - .ancestors(BaseRuleClasses.NativeActionCreatingRule.class) - .factoryClass(factoryClass) - .build(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java deleted file mode 100644 index 6ba972dc3524bb..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import com.google.devtools.build.lib.actions.ActionConflictException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.RunfilesProvider; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.Type; -import javax.annotation.Nullable; - -/** An implementation of the {@code android_host_service_fixture} rule. */ -public class AndroidHostServiceFixture implements RuleConfiguredTargetFactory { - - private final AndroidSemantics androidSemantics; - - protected AndroidHostServiceFixture(AndroidSemantics androidSemantics) { - this.androidSemantics = androidSemantics; - } - - @Override - @Nullable - public ConfiguredTarget create(RuleContext ruleContext) - throws InterruptedException, RuleErrorException, ActionConflictException { - androidSemantics.checkForMigrationTag(ruleContext); - RuleConfiguredTargetBuilder ruleBuilder = new RuleConfiguredTargetBuilder(ruleContext); - NestedSet supportApks = AndroidCommon.getSupportApks(ruleContext); - FilesToRunProvider executable = ruleContext.getExecutablePrerequisite("executable"); - - NestedSet filesToBuild = - NestedSetBuilder.stableOrder() - .addTransitive(supportApks) - .add(executable.getExecutable()) - .build(); - Runfiles runfiles = - new Runfiles.Builder(ruleContext.getWorkspaceName()) - .addTransitiveArtifacts(supportApks) - .merge(executable.getRunfilesSupport()) - .build(); - return ruleBuilder - .setFilesToBuild(filesToBuild) - .addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles)) - .addNativeDeclaredProvider( - new AndroidHostServiceFixtureInfoProvider( - executable.getExecutable(), - ruleContext.getExpander().withDataLocations().tokenized("service_names"), - AndroidCommon.getSupportApks(ruleContext), - ruleContext.attributes().get("provides_test_args", Type.BOOLEAN), - ruleContext.attributes().get("daemon", Type.BOOLEAN))) - .build(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureRule.java deleted file mode 100644 index 96ba2d39d9b1ec..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixtureRule.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import static com.google.devtools.build.lib.packages.Types.STRING_LIST; - -import com.google.devtools.build.lib.analysis.BaseRuleClasses; -import com.google.devtools.build.lib.analysis.RuleDefinition; -import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; -import com.google.devtools.build.lib.packages.RuleClass; - -/** Rule definition for the {@code android_host_service_fixture} rule. */ -public class AndroidHostServiceFixtureRule implements RuleDefinition { - - private final Class factoryClass; - - public AndroidHostServiceFixtureRule(Class factoryClass) { - this.factoryClass = factoryClass; - } - - @Override - public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { - return builder - .setUndocumented() - .add( - attr("executable", LABEL) - .exec() - .cfg(ExecutionTransitionFactory.createFactory()) - .mandatory() - .allowedFileTypes()) - .add(attr("service_names", STRING_LIST)) - .add( - attr("support_apks", LABEL_LIST) - .allowedFileTypes(AndroidRuleClasses.APK) - .allowedRuleClasses("android_binary")) - .add(attr("provides_test_args", BOOLEAN).value(false)) - .add(attr("daemon", BOOLEAN).value(false)) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("android_host_service_fixture") - .ancestors(BaseRuleClasses.NativeActionCreatingRule.class) - .factoryClass(factoryClass) - .build(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java deleted file mode 100644 index 6f87de7e0dbd62..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.actions.ActionConflictException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.OutputGroupInfo; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.AttributeMap; -import com.google.devtools.build.lib.packages.BuildType; -import com.google.devtools.build.lib.packages.TriState; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.android.AndroidLibraryAarInfo.Aar; -import com.google.devtools.build.lib.rules.android.databinding.DataBinding; -import com.google.devtools.build.lib.rules.java.JavaCommon; -import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; -import com.google.devtools.build.lib.rules.java.ProguardLibrary; -import com.google.devtools.build.lib.rules.java.ProguardSpecProvider; -import javax.annotation.Nullable; - -/** An implementation for the "android_library" rule. */ -public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { - - protected abstract JavaSemantics createJavaSemantics(); - - protected abstract AndroidSemantics createAndroidSemantics(); - - /** Checks expected rule invariants, throws rule errors if anything is set wrong. */ - private static void validateRuleContext(RuleContext ruleContext) - throws InterruptedException, RuleErrorException { - /** - * Report an error if android_library rule contains deps without srcs or locally-used resources. - * Such deps are implicitly exported (deprecated behavior), and will soon be disallowed - * entirely. - */ - // TODO(cushon): this rule doesn't cover srcs-less deps exporting in android_binary, which - // it is possible to add to deps - if (usesDeprecatedImplicitExport(ruleContext)) { - String message = - "android_library will be deprecating the use of deps to export " - + "targets implicitly. Please use android_library.exports to explicitly specify " - + "targets this rule exports"; - ruleContext.attributeError("deps", message); - } - } - - /** - * TODO(b/14473160): Remove when deps are no longer implicitly exported. - * - *

Returns true if the rule (possibly) relies on the implicit dep exports behavior. - * - *

If this returns true, then the rule *is* exporting deps implicitly, and does not have any - * srcs or locally-used resources consuming the deps. - * - *

Else, this rule either is not using deps or has another deps-consuming attribute (src, - * locally-used resources) - */ - private static boolean usesDeprecatedImplicitExport(RuleContext ruleContext) - throws RuleErrorException { - AttributeMap attrs = ruleContext.attributes(); - - if (!attrs.isAttributeValueExplicitlySpecified("deps") - || attrs.get("deps", BuildType.LABEL_LIST).isEmpty()) { - return false; - } - - String[] labelListAttrs = {"srcs", "idl_srcs", "assets", "resource_files"}; - for (String attr : labelListAttrs) { - if (attrs.isAttributeValueExplicitlySpecified(attr) - && !attrs.get(attr, BuildType.LABEL_LIST).isEmpty()) { - return false; - } - } - - boolean hasManifest = attrs.isAttributeValueExplicitlySpecified("manifest"); - boolean hasAssetsDir = attrs.isAttributeValueExplicitlySpecified("assets_dir"); - boolean hasInlineConsts = - attrs.isAttributeValueExplicitlySpecified("inline_constants") - && attrs.get("inline_constants", Type.BOOLEAN); - boolean hasExportsManifest = - attrs.isAttributeValueExplicitlySpecified("exports_manifest") - && attrs.get("exports_manifest", BuildType.TRISTATE) == TriState.YES; - - return !(hasManifest || hasInlineConsts || hasAssetsDir || hasExportsManifest); - } - - @Override - @Nullable - public ConfiguredTarget create(RuleContext ruleContext) - throws InterruptedException, RuleErrorException, ActionConflictException { - // Create semantics objects, which are different between Blaze and Bazel. - JavaSemantics javaSemantics = createJavaSemantics(); - AndroidSemantics androidSemantics = createAndroidSemantics(); - androidSemantics.checkForMigrationTag(ruleContext); - androidSemantics.validateAndroidLibraryRuleContext(ruleContext); - AndroidSdkProvider.verifyPresence(ruleContext); - validateRuleContext(ruleContext); - - // Create wrappers for the ProGuard configuration files. - NestedSetBuilder proguardConfigsbuilder = NestedSetBuilder.stableOrder(); - ProguardLibrary proguardLibrary = new ProguardLibrary(ruleContext); - proguardConfigsbuilder.addTransitive(proguardLibrary.collectProguardSpecs()); - - // If there are idl srcs, we'll need the transitive proguard configurations too. - AndroidIdlHelper.maybeAddSupportLibProguardConfigs(ruleContext, proguardConfigsbuilder); - NestedSet transitiveProguardConfigs = proguardConfigsbuilder.build(); - - AndroidConfiguration androidConfig = AndroidCommon.getAndroidConfig(ruleContext); - - // "Resources" here include actual resources (xmls, drawables, etc), assets, and the manifest. - boolean definesLocalResources = - AndroidResources.definesAndroidResources(ruleContext.attributes()); - if (definesLocalResources) { - AndroidResources.validateRuleContext(ruleContext); - } - - // TODO(b/69668042): Always correctly apply neverlinking for resources - boolean isNeverLink = - JavaCommon.isNeverLink(ruleContext) - && (definesLocalResources || androidConfig.fixedResourceNeverlinking()); - ResourceDependencies resourceDeps = ResourceDependencies.fromRuleDeps(ruleContext, isNeverLink); - AssetDependencies assetDeps = AssetDependencies.fromRuleDeps(ruleContext, isNeverLink); - - // Start processing Android data via the AndroidDataContext. - // "Data" is a collective term for manifest, resources, and assets. - final AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext); - // Use a standalone resource-only APK (with extension ".ap_") to decouple Android data from the - // other artifacts. - final ResourceApk resourceApk; - if (definesLocalResources) { - StampedAndroidManifest manifest = - AndroidManifest.fromAttributes(ruleContext, dataContext, androidSemantics) - .stamp(dataContext); - - ValidatedAndroidResources resources = - AndroidResources.from(ruleContext, "resource_files") - .process( - ruleContext, - dataContext, - manifest, - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()), - isNeverLink); - - MergedAndroidAssets assets = AndroidAssets.from(ruleContext).process(dataContext, assetDeps); - - resourceApk = ResourceApk.of(resources, assets, null, null); - - if (ruleContext.hasErrors()) { - return null; - } - } else { - // No local resources, but we still need to process transitive resources in order to export an - // aar. - resourceApk = - ResourceApk.processFromTransitiveLibraryData( - dataContext, - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()), - resourceDeps, - assetDeps, - StampedAndroidManifest.createEmpty(ruleContext, /* exported = */ false)); - } - - // JavaCommon and AndroidCommon contain shared helper classes between java_* and android_* - // rules respectively. - JavaCommon javaCommon = - AndroidCommon.createJavaCommonWithAndroidDataBinding( - ruleContext, - javaSemantics, - resourceApk.asDataBindingContext(), - /* isLibrary */ true, - /* shouldCompileJavaSrcs */ true); - androidSemantics.checkRule(ruleContext, javaCommon); - AndroidCommon androidCommon = new AndroidCommon(javaCommon); - - // As android_library makes use of the Java rule compilation pipeline, we collect all - // Java-related information here to be passed into the JavaSourceInfoProvider later. - JavaTargetAttributes javaTargetAttributes = - androidCommon.init( - javaSemantics, - androidSemantics, - resourceApk, - /* addCoverageSupport= */ false, - /* collectJavaCompilationArgs= */ true, - /* isBinary= */ false, - /* shouldCompileJavaSrcs= */ true, - /* excludedRuntimeArtifacts= */ null, - /* generateExtensionRegistry= */ false); - if (javaTargetAttributes == null) { - return null; - } - - // Create the implicit AAR output artifact which contains non-transitive resources, proguard - // specs and class jar. - final Aar aar = - Aar.makeAar( - dataContext, - resourceApk, - proguardLibrary.collectLocalProguardSpecs(), - androidCommon.getClassJar()); - - // Start building the configured target by adding all the necessary transitive providers/infos. - // Includes databinding, IDE, Java. Also declares the output groups and sets the files to build. - RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext); - androidCommon.addTransitiveInfoProviders( - builder, - aar.getAar(), - resourceApk, - null, - ImmutableList.of(), - NativeLibs.EMPTY, - // TODO(elenairina): Use JavaCommon.isNeverlink(ruleContext) for consistency among rules. - androidCommon.isNeverLink(), - /* isLibrary = */ true); - - NestedSetBuilder transitiveResourcesJars = collectTransitiveResourceJars(ruleContext); - if (resourceApk.getResourceJavaClassJar() != null) { - transitiveResourcesJars.add(resourceApk.getResourceJavaClassJar()); - } - - builder - // android_library doesn't do any cc steps, so we'll just pass native libs along. - .addNativeDeclaredProvider( - new AndroidNativeLibsInfo( - AndroidCommon.collectTransitiveNativeLibs(ruleContext).build())) - .addNativeDeclaredProvider(new AndroidCcLinkParamsProvider(androidCommon.getCcInfo())) - .addNativeDeclaredProvider(new ProguardSpecProvider(transitiveProguardConfigs)) - .addNativeDeclaredProvider( - new AndroidProguardInfo(proguardLibrary.collectLocalProguardSpecs())) - .addOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL, transitiveProguardConfigs) - .addNativeDeclaredProvider( - AndroidLibraryResourceClassJarProvider.create(transitiveResourcesJars.build())); - - // If this isn't a neverlink target, we'll provide the artifacts in the AAR too. - if (!JavaCommon.isNeverLink(ruleContext)) { - builder.addNativeDeclaredProvider(aar.toProvider(ruleContext, definesLocalResources)); - } - - return builder.build(); - } - - private NestedSetBuilder collectTransitiveResourceJars(RuleContext ruleContext) { - NestedSetBuilder builder = NestedSetBuilder.naiveLinkOrder(); - Iterable providers = - AndroidCommon.getTransitivePrerequisites( - ruleContext, AndroidLibraryResourceClassJarProvider.PROVIDER); - for (AndroidLibraryResourceClassJarProvider resourceJarProvider : providers) { - builder.addTransitive(resourceJarProvider.getResourceClassJars()); - } - return builder; - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibraryBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibraryBaseRule.java deleted file mode 100644 index adcc2b8f08f220..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibraryBaseRule.java +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import static com.google.devtools.build.lib.packages.Type.STRING; - -import com.google.devtools.build.lib.analysis.RuleDefinition; -import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; -import com.google.devtools.build.lib.packages.RuleClass; -import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; -import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier; -import com.google.devtools.build.lib.packages.TriState; -import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.AndroidResourceSupportRule; -import com.google.devtools.build.lib.rules.java.JavaConfiguration; -import com.google.devtools.build.lib.rules.java.JavaInfo; -import com.google.devtools.build.lib.rules.java.JavaPluginInfo; -import com.google.devtools.build.lib.rules.java.JavaRuleClasses; -import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.rules.java.ProguardLibraryRule; -import com.google.devtools.build.lib.util.FileTypeSet; - -/** Rule definition for the android_library rule. */ -public final class AndroidLibraryBaseRule implements RuleDefinition { - private final AndroidNeverlinkAspect androidNeverlinkAspect; - - public AndroidLibraryBaseRule(AndroidNeverlinkAspect androidNeverlinkAspect) { - this.androidNeverlinkAspect = androidNeverlinkAspect; - } - - @Override - public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { - return builder - .requiresConfigurationFragments(JavaConfiguration.class, AndroidConfiguration.class) - /* - The list of .java or .srcjar files that - are processed to create the target. -

srcs files of type .java are compiled. - For readability's sake, it is not good to put the name of a - generated .java source file into the srcs. - Instead, put the depended-on rule name in the srcs, as - described below. -

-

srcs files of type .srcjar are unpacked and - compiled. (This is useful if you need to generate a set of .java files with - a genrule or build extension.) -

-

If srcs is omitted, then any dependency specified in - deps is exported from this rule (see - java_library.exports for more - information about exporting dependencies). However, this behavior will be - deprecated soon; try not to rely on it. -

- */ - .add( - attr("srcs", LABEL_LIST) - .direct_compile_time_input() - .allowedFileTypes(JavaSemantics.JAVA_SOURCE, JavaSemantics.SOURCE_JAR)) - /* - The list of other libraries to link against. - Permitted library types are: android_library, - java_library with android constraint and - cc_library wrapping or producing .so native libraries - for the Android target platform. - */ - .override( - builder - .copy("deps") - .allowedRuleClasses(AndroidRuleClasses.ALLOWED_DEPENDENCIES) - .allowedFileTypes() - .mandatoryProviders(AndroidRuleClasses.CONTAINS_CC_INFO_PARAMS) - .mandatoryProviders(JavaRuleClasses.CONTAINS_JAVA_PROVIDER) - .aspect(androidNeverlinkAspect)) - /* - The closure of all rules reached via exports attributes - are considered direct dependencies of any rule that directly depends on the - target with exports. -

The exports are not direct deps of the rule they belong to.

- */ - .add( - attr("exports", LABEL_LIST) - .allowedRuleClasses(AndroidRuleClasses.ALLOWED_DEPENDENCIES) - .allowedFileTypes(/*May not have files in exports!*/ ) - .mandatoryProviders(AndroidRuleClasses.CONTAINS_CC_INFO_PARAMS) - .mandatoryProviders(JavaRuleClasses.CONTAINS_JAVA_PROVIDER) - .aspect(androidNeverlinkAspect)) - /* - Whether to export manifest entries to android_binary targets - that depend on this target. uses-permissions attributes are never exported. - */ - .add(attr("exports_manifest", TRISTATE).value(TriState.YES)) - /* - The list of java_plugins (e.g. annotation - processors) to export to libraries that directly depend on this library. -

- The specified list of java_plugins will be applied to any library which - directly depends on this library, just as if that library had explicitly declared these - labels in plugins. -

- */ - .add( - attr("exported_plugins", LABEL_LIST) - .cfg(ExecutionTransitionFactory.createFactory()) - .mandatoryProviders(JavaPluginInfo.PROVIDER.id()) - .allowedFileTypes(FileTypeSet.NO_FILE)) - .add(attr("alwayslink", BOOLEAN).undocumented("purely informational for now")) - /* - Only use this library for compilation and not at runtime. - The outputs of a rule marked as neverlink will not be used in - .apk creation. Useful if the library will be provided by the - runtime environment during execution. - */ - .add(attr("neverlink", BOOLEAN).value(false)) - /* - Package-relative path to the root of the java package tree containing idl - sources included in this library. -

This path will be used as the import root when processing idl sources that - depend on this library.

-

When idl_import_root is specified, both idl_parcelables - and idl_srcs must be at the path specified by the java package of the object - they represent under idl_import_root. When idl_import_root is - not specified, both idl_parcelables and idl_srcs must be at the - path specified by their package under a Java root.

-

See - examples.

- */ - .add(attr("idl_import_root", STRING)) - /* - List of Android IDL definitions to translate to Java interfaces. - After the Java interfaces are generated, they will be compiled together - with the contents of srcs. -

These files will be made available as imports for any - android_library target that depends on this library, directly - or via its transitive closure.

-

These files must be placed appropriately for the aidl compiler to find them. - See the description of idl_import_root - for information about what this means.

- */ - .add( - attr("idl_srcs", LABEL_LIST) - .direct_compile_time_input() - .allowedFileTypes(AndroidRuleClasses.ANDROID_IDL)) - /* - List of Android IDL definitions to supply as imports. - These files will be made available as imports for any - android_library target that depends on this library, directly - or via its transitive closure, but will not be translated to Java - or compiled. -

Only .aidl files that correspond directly to - .java sources in this library should be included (e.g., custom - implementations of Parcelable), otherwise idl_srcs should be - used.

-

These files must be placed appropriately for the aidl compiler to find them. - See the description of idl_import_root - for information about what this means.

- */ - .add( - attr("idl_parcelables", LABEL_LIST) - .direct_compile_time_input() - .allowedFileTypes(AndroidRuleClasses.ANDROID_IDL)) - /* - List of preprocessed Android IDL definitions to supply as imports. - These files will be made available as imports for any - android_library target that depends on this library, directly - or via its transitive closure, but will not be translated to Java - or compiled. -

Only preprocessed .aidl files that correspond directly to - .java sources in this library should be included (e.g., custom - implementations of Parcelable), otherwise use idl_srcs for - Android IDL definitions that need to be translated to Java interfaces and - use idl_parcelable - for non-preprocessed AIDL files. -

- - */ - .add( - attr("idl_preprocessed", LABEL_LIST) - .direct_compile_time_input() - .allowedFileTypes(AndroidRuleClasses.ANDROID_IDL)) - .advertiseStarlarkProvider(StarlarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey())) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("$android_library_base") - .type(RuleClassType.ABSTRACT) - .ancestors(AndroidResourceSupportRule.class, ProguardLibraryRule.class) - .build(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index eb458f73d3156e..3d473f06128c5f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -15,50 +15,20 @@ import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_KEYED_STRING_DICT; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import static com.google.devtools.build.lib.packages.Type.INTEGER; -import static com.google.devtools.build.lib.packages.Type.STRING; -import static com.google.devtools.build.lib.packages.Types.STRING_DICT; -import static com.google.devtools.build.lib.packages.Types.STRING_LIST; -import static com.google.devtools.build.lib.util.FileTypeSet.NO_FILE; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.events.EventHandler; -import com.google.devtools.build.lib.packages.Attribute; -import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet; import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault; -import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier; -import com.google.devtools.build.lib.packages.TriState; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.android.databinding.DataBinding; -import com.google.devtools.build.lib.rules.config.ConfigFeatureFlagProvider; import com.google.devtools.build.lib.rules.cpp.CcInfo; -import com.google.devtools.build.lib.rules.cpp.CppConfiguration; -import com.google.devtools.build.lib.rules.java.JavaConfiguration; -import com.google.devtools.build.lib.rules.java.JavaInfo; -import com.google.devtools.build.lib.rules.java.JavaPluginInfo; -import com.google.devtools.build.lib.rules.java.JavaRuleClasses; -import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; import com.google.devtools.build.lib.util.FileType; -import com.google.devtools.build.lib.util.FileTypeSet; -import java.util.List; -import javax.annotation.Nullable; -import net.starlark.java.eval.StarlarkInt; /** Rule definitions for Android rules. */ public final class AndroidRuleClasses { @@ -121,19 +91,6 @@ public final class AndroidRuleClasses { fromTemplates("%{name}_resource_paths.map"); public static final SafeImplicitOutputsFunction ANDROID_INCREMENTAL_RESOURCES_APK = fromTemplates("%{name}_files/incremental.ap_"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_APK = fromTemplates("%{name}.apk"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_INCREMENTAL_APK = - fromTemplates("%{name}_incremental.apk"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_UNSIGNED_APK = - fromTemplates("%{name}_unsigned.apk"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_V4_SIGNATURE = - fromTemplates("%{name}.apk.idsig"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_DEPLOY_JAR = - fromTemplates("%{name}_deploy.jar"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_JAR = - fromTemplates("%{name}_proguard.jar"); - public static final SafeImplicitOutputsFunction ANDROID_BINARY_INSTRUMENTED_JAR = - fromTemplates("%{name}_instrumented.jar"); public static final SafeImplicitOutputsFunction ANDROID_TEST_FILTERED_JAR = fromTemplates("%{name}_filtered.jar"); public static final SafeImplicitOutputsFunction ANDROID_R_TXT = @@ -190,8 +147,6 @@ public final class AndroidRuleClasses { fromTemplates("%{name}_images/emulator-meta-data.pb"); static final FileType APK = FileType.of(".apk"); - public static final String NOCOMPRESS_EXTENSIONS_ATTR = "nocompress_extensions"; - public static final ImmutableList CONTAINS_CC_INFO_PARAMS = ImmutableList.of(StarlarkProviderIdentifier.forKey(CcInfo.PROVIDER.getKey())); @@ -202,728 +157,9 @@ public static LabelLateBoundDefault getAndroidSdkLabel(Label androidSdk) { androidSdk, (rule, attributes, configuration) -> configuration.getSdk()); } - - @SerializationConstant - static final LabelLateBoundDefault LEGACY_MAIN_DEX_LIST_GENERATOR = - LabelLateBoundDefault.fromTargetConfiguration( - AndroidConfiguration.class, - null, - (rule, attributes, androidConfig) -> androidConfig.getLegacyMainDexListGenerator()); - - @SerializationConstant - static final LabelLateBoundDefault OPTIMIZING_DEXER = - LabelLateBoundDefault.fromTargetConfiguration( - AndroidConfiguration.class, - null, - (rule, attributes, androidConfig) -> androidConfig.getOptimizingDexer()); public static final FileType ANDROID_IDL = FileType.of(".aidl"); - public static final String[] ALLOWED_DEPENDENCIES = { - "aar_import", - "android_library", - "cc_library", - "java_import", - "java_library", - "java_lite_proto_library", - }; - - public static boolean hasProguardSpecs(AttributeMap rule) { - // The below is a hack to support configurable attributes (proguard_specs seems like - // too valuable an attribute to make nonconfigurable, and we don't currently - // have the ability to know the configuration when determining implicit outputs). So if the - // attribute is configurable, we create the proguard implicit output. At analysis time, we know - // the actual value of proguard_specs, and if it is empty we do not use the proguarded jar for - // dexing. If the user explicitly tries to build the proguard jar, it will fail. - // - // TODO(bazel-team): find a stronger approach for this. One simple approach is to somehow - // receive 'rule' as an AggregatingAttributeMapper instead of a RawAttributeMapper, - // check that all possible values are non-empty, and simply don't support configurable - // instances that mix empty and non-empty lists. A more ambitious approach would be - // to somehow determine implicit outputs after the configuration is known. A third - // approach is to refactor the Android rule logic to avoid these dependencies in the - // first place. - return rule.isConfigurable("proguard_specs") - || !rule.get("proguard_specs", LABEL_LIST).isEmpty(); - } - - public static final SafeImplicitOutputsFunction ANDROID_BINARY_IMPLICIT_OUTPUTS = - new SafeImplicitOutputsFunction() { - - @Override - public Iterable getImplicitOutputs(EventHandler eventHandler, AttributeMap rule) { - List functions = Lists.newArrayList(); - functions.add(AndroidRuleClasses.ANDROID_BINARY_APK); - functions.add(AndroidRuleClasses.ANDROID_BINARY_UNSIGNED_APK); - functions.add(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR); - - if (hasProguardSpecs(rule)) { - functions.add(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_JAR); - functions.add(AndroidSemantics.ANDROID_BINARY_PROGUARD_CONFIG); - if (ProguardHelper.genProguardMapping(rule)) { - functions.add(AndroidSemantics.ANDROID_BINARY_PROGUARD_MAP); - } - } - return fromFunctions(functions).getImplicitOutputs(eventHandler, rule); - } - }; - - public static final SafeImplicitOutputsFunction ANDROID_LIBRARY_IMPLICIT_OUTPUTS = - new SafeImplicitOutputsFunction() { - @Override - public Iterable getImplicitOutputs( - EventHandler eventHandler, AttributeMap attributes) { - - ImmutableList.Builder implicitOutputs = - ImmutableList.builder(); - - implicitOutputs.add( - AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR, - AndroidRuleClasses.ANDROID_LIBRARY_SOURCE_JAR, - AndroidRuleClasses.ANDROID_LIBRARY_AAR /* TODO(b/36518935): remove this */); - - if (AndroidResources.definesAndroidResources(attributes)) { - implicitOutputs.add( - AndroidRuleClasses.ANDROID_JAVA_SOURCE_JAR, - AndroidRuleClasses.ANDROID_R_TXT, - AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR); - } - - return fromFunctions(implicitOutputs.build()) - .getImplicitOutputs(eventHandler, attributes); - } - }; - - /** Base class for rule definitions that support resource declarations. */ - public static final class AndroidResourceSupportRule implements RuleDefinition { - @Override - public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { - return builder - /* - The name of the Android manifest file, normally AndroidManifest.xml. - Must be defined if resource_files or assets are defined. - */ - .add(attr("manifest", LABEL).allowedFileTypes(FileType.of(".xml"))) - /* - The list of resources to be packaged. - This is typically a glob of all files under the - res directory. -
- Generated files (from genrules) can be referenced by - Label here as well. The only restriction is that - the generated outputs must be under the same "res" directory as any other - resource files that are included. - */ - .add(attr("resource_files", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) - /* - The string giving the path to the files in assets. - The pair assets and assets_dir describe packaged - assets and either both attributes should be provided or none of them. - */ - .add(attr("assets_dir", STRING)) - /* - The list of assets to be packaged. - This is typically a glob of all files under the - assets directory. You can also reference other rules (any rule that produces - files) or exported files in the other packages, as long as all those files are under the - assets_dir directory in the corresponding package. - */ - .add(attr("assets", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) - /* - Let the compiler inline the constants defined in the generated java sources. - This attribute must be set to 0 for all android_library rules - used directly by an android_binary, - and for any android_binary that has an android_library - in its transitive closure. - */ - .add( - attr("inline_constants", BOOLEAN) - .undocumented("deprecated noop on library") - .value(false)) - /* - Java package for which java sources will be generated. - By default the package is inferred from the directory where the BUILD file - containing the rule is. You can specify a different package but this is - highly discouraged since it can introduce classpath conflicts with other - libraries that will only be detected at runtime. - */ - .add(attr("custom_package", STRING)) - /* - If true, this rule processes - data - binding expressions in layout resources included through the - resource_files attribute. Without this - setting, data binding expressions produce build failures. -

- To build an Android app with data binding, you must also do the following: -

    -
  1. Set this attribute for all Android rules that transitively depend on this one. - This is because dependers inherit the rule's data binding expressions through resource - merging. So they also need to build with data binding to parse those expressions. -
  2. Add a deps = entry for the data binding runtime library to all targets - that set this attribute. The location of this library depends on your depot setup. -
- */ - .add(attr("enable_data_binding", Type.BOOLEAN)) - // The javac annotation processor from Android's data binding library that turns - // processed XML expressions into Java code. - .add( - attr(DataBinding.DATABINDING_ANNOTATION_PROCESSOR_ATTR, LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value(env.getToolsLabel("//tools/android:databinding_annotation_processor"))) - .add( - attr(DataBinding.DATABINDING_EXEC_PROCESSOR_ATTR, LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:databinding_exec"))) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("$android_resource_support") - .type(RuleClassType.ABSTRACT) - .ancestors(AndroidRuleClasses.AndroidBaseRule.class) - .build(); - } - } - - /** Base class for Android rule definitions. */ - public static final class AndroidBaseRule implements RuleDefinition { - @Override - public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { - return builder - .add( - attr(":android_sdk", LABEL) - .allowedRuleClasses("android_sdk") - .value(getAndroidSdkLabel(env.getToolsLabel(AndroidRuleClasses.DEFAULT_SDK)))) - /* - Java compiler plugins to run at compile-time. - Every java_plugin specified in - the plugins attribute will be run whenever - this target is built. Resources generated by - the plugin will be included in the result jar of - the target. - */ - .add( - attr("plugins", LABEL_LIST) - .cfg(ExecutionTransitionFactory.createFactory()) - .mandatoryProviders(JavaPluginInfo.PROVIDER.id()) - .legacyAllowAnyFileType()) - .add( - attr(":java_plugins", LABEL_LIST) - .cfg(ExecutionTransitionFactory.createFactory()) - .mandatoryProviders(JavaPluginInfo.PROVIDER.id()) - .silentRuleClassFilter() - .value(JavaSemantics.JAVA_PLUGINS)) - /* - Extra compiler options for this target. - Subject to "Make variable" substitution and - Bourne shell tokenization. -

- These compiler options are passed to javac after the global compiler options.

- */ - .add(attr("javacopts", STRING_LIST)) - .add( - attr("$idlclass", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:IdlClass"))) - .add( - attr("$desugar_java8_extra_bootclasspath", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value(env.getToolsLabel("//tools/android:desugar_java8_extra_bootclasspath"))) - .add( - attr("$android_resources_busybox", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel(DEFAULT_RESOURCES_BUSYBOX))) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("$android_base") - .type(RuleClassType.ABSTRACT) - .ancestors(BaseRuleClasses.NativeActionCreatingRule.class) - .build(); - } - } - - /** Base class for Android rule definitions that produce binaries. */ - public static final class AndroidBinaryBaseRule implements RuleDefinition { - - private final AndroidNeverlinkAspect androidNeverlinkAspect; - private final DexArchiveAspect dexArchiveAspect; - - public AndroidBinaryBaseRule( - AndroidNeverlinkAspect androidNeverlinkAspect, DexArchiveAspect dexArchiveAspect) { - this.androidNeverlinkAspect = androidNeverlinkAspect; - this.dexArchiveAspect = dexArchiveAspect; - } - - @Override - public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { - return builder - .requiresConfigurationFragments( - AndroidConfiguration.class, JavaConfiguration.class, CppConfiguration.class) - /* - The list of source files that are processed to create the target. -

srcs files of type .java are compiled. - For readability's sake, it is not good to put the name of a - generated .java source file into the srcs. - Instead, put the depended-on rule name in the srcs, as - described below. -

-

srcs files of type .srcjar are unpacked and - compiled. (This is useful if you need to generate a set of .java files with - a genrule or build extension.) -

- */ - .add( - attr("srcs", LABEL_LIST) - .direct_compile_time_input() - .allowedFileTypes(JavaSemantics.JAVA_SOURCE, JavaSemantics.SOURCE_JAR)) - // manifest is required for android_binary to ensure that we have an Android package. - .override(builder.copy("manifest").mandatory()) - /* - The list of other libraries to be linked in to the binary target. - Permitted library types are: android_library, - java_library with android constraint and - cc_library wrapping or producing .so native libraries for the - Android target platform. - */ - .override( - builder - .copy("deps") - .cfg(AndroidSplitTransition.FACTORY) - .allowedRuleClasses(ALLOWED_DEPENDENCIES) - .allowedFileTypes() - .mandatoryProviders(CONTAINS_CC_INFO_PARAMS) - .mandatoryProviders(JavaRuleClasses.CONTAINS_JAVA_PROVIDER) - .mandatoryProviders( - StarlarkProviderIdentifier.forKey(AndroidResourcesInfo.PROVIDER.getKey()), - StarlarkProviderIdentifier.forKey(AndroidAssetsInfo.PROVIDER.getKey())) - .aspect(androidNeverlinkAspect) - .aspect(dexArchiveAspect, DexArchiveAspect.PARAM_EXTRACTOR)) - /* - File containing the debug keystore to be used to sign the debug apk. Usually you do not - want to use a key other than the default key, so this attribute should be omitted. -

WARNING: Do not use your production keys, they should be - strictly safeguarded and not kept in your source tree.

- */ - .add( - attr("debug_key", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .legacyAllowAnyFileType() - .value(env.getToolsLabel("//tools/android:debug_keystore"))) - /* - List of files, debug keystores to be used to sign the debug apk. Usually you do not - want to use keys other than the default key, so this attribute should be omitted. -

WARNING: Do not use your production keys, they should be - strictly safeguarded and not kept in your source tree.

- */ - .add( - attr("debug_signing_keys", LABEL_LIST) - .cfg(ExecutionTransitionFactory.createFactory()) - .legacyAllowAnyFileType()) - /* - File containing the signing lineage for the debug_signing_keys. Usually you do not - want to use keys other than the default key, so this attribute should be omitted. -

WARNING: Do not use your production keys, they should be - strictly safeguarded and not kept in your source tree.

- */ - .add( - attr("debug_signing_lineage_file", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .legacyAllowAnyFileType()) - /* - Sets the minimum Android platform version (API Level) for which an APK's rotated signing - key should be used to produce the APK's signature. The original signing key for the APK - will be used for all previous platform versions. - */ - .add(attr("key_rotation_min_sdk", STRING)) - /* - A list of file extension to leave uncompressed in apk. - */ - .add(attr("nocompress_extensions", STRING_LIST)) - /* - Do PNG crunching (or not). This is independent of nine-patch processing, which is always - done. This is a deprecated workaround for an - aapt bug which has - been fixed in aapt2. - */ - .add(attr("crunch_png", BOOLEAN).value(true)) - /* - A list of resource configuration filters, such 'en' that will limit the resources in the - apk to only the ones in the 'en' configuration. To enable pseudolocalization, include the - en_XA and/or ar_XB pseudo-locales. - */ - .add(attr(ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME, STRING_LIST)) - /* - The minSdkVersion. This must match the minSdkVersion specified in the AndroidManifest.xml. - If set, will be used for dex/desugaring. - */ - .add( - attr("min_sdk_version", INTEGER) - .undocumented("experimental") - .value(StarlarkInt.of(0)) - .nonconfigurable("AspectParameters don't support configurations.")) - /* - Whether to perform resource shrinking. Resources that are not used by the binary will be - removed from the APK. This is only supported for rules using local resources (i.e. the - manifest and resource_files attributes) and requires ProGuard. - It operates in mostly the same manner as the Gradle resource shrinker - (https://developer.android.com/studio/build/shrink-code.html#shrink-resources). -

Notable differences: -

    -
  • resources in values/ will be removed as well as file based - resources
  • -
  • uses strict mode by default
  • -
  • removing unused ID resources is only supported with aapt2
  • -
- If resource shrinking is enabled, name_files/resource_shrinker.log - will also be generated, detailing the analysis and deletions performed. -

Possible values: -

    -
  • shrink_resources = 1: Turns on Android resource shrinking
  • -
  • shrink_resources = 0: Turns off Android resource shrinking
  • -
  • shrink_resources = -1: Shrinking is controlled by the - - --android_resource_shrinking flag.
  • -
- */ - .add(attr("shrink_resources", TRISTATE).value(TriState.AUTO)) - /* - Densities to filter for when building the apk. - This will strip out raster drawable resources that would not be loaded by a device with - the specified screen densities, to reduce APK size. A corresponding compatible-screens - section will also be added to the manifest if it does not already contain a superset - listing. - */ - .add(attr(ResourceFilterFactory.DENSITIES_NAME, STRING_LIST)) - .add( - attr("$shuffle_jars", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:shuffle_jars"))) - .add( - attr("$dexbuilder", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:dexbuilder"))) - .add( - attr("$dexbuilder_after_proguard", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:dexbuilder_after_proguard"))) - .add( - attr("$dexsharder", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:dexsharder"))) - .add( - attr("$dexmerger", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:dexmerger"))) - .add( - attr("$merge_dexzips", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:merge_dexzips"))) - .add( - attr("$desugar", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:desugar_java8"))) - .add( - attr("$java8_legacy_dex", LABEL) - .value(env.getToolsLabel("//tools/android:java8_legacy_dex"))) - .add( - attr("$build_java8_legacy_dex", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:build_java8_legacy_dex"))) - .add( - attr("$desugared_java8_legacy_apis", LABEL) - .value(env.getToolsLabel("//tools/android:desugared_java8_legacy_apis"))) - .add( - attr("$merge_proguard_maps", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:merge_proguard_maps"))) - /* - Additional command-line flags for the dx tool when generating classes.dex. - Subject to "Make variable" substitution and - Bourne shell tokenization. - */ - .add(attr("dexopts", STRING_LIST)) - /* - Number of shards dexing should be decomposed into. - This is makes dexing much faster at the expense of app installation and startup time. The - larger the binary, the more shards should be used. 25 is a good value to start - experimenting with. -

- Note that each shard will result in at least one dex in the final app. For this reason, - setting this to more than 1 is not recommended for release binaries. - */ - .add(attr("dex_shards", INTEGER).value(StarlarkInt.of(1))) - /* - Force the target to be built with or without incremental dexing, overriding defaults - and --incremental_dexing flag. - */ - .add( - attr("incremental_dexing", TRISTATE) - // Read by DexArchiveAspect's attribute extractor - .nonconfigurable("AspectParameters don't support configurations.")) - /* - Whether to split code into multiple dex files.
- Possible values: -

    -
  • native: Split code into multiple dex files when the dex 64K index limit - is exceeded. Assumes native platform support for loading multidex classes at runtime. - This works with only Android L and newer.
  • -
  • legacy: Split code into multiple dex files when the dex 64K index limit - is exceeded. Assumes multidex classes are loaded through application code (i.e. no - native platform support).
  • -
  • manual_main_dex: Split code into multiple dex files when the dex 64K - index limit is exceeded. The content of the main dex file needs to be specified by - providing a list of classes in a text file using the - main_dex_list attribute.
  • -
  • off: Compile all code to a single dex file, even if it exceeds the - index limit.
  • -
- */ - .add( - attr("multidex", STRING) - .allowedValues(new AllowedValueSet(MultidexMode.getValidValues())) - .value(MultidexMode.NATIVE.getAttributeValue())) - /* - Command line options to pass to the main dex list builder. - Use this option to affect the classes included in the main dex list. - */ - .add(attr("main_dex_list_opts", STRING_LIST)) - /* - - A text file contains a list of class file names. Classes defined by those class files are - put in the primary classes.dex. e.g.:
-          android/support/multidex/MultiDex$V19.class
-          android/support/multidex/MultiDex.class
-          android/support/multidex/MultiDexApplication.class
-          com/google/common/base/Objects.class
-                    
- Must be used with multidex="manual_main_dex". - */ - .add(attr("main_dex_list", LABEL).legacyAllowAnyFileType()) - /* - Files to be used as the Proguard specifications to determine classes that must be kept in - the main dex. - Only allowed if the multidex attribute is set to legacy. - */ - .add(attr("main_dex_proguard_specs", LABEL_LIST).legacyAllowAnyFileType()) - /* - Files to be used as Proguard specification. - This file will describe the set of specifications to be used by Proguard. - */ - .add(attr("proguard_specs", LABEL_LIST).legacyAllowAnyFileType()) - /* - Whether to generate Proguard mapping file. - The mapping file will be generated only if proguard_specs is - specified. This file will list the mapping between the original and - obfuscated class, method, and field names. -

WARNING: If this attribute is used, the Proguard - specification should contain neither -dontobfuscate nor - -printmapping.

- */ - .add( - attr("proguard_generate_mapping", BOOLEAN) - .value(false) - .nonconfigurable("value is referenced in an ImplicitOutputsFunction")) - /* - File to be used as a mapping for proguard. - A mapping file generated by proguard_generate_mapping to be - re-used to apply the same mapping to a new build. - */ - .add(attr("proguard_apply_mapping", LABEL).legacyAllowAnyFileType()) - /* - File to be used as a mapping for proguard. - A line separated file of "words" to pull from when renaming classes and members during - obfuscation. - */ - .add(attr("proguard_apply_dictionary", LABEL).legacyAllowAnyFileType()) - .add( - attr("$dex_list_obfuscator", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:dex_list_obfuscator"))) - .add( - attr(":bytecode_optimizer", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value(AndroidSemantics.BYTECODE_OPTIMIZER)) - // We need the C++ toolchain for every sub-configuration to get the correct linker. - .add( - attr("$cc_toolchain_split", LABEL) - .cfg(AndroidSplitTransition.FACTORY) - .value(env.getToolsLabel("//tools/cpp:current_cc_toolchain"))) - /* - A dictionary of values to be overridden in the manifest. -

- Any instance of ${name} in the manifest will be replaced with the value - corresponding to name in this dictionary. -

- applicationId, versionCode, versionName, - minSdkVersion, targetSdkVersion and - maxSdkVersion will also override the corresponding attributes in the manifest - and uses-sdk tags. -

- packageName will be ignored and will be set from either - applicationId if specified or the package in manifest. -

- When manifest_merger is set to legacy, only - applicationId, versionCode and versionName will - have any effect. - */ - .add(attr("manifest_values", STRING_DICT)) - .add( - attr(AndroidFeatureFlagSetProvider.FEATURE_FLAG_ATTR, LABEL_KEYED_STRING_DICT) - .undocumented("the feature flag feature has not yet been launched") - .allowedRuleClasses("config_feature_flag") - .allowedFileTypes() - .nonconfigurable("defines an aspect of configuration") - .mandatoryProviders(ImmutableList.of(ConfigFeatureFlagProvider.id()))) - .add(AndroidFeatureFlagSetProvider.getAllowlistAttribute(env)) - .addAllowlistChecker(AndroidFeatureFlagSetProvider.CHECK_ALLOWLIST_IF_TRIGGERED) - // The resource extractor is used at the binary level to extract java resources from the - // deploy jar so that they can be added to the APK. - .add( - attr("$resource_extractor", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:resource_extractor"))) - /* -

The android_binary target to instrument.

-

If this attribute is set, this android_binary will be treated as a test - application for instrumentation tests. An android_instrumentation_test - target can then specify this target in its - test_app attribute. - */ - .add( - attr("instruments", LABEL) - .allowedRuleClasses("android_binary") - .allowedFileTypes(NO_FILE)) - .add( - attr("$instrumentation_test_check", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value( - new Attribute.ComputedDefault() { - @Override - @Nullable - public Object getDefault(AttributeMap rule) { - return rule.isAttributeValueExplicitlySpecified("instruments") - ? env.getToolsLabel("//tools/android:instrumentation_test_check") - : null; - } - }) - .exec()) - .add( - attr("$zip_filter", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value(env.getToolsLabel("//tools/android:zip_filter"))) - /* - Package ID to be assigned to resources in this binary. -

See AAPT2's --package-id argument for more information. This can (and - should) typically be left unset, resulting in the default value of 127 - (0x7F). - */ - // This is only implemented in Starlark, but is present here for doc generation. - .add(attr("package_id", INTEGER)) - .add( - attr("application_resources", LABEL) - .mandatoryProviders(AndroidApplicationResourceInfo.PROVIDER.id()) - .allowedFileTypes(NO_FILE) - .undocumented( - "Do not use this attribute. It's for the migration of " - + "Android resource processing to Starlark only.") - .aspect(androidNeverlinkAspect) - .aspect(dexArchiveAspect, DexArchiveAspect.PARAM_EXTRACTOR)) - // Nothing in the native rule reads this. This is only for facilitating the Starlark - // migration of the android rules. - .add(attr("stamp", TRISTATE).value(TriState.AUTO)) - // This comes from the --legacy_main_dex_list_generator flag. - .add( - attr(":legacy_main_dex_list_generator", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value(LEGACY_MAIN_DEX_LIST_GENERATOR) - .exec()) - // This comes from the --optimizing_dexer flag. - .add( - attr(":optimizing_dexer", LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .value(OPTIMIZING_DEXER) - .exec()) - .removeAttribute("data") - .advertiseStarlarkProvider(StarlarkProviderIdentifier.forKey(ApkInfo.PROVIDER.getKey())) - .advertiseStarlarkProvider(StarlarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey())) - .build(); - } - - @Override - public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() - .name("$android_binary_base") - .type(RuleClassType.ABSTRACT) - .ancestors(AndroidResourceSupportRule.class) - .build(); - } - } - - /** Semantic options for the dexer's multidex behavior. */ - public enum MultidexMode { - // Build dexes with multidex, assuming native platform support for multidex. - NATIVE, - // Build dexes with multidex and implement support at the application level. - LEGACY, - // Build dexes with multidex, main dex list needs to be manually specified. - MANUAL_MAIN_DEX; - - /** Returns the attribute value that specifies this mode. */ - public String getAttributeValue() { - return toString().toLowerCase(); - } - - /** - * Returns the name of the output dex classes file. In multidex mode, this is an archive of - * (possibly) multiple files. - */ - public String getOutputDexFilename() { - return "classes.dex.zip"; - } - - /** Converts an attribute value to a corresponding mode. Returns null on no match. */ - @Nullable - public static MultidexMode fromValue(String value) { - for (MultidexMode mode : values()) { - if (mode.getAttributeValue().equals(value)) { - return mode; - } - } - return null; - } - - /** Enumerates valid values for the "multidex" attribute. */ - public static List getValidValues() { - List ans = Lists.newArrayList(); - for (MultidexMode mode : MultidexMode.values()) { - ans.add(mode.getAttributeValue()); - } - return ans; - } - } - /** Definition of the {@code android_tools_defaults_jar} rule. */ public static final class AndroidBaseToolsDefaultsJarRule implements RuleDefinition { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java index 8262e5f7be5a79..f812379fbdd74b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java @@ -13,26 +13,15 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; -import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; -import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault; -import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.Types; -import com.google.devtools.build.lib.rules.android.ProguardHelper.ProguardOutput; -import com.google.devtools.build.lib.rules.java.BootClassPathInfo; -import com.google.devtools.build.lib.rules.java.JavaCommon; import com.google.devtools.build.lib.rules.java.JavaConfiguration; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; import java.util.Map; import java.util.Optional; @@ -44,20 +33,6 @@ * to keep state. */ public interface AndroidSemantics { - - SafeImplicitOutputsFunction ANDROID_BINARY_CLASS_JAR = fromTemplates("%{name}.jar"); - SafeImplicitOutputsFunction ANDROID_BINARY_SOURCE_JAR = fromTemplates("%{name}-src.jar"); - SafeImplicitOutputsFunction ANDROID_BINARY_DEPLOY_JAR = fromTemplates("%{name}_deploy.jar"); - SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_MAP = fromTemplates("%{name}_proguard.map"); - SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_PROTO_MAP = - fromTemplates("%{name}_proguard.pbmap"); - SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_SEEDS = - fromTemplates("%{name}_proguard.seeds"); - SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_USAGE = - fromTemplates("%{name}_proguard.usage"); - SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_CONFIG = - fromTemplates("%{name}_proguard.config"); - /** Implementation for the :proguard attribute. */ @SerializationConstant LabelLateBoundDefault PROGUARD = @@ -66,24 +41,6 @@ public interface AndroidSemantics { null, (rule, attributes, javaConfig) -> javaConfig.getProguardBinary()); - @SerializationConstant - LabelLateBoundDefault BYTECODE_OPTIMIZER = - LabelLateBoundDefault.fromTargetConfiguration( - JavaConfiguration.class, - null, - (rule, attributes, javaConfig) -> { - // Use a modicum of smarts to avoid implicit dependencies where we don't need them. - boolean hasProguardSpecs = - attributes.has("proguard_specs") - && !attributes.get("proguard_specs", LABEL_LIST).isEmpty(); - JavaConfiguration.NamedLabel optimizer = javaConfig.getBytecodeOptimizer(); - if ((!hasProguardSpecs && !javaConfig.runLocalJavaOptimizations()) - || !optimizer.label().isPresent()) { - return null; - } - return optimizer.label().get(); - }); - default AndroidManifest renameManifest( AndroidDataContext dataContext, AndroidManifest rawManifest) throws InterruptedException { return rawManifest.renameManifestIfNeeded(dataContext); @@ -113,86 +70,6 @@ default Optional maybeDoLegacyManifestMerging( ImmutableList getCompatibleJavacOptions(RuleContext ruleContext) throws RuleErrorException; - /** - * Configures the builder for generating the output jar used to configure the main dex file. - * - * @throws InterruptedException - */ - void addMainDexListActionArguments( - RuleContext ruleContext, - SpawnAction.Builder builder, - CustomCommandLine.Builder commandLine, - Artifact proguardMap) - throws InterruptedException; - - /** Given an Android {@code manifest}, returns a list of relevant Proguard specs. */ - ImmutableList getProguardSpecsForManifest( - AndroidDataContext dataContext, Artifact manifest); - - /** - * Add coverage instrumentation to the Java compilation of an Android binary. - * - * @throws InterruptedException - */ - void addCoverageSupport( - RuleContext ruleContext, boolean forAndroidTest, JavaTargetAttributes.Builder attributes) - throws InterruptedException; - - /** Returns the list of attributes that may contribute Java runtime dependencies. */ - ImmutableList getAttributesWithJavaRuntimeDeps(RuleContext ruleContext); - - /** A hook for checks of internal-only or external-only attributes of {@code android_binary}. */ - default void validateAndroidBinaryRuleContext(RuleContext ruleContext) - throws RuleErrorException {} - - /** A hook for checks of internal-only or external-only attributes of {@code android_library}. */ - default void validateAndroidLibraryRuleContext(RuleContext ruleContext) - throws RuleErrorException {} - - /** The artifact for the map that proguard will output. */ - Artifact getProguardOutputMap(RuleContext ruleContext) throws InterruptedException; - - /** The artifact for ART profile information. */ - Artifact getArtProfileForApk( - RuleContext ruleContext, - Artifact finalClassesDex, - Artifact proguardOutputMap, - String baselineProfileDir); - - /** The merged baseline profiles from the {@code baseline_profiles} attribute. */ - Artifact mergeBaselineProfiles( - RuleContext ruleContext, String baselineProfileDir, boolean includeStartupProfiles); - - /** The merged startup profiles from the {@code startup_profiles} attribute. */ - Artifact mergeStartupProfiles(RuleContext ruleContext, String baselineProfileDir); - - /** Expands any wildcards present in a baseline profile, and returns the new expanded artifact. */ - public Artifact expandBaselineProfileWildcards( - RuleContext ruleContext, - Artifact deployJar, - Artifact mergedStaticProfile, - String baselineProfileDir); - - /** The artifact for ART profile information, given a particular merged profile. */ - Artifact compileBaselineProfile( - RuleContext ruleContext, - Artifact finalClassesDex, - Artifact proguardOutputMap, - Artifact mergedStaticProfile, - String baselineProfileDir); - - boolean postprocessClassesRewritesMap(RuleContext ruleContext); - - /** Maybe post process the dex files and proguard output map. */ - AndroidBinary.DexPostprocessingOutput postprocessClassesDexZip( - RuleContext ruleContext, - NestedSetBuilder filesBuilder, - Artifact classesDexZip, - ProguardOutput proguardOutput, - Artifact proguardMapOutput, - Artifact mainDexList) - throws InterruptedException; - default AndroidDataContext makeContextForNative(RuleContext ruleContext) throws RuleErrorException { return AndroidDataContext.forNative(ruleContext); @@ -219,49 +96,4 @@ default void checkForMigrationTag(RuleContext ruleContext) throws RuleErrorExcep /** Executes a ruleContext.attributeError when the check for the migration tag fails. */ void registerMigrationRuleError(RuleContext ruleContext) throws RuleErrorException; - - /** - * Whether invoking apksigner, whether or not to pass it flags to make DSA signing be - * deterministic. - */ - default boolean deterministicSigning() { - return false; - } - - default BootClassPathInfo getBootClassPathInfo(RuleContext ruleContext) - throws RuleErrorException, InterruptedException { - BootClassPathInfo bootClassPathInfo; - AndroidSdkProvider androidSdkProvider = AndroidSdkProvider.fromRuleContext(ruleContext); - if (androidSdkProvider.getSystem() != null) { - bootClassPathInfo = androidSdkProvider.getSystem(); - } else { - NestedSetBuilder bootclasspath = NestedSetBuilder.stableOrder(); - if (ruleContext.getConfiguration().getFragment(AndroidConfiguration.class).desugarJava8()) { - bootclasspath.addTransitive( - PrerequisiteArtifacts.nestedSet( - ruleContext.getRulePrerequisitesCollection(), - "$desugar_java8_extra_bootclasspath")); - } - bootclasspath.add(androidSdkProvider.getAndroidJar()); - bootClassPathInfo = BootClassPathInfo.create(ruleContext, bootclasspath.build()); - } - return bootClassPathInfo; - } - - /** - * Returns an artifact representing the protobuf-format version of the proguard mapping, or null - * if the proguard version doesn't support this. - */ - Artifact getProtoMapping(RuleContext ruleContext) throws InterruptedException; - - Artifact getObfuscatedConstantStringMap(RuleContext ruleContext) throws InterruptedException; - - /** - * Verifies if the rule contains any errors. - * - *

Errors should be signaled through {@link RuleContext}. - */ - void checkRule(RuleContext ruleContext, JavaCommon javaCommon) throws RuleErrorException; - - String getTestRunnerMainClass(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApkActionsBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApkActionsBuilder.java deleted file mode 100644 index 34bcc3a06d4177..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ApkActionsBuilder.java +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.packages.Types; -import com.google.devtools.build.lib.rules.android.AndroidConfiguration.ApkSigningMethod; -import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.util.List; - -/** - * A class for coordinating APK building, signing and zipaligning. - * - *

It is not always necessary to zip align APKs, for instance if the APK does not contain - * resources. Furthermore, we do not always care about the unsigned apk because it cannot be - * installed on a device until it is signed. - */ -public class ApkActionsBuilder { - private Artifact classesDex; - private ImmutableList.Builder inputZips = new ImmutableList.Builder<>(); - private Artifact javaResourceZip; - private FilesToRunProvider resourceExtractor; - private Artifact javaResourceFile; - private NativeLibs nativeLibs = NativeLibs.EMPTY; - private Artifact unsignedApk; - private Artifact signedApk; - private boolean zipalignApk = false; - private List signingKeys; - private Artifact signingLineage; - private String artifactLocation; - private Artifact v4SignatureFile; - private boolean deterministicSigning; - private String signingKeyRotationMinSdk; - - private final String apkName; - - public static ApkActionsBuilder create(String apkName) { - return new ApkActionsBuilder(apkName); - } - - private ApkActionsBuilder(String apkName) { - this.apkName = apkName; - } - - /** Sets the native libraries to be included in the APK. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setNativeLibs(NativeLibs nativeLibs) { - this.nativeLibs = nativeLibs; - return this; - } - - /** - * Sets the dex file to be included in the APK. - * - *

Can be either a plain classes.dex or a .zip file containing dexes. - */ - @CanIgnoreReturnValue - public ApkActionsBuilder setClassesDex(Artifact classesDex) { - Preconditions.checkArgument( - classesDex == null - || classesDex.getFilename().endsWith(".zip") - || classesDex.getFilename().equals("classes.dex")); - this.classesDex = classesDex; - return this; - } - - /** Add a zip file that should be copied as is into the APK. */ - @CanIgnoreReturnValue - public ApkActionsBuilder addInputZip(Artifact inputZip) { - this.inputZips.add(inputZip); - return this; - } - - @CanIgnoreReturnValue - public ApkActionsBuilder addInputZips(Iterable inputZips) { - this.inputZips.addAll(inputZips); - return this; - } - - /** - * Adds a zip to be added to the APK and an executable that filters the zip to extract the - * relevant contents first. - */ - @CanIgnoreReturnValue - public ApkActionsBuilder setJavaResourceZip( - Artifact javaResourceZip, FilesToRunProvider resourceExtractor) { - this.javaResourceZip = javaResourceZip; - this.resourceExtractor = resourceExtractor; - return this; - } - - /** - * Adds an individual resource file to the root directory of the APK. - * - *

This provides the same functionality as {@code javaResourceZip}, except much more hacky. - * Will most probably won't work if there is an input artifact in the same directory as this file. - */ - @CanIgnoreReturnValue - public ApkActionsBuilder setJavaResourceFile(Artifact javaResourceFile) { - this.javaResourceFile = javaResourceFile; - return this; - } - - /** Requests an unsigned APK be built at the specified artifact. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setUnsignedApk(Artifact unsignedApk) { - this.unsignedApk = unsignedApk; - return this; - } - - /** Requests a signed APK be built at the specified artifact. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setSignedApk(Artifact signedApk) { - this.signedApk = signedApk; - return this; - } - - @CanIgnoreReturnValue - public ApkActionsBuilder setV4Signature(Artifact v4SignatureFile) { - this.v4SignatureFile = v4SignatureFile; - return this; - } - - /** Requests that signed APKs are zipaligned. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setZipalignApk(boolean zipalign) { - this.zipalignApk = zipalign; - return this; - } - - /** Sets the signing keys that will be used to sign the APK. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setSigningKeys(List signingKeys) { - this.signingKeys = signingKeys; - return this; - } - - /** Sets the signing lineage file used to sign the APK. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setSigningLineageFile(Artifact signingLineage) { - this.signingLineage = signingLineage; - return this; - } - - @CanIgnoreReturnValue - public ApkActionsBuilder setSigningKeyRotationMinSdk(String minSdk) { - this.signingKeyRotationMinSdk = minSdk; - return this; - } - - /** Sets the output APK instead of creating with a static/standard path. */ - @CanIgnoreReturnValue - public ApkActionsBuilder setArtifactLocationDirectory(String artifactLocation) { - this.artifactLocation = artifactLocation; - return this; - } - - @CanIgnoreReturnValue - public ApkActionsBuilder setDeterministicSigning(boolean deterministicSigning) { - this.deterministicSigning = deterministicSigning; - return this; - } - - /** Registers the actions needed to build the requested APKs in the rule context. */ - public void registerActions(RuleContext ruleContext) - throws InterruptedException, RuleErrorException { - // If the caller did not request an unsigned APK, we still need to construct one so that - // we can sign it. So we make up an intermediate artifact. - Artifact intermediateUnsignedApk = - unsignedApk != null - ? unsignedApk - : getApkArtifact(ruleContext, "unsigned_" + signedApk.getFilename()); - buildApk(ruleContext, intermediateUnsignedApk); - - if (signedApk != null) { - Artifact apkToSign = intermediateUnsignedApk; - // Zipalignment is performed before signing. So if a zipaligned APK is requested, we need an - // intermediate zipaligned-but-not-signed apk artifact. - if (zipalignApk) { - apkToSign = getApkArtifact(ruleContext, "zipaligned_" + signedApk.getFilename()); - zipalignApk(ruleContext, intermediateUnsignedApk, apkToSign); - } - signApk(ruleContext, apkToSign, signedApk); - } - } - - /** Appends the --output_jar_creator flag to the singlejar command line. */ - private void setSingleJarCreatedBy(RuleContext ruleContext, CustomCommandLine.Builder builder) { - if (ruleContext.getConfiguration().getFragment(BazelAndroidConfiguration.class) != null) { - // Only enabled for Bazel, not Blaze. - builder.add("--output_jar_creator"); - builder.add("Bazel"); - } - } - - /** Registers generating actions for {@code outApk} that build an unsigned APK using SingleJar. */ - private void buildApk(RuleContext ruleContext, Artifact outApk) - throws InterruptedException, RuleErrorException { - Artifact compressedApk = getApkArtifact(ruleContext, "compressed_" + outApk.getFilename()); - - SpawnAction.Builder compressedApkActionBuilder = - createSpawnActionBuilder(ruleContext) - .setMnemonic("ApkBuilder") - .setProgressMessage("Generating unsigned %s", apkName) - .addOutput(compressedApk); - CustomCommandLine.Builder compressedApkCommandLine = - CustomCommandLine.builder() - .add("--exclude_build_data") - .add("--compression") - .add("--normalize") - .addExecPath("--output", compressedApk); - setSingleJarCreatedBy(ruleContext, compressedApkCommandLine); - setSingleJarAsExecutable(ruleContext, compressedApkActionBuilder); - - if (classesDex != null) { - compressedApkActionBuilder.addInput(classesDex); - if (classesDex.getFilename().endsWith(".zip")) { - compressedApkCommandLine.addExecPath("--sources", classesDex); - } else { - compressedApkCommandLine - .add("--resources") - .addFormatted("%s:%s", classesDex, classesDex.getFilename()); - } - } - - if (javaResourceFile != null) { - compressedApkActionBuilder.addInput(javaResourceFile); - compressedApkCommandLine - .add("--resources") - .addFormatted("%s:%s", javaResourceFile, javaResourceFile.getFilename()); - } - - for (String architecture : nativeLibs.getMap().keySet()) { - for (Artifact nativeLib : nativeLibs.getMap().get(architecture).toList()) { - compressedApkActionBuilder.addInput(nativeLib); - compressedApkCommandLine - .add("--resources") - .addFormatted("%s:lib/%s/%s", nativeLib, architecture, nativeLib.getFilename()); - } - } - - SpawnAction.Builder singleJarActionBuilder = - createSpawnActionBuilder(ruleContext) - .setMnemonic("ApkBuilder") - .setProgressMessage("Generating unsigned %s", apkName) - .addInput(compressedApk) - .addOutput(outApk); - CustomCommandLine.Builder singleJarCommandLine = CustomCommandLine.builder(); - singleJarCommandLine - .add("--exclude_build_data") - .add("--dont_change_compression") - .add("--normalize") - .addExecPath("--sources", compressedApk) - .addExecPath("--output", outApk); - setSingleJarCreatedBy(ruleContext, singleJarCommandLine); - setSingleJarAsExecutable(ruleContext, singleJarActionBuilder); - - if (javaResourceZip != null) { - // The javaResourceZip contains many files that are unwanted in the APK such as .class files. - Artifact extractedJavaResourceZip = - getApkArtifact(ruleContext, "extracted_" + javaResourceZip.getFilename()); - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .setExecutable(resourceExtractor) - .setMnemonic("ResourceExtractor") - .setProgressMessage("Extracting Java resources from deploy jar for %s", apkName) - .addInput(javaResourceZip) - .addOutput(extractedJavaResourceZip) - .addCommandLine( - CustomCommandLine.builder() - .addExecPath(javaResourceZip) - .addExecPath(extractedJavaResourceZip) - .build()) - .useDefaultShellEnvironment() - .build(ruleContext)); - - if (ruleContext.getFragment(AndroidConfiguration.class).compressJavaResources()) { - compressedApkActionBuilder.addInput(extractedJavaResourceZip); - compressedApkCommandLine.addExecPath("--sources", extractedJavaResourceZip); - } else { - singleJarActionBuilder.addInput(extractedJavaResourceZip); - singleJarCommandLine.addExecPath("--sources", extractedJavaResourceZip); - } - } - - if (nativeLibs.getName() != null) { - singleJarActionBuilder.addInput(nativeLibs.getName()); - singleJarCommandLine - .add("--resources") - .addFormatted("%s:%s", nativeLibs.getName(), nativeLibs.getName().getFilename()); - } - - for (Artifact inputZip : inputZips.build()) { - singleJarActionBuilder.addInput(inputZip); - singleJarCommandLine.addExecPath("--sources", inputZip); - } - - List noCompressExtensions; - if (ruleContext - .getRule() - .isAttrDefined(AndroidRuleClasses.NOCOMPRESS_EXTENSIONS_ATTR, Types.STRING_LIST)) { - noCompressExtensions = - ruleContext - .getExpander() - .withDataLocations() - .tokenized(AndroidRuleClasses.NOCOMPRESS_EXTENSIONS_ATTR); - } else { - // This code is also used by android_test, which doesn't have this attribute. - noCompressExtensions = ImmutableList.of(); - } - if (!noCompressExtensions.isEmpty()) { - compressedApkCommandLine.addAll("--nocompress_suffixes", noCompressExtensions); - singleJarCommandLine.addAll("--nocompress_suffixes", noCompressExtensions); - } - - compressedApkActionBuilder.addCommandLine(compressedApkCommandLine.build()); - ruleContext.registerAction(compressedApkActionBuilder.build(ruleContext)); - singleJarActionBuilder.addCommandLine(singleJarCommandLine.build()); - ruleContext.registerAction(singleJarActionBuilder.build(ruleContext)); - } - - /** Uses the zipalign tool to align the zip boundaries for uncompressed resources by 4 bytes. */ - private void zipalignApk(RuleContext ruleContext, Artifact inputApk, Artifact zipAlignedApk) - throws RuleErrorException { - ruleContext.registerAction( - createSpawnActionBuilder(ruleContext) - .addInput(inputApk) - .addOutput(zipAlignedApk) - .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getZipalign()) - .setProgressMessage("Zipaligning %s", apkName) - .setMnemonic("AndroidZipAlign") - .addInput(inputApk) - .addOutput(zipAlignedApk) - .addCommandLine( - CustomCommandLine.builder() - .add("-p") // memory page aligment for stored shared object files - .add("4") - .addExecPath(inputApk) - .addExecPath(zipAlignedApk) - .build()) - .build(ruleContext)); - } - - /** - * Signs an APK using the ApkSignerTool. Supports both the jar signing scheme(v1) and the apk - * signing scheme v2. Note that zip alignment is preserved by this step. Furthermore, zip - * alignment cannot be performed after v2 signing without invalidating the signature. - */ - private void signApk( - RuleContext ruleContext, Artifact unsignedApk, Artifact signedAndZipalignedApk) - throws RuleErrorException { - ApkSigningMethod signingMethod = - ruleContext.getFragment(AndroidConfiguration.class).getApkSigningMethod(); - SpawnAction.Builder actionBuilder = - createSpawnActionBuilder(ruleContext) - .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getApkSigner()) - .setProgressMessage("Signing %s", apkName) - .setMnemonic("ApkSignerTool") - .addOutput(signedAndZipalignedApk) - .addInput(unsignedApk); - CustomCommandLine.Builder commandLine = CustomCommandLine.builder().add("sign"); - actionBuilder.addInputs(signingKeys); - if (signingLineage != null) { - actionBuilder.addInput(signingLineage); - commandLine.add("--lineage").addExecPath(signingLineage); - } - - if (deterministicSigning) { - // Enable deterministic DSA signing to keep the output of apksigner deterministic. - // This requires including BouncyCastleProvider as a Security provider, since the standard - // JDK Security providers do not include support for deterministic DSA signing. - // Since this adds BouncyCastleProvider to the end of the Provider list, any non-DSA signing - // algorithms (such as RSA) invoked by apksigner will still use the standard JDK - // implementations and not Bouncy Castle. - commandLine.add("--deterministic-dsa-signing", "true"); - commandLine.add("--provider-class", "org.bouncycastle.jce.provider.BouncyCastleProvider"); - } - - for (int i = 0; i < signingKeys.size(); i++) { - if (i > 0) { - commandLine.add("--next-signer"); - } - commandLine.add("--ks").addExecPath(signingKeys.get(i)).add("--ks-pass", "pass:android"); - } - commandLine - .add("--v1-signing-enabled", Boolean.toString(signingMethod.signV1())) - .add("--v1-signer-name", "CERT") - .add("--v2-signing-enabled", Boolean.toString(signingMethod.signV2())); - if (signingMethod.signV4() != null) { - commandLine.add("--v4-signing-enabled", Boolean.toString(signingMethod.signV4())); - } - if (!Strings.isNullOrEmpty(signingKeyRotationMinSdk)) { - commandLine.add("--rotation-min-sdk-version", signingKeyRotationMinSdk); - } - commandLine.add("--out").addExecPath(signedAndZipalignedApk).addExecPath(unsignedApk); - - if (v4SignatureFile != null) { - actionBuilder.addOutput(v4SignatureFile); - } - ruleContext.registerAction( - actionBuilder.addCommandLine(commandLine.build()).build(ruleContext)); - } - - private static void setSingleJarAsExecutable(RuleContext ruleContext, SpawnAction.Builder builder) - throws RuleErrorException { - FilesToRunProvider singleJar = JavaToolchainProvider.from(ruleContext).getSingleJar(); - builder.setExecutable(singleJar); - } - - private Artifact getApkArtifact(RuleContext ruleContext, String baseName) { - if (artifactLocation != null) { - return ruleContext.getUniqueDirectoryArtifact( - artifactLocation, baseName, ruleContext.getBinOrGenfilesDirectory()); - } else { - return AndroidBinary.getDxArtifact(ruleContext, baseName); - } - } - - /** Adds execution info by propagating tags from the target */ - private static SpawnAction.Builder createSpawnActionBuilder(RuleContext ruleContext) { - return new SpawnAction.Builder() - .setExecutionInfo( - TargetUtils.getExecutionInfo( - ruleContext.getRule(), ruleContext.isAllowTagsPropagation())); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java b/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java deleted file mode 100644 index 24ca8770a5c4b6..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveAspect.java +++ /dev/null @@ -1,802 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType.UNQUOTED; -import static com.google.devtools.build.lib.packages.Attribute.attr; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; -import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL; -import static com.google.devtools.build.lib.packages.BuildType.TRISTATE; -import static com.google.devtools.build.lib.packages.StarlarkProviderIdentifier.forKey; -import static com.google.devtools.build.lib.packages.Type.INTEGER; -import static com.google.devtools.build.lib.rules.android.AndroidCommon.getAndroidConfig; -import static com.google.devtools.build.lib.rules.android.AndroidSdkProvider.ANDROID_SDK_TOOLCHAIN_TYPE_ATTRIBUTE_NAME; - -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Joiner; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableCollection; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.common.collect.Streams; -import com.google.devtools.build.lib.actions.ActionConflictException; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ExecutionRequirements; -import com.google.devtools.build.lib.actions.ParamFileInfo; -import com.google.devtools.build.lib.analysis.Allowlist; -import com.google.devtools.build.lib.analysis.ConfiguredAspect; -import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; -import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement; -import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.cmdline.RepositoryName; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.AspectDefinition; -import com.google.devtools.build.lib.packages.AspectParameters; -import com.google.devtools.build.lib.packages.AttributeMap; -import com.google.devtools.build.lib.packages.NativeAspectClass; -import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; -import com.google.devtools.build.lib.packages.Rule; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.packages.TriState; -import com.google.devtools.build.lib.rules.java.JavaCommon; -import com.google.devtools.build.lib.rules.java.JavaInfo; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; -import com.google.devtools.build.lib.rules.proto.ProtoInfo; -import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainProvider; -import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import javax.annotation.Nullable; - -/** Aspect to {@link DexArchiveProvider build .dex Archives} from Jars. */ -public class DexArchiveAspect extends NativeAspectClass implements ConfiguredAspectFactory { - public static final String NAME = "DexArchiveAspect"; - - /** - * Function that returns a {@link Rule}'s {@code incremental_dexing} attribute for use by this - * aspect. Must be provided when attaching this aspect to a target. - */ - @SerializationConstant - public static final Function PARAM_EXTRACTOR = - (Rule rule) -> { - AttributeMap attributes = NonconfigurableAttributeMapper.of(rule); - AspectParameters.Builder result = new AspectParameters.Builder(); - TriState incrementalAttr = attributes.get("incremental_dexing", TRISTATE); - result.addAttribute("incremental_dexing", incrementalAttr.name()); - result.addAttribute( - "min_sdk_version", attributes.get("min_sdk_version", INTEGER).toString()); - result.addAttribute("toprule_kind", rule.getRuleClass()); - return result.build(); - }; - - /** - * Function that limits this aspect to Java 8 desugaring (disabling incremental dexing) when - * attaching this aspect to a target. This is intended for implicit attributes like the stub APKs - * for {@code bazel mobile-install}. - */ - @SerializationConstant - static final Function ONLY_DESUGAR_JAVA8 = - (Rule rule) -> - new AspectParameters.Builder() - .addAttribute("incremental_dexing", TriState.NO.name()) - .build(); - /** Aspect-only label for dexbuidler executable, to avoid name clashes with labels on rules. */ - private static final String ASPECT_DEXBUILDER_PREREQ = "$dex_archive_dexbuilder"; - /** Aspect-only label for desugaring executable, to avoid name clashes with labels on rules. */ - private static final String ASPECT_DESUGAR_PREREQ = "$aspect_desugar"; - - private static final ImmutableList TRANSITIVE_ATTRIBUTES = - ImmutableList.of( - "deps", - "exports", - "runtime_deps", - // Propagate the aspect down legacy toolchain dependencies. This won't work for platform- - // based toolchains, which aren't connected to an attribute. See - // propagateDownLegacyToolchain for how this distinction is handled. - ":android_sdk", - "aidl_lib", // for the aidl runtime in the android_sdk rule - "$toolchain", // this is _toolchain in Starlark rules (b/78647825) - "$build_stamp_deps", // for build stamp runtime class deps - "$build_stamp_mergee_manifest_lib", // for empty build stamp Service class implementation - // To get from proto_library through proto_lang_toolchain rule to proto runtime library. - ":aspect_proto_toolchain_for_javalite", - "runtime"); - - private static final FlagMatcher DEXOPTS_SUPPORTED_IN_DEXBUILDER = - new FlagMatcher( - ImmutableList.of("--no-locals", "--no-optimize", "--no-warnings", "--positions")); - - private final RepositoryName toolsRepository; - private final String sdkToolchainLabel; - - public DexArchiveAspect(RepositoryName toolsRepository, String sdkToolchainLabel) { - this.toolsRepository = toolsRepository; - this.sdkToolchainLabel = sdkToolchainLabel; - } - - @Override - public AspectDefinition getDefinition(AspectParameters params) { - Label toolchainType = Label.parseCanonicalUnchecked(toolsRepository + sdkToolchainLabel); - AspectDefinition.Builder result = - new AspectDefinition.Builder(this) - .requireStarlarkProviders(forKey(JavaInfo.PROVIDER.getKey())) - // Latch onto Starlark toolchains in case they have a "runtime" (b/78647825) - .requireStarlarkProviders(forKey(ToolchainInfo.PROVIDER.getKey())) - // For android_sdk rules, where we just want to get at aidl runtime deps. - .requireStarlarkProviders(forKey(AndroidSdkProvider.PROVIDER.getKey())) - .requireStarlarkProviders(forKey(ProtoInfo.PROVIDER.getKey())) - .requireStarlarkProviderSets( - ImmutableList.of( - // For proto_lang_toolchain rules, where we just want to get at their runtime - // deps. - ImmutableSet.of(ProtoLangToolchainProvider.PROVIDER_ID))) - .add(attr(ANDROID_SDK_TOOLCHAIN_TYPE_ATTRIBUTE_NAME, NODEP_LABEL).value(toolchainType)) - .addToolchainTypes( - ToolchainTypeRequirement.builder(toolchainType).mandatory(true).build()) - // Parse labels since we don't have RuleDefinitionEnvironment.getLabel like in a rule - .add( - attr(ASPECT_DESUGAR_PREREQ, LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value( - Label.parseCanonicalUnchecked( - toolsRepository + "//tools/android:desugar_java8"))) - // Access to --android_sdk so we can stub in a bootclasspath for desugaring if missing - // Remove this entirely when we remove --android_sdk support. - .add( - attr(":dex_archive_android_sdk", LABEL) - .allowedRuleClasses("android_sdk", "filegroup") - .value( - AndroidRuleClasses.getAndroidSdkLabel( - Label.parseCanonicalUnchecked( - toolsRepository + AndroidRuleClasses.DEFAULT_SDK)))) - .add( - Allowlist.getAttributeFromAllowlistName("enable_starlark_dex_desugar_proguard") - .value( - Label.parseCanonicalUnchecked( - toolsRepository - + "//tools/allowlists/android_binary_allowlist:enable_starlark_dex_desugar_proguard"))) - .requiresConfigurationFragments(AndroidConfiguration.class) - .requireAspectsWithProviders( - ImmutableList.of(ImmutableSet.of(forKey(JavaInfo.PROVIDER.getKey())))); - if (TriState.valueOf(params.getOnlyValueOfAttribute("incremental_dexing")) != TriState.NO) { - // Marginally improves "query2" precision for targets that disable incremental dexing - result.add( - attr(ASPECT_DEXBUILDER_PREREQ, LABEL) - .cfg(ExecutionTransitionFactory.createFactory()) - .exec() - .value( - Label.parseCanonicalUnchecked(toolsRepository + "//tools/android:dexbuilder"))); - } - for (String attr : TRANSITIVE_ATTRIBUTES) { - result.propagateAlongAttribute(attr); - } - return result.build(); - } - - /** - * Returns toolchain .jars that need dexing for platform-based toolchains. - * - *

Legacy toolchains handle these .jars recursively by propagating the aspect down the - * ":android_sdk" attribute. So they don't need this method. - */ - private static ImmutableList getPlatformBasedToolchainJars(RuleContext ruleContext) - throws RuleErrorException { - if (!ruleContext.attributes().has(":android_sdk")) { - // If we're dexing a non-Android target (like a java_library), there's no Android toolchain to - // include. - return ImmutableList.of(); - } - - AndroidSdkProvider androidSdk = AndroidSdkProvider.fromRuleContext(ruleContext); - if (androidSdk == null || androidSdk.getAidlLib() == null) { - // If the Android SDK is null, we don't have a valid toolchain. Expect a rule error reported - // from AndroidSdkProvider. - return ImmutableList.of(); - } - return ImmutableList.copyOf( - JavaInfo.getJavaInfo(androidSdk.getAidlLib()).getDirectRuntimeJars()); - } - - @Override - @Nullable - public ConfiguredAspect create( - Label targetLabel, - ConfiguredTarget ct, - RuleContext ruleContext, - AspectParameters params, - RepositoryName toolsRepository) - throws InterruptedException, ActionConflictException { - - ConfiguredAspect.Builder result = new ConfiguredAspect.Builder(ruleContext); - - // No-op out of the aspect in the android_binary rule if the Starlark dex/desugar will execute - // to avoid registering duplicate actions and bloating memory. - if (!params.getAttribute("toprule_kind").isEmpty() - && params.getOnlyValueOfAttribute("toprule_kind").equals("android_binary") - && Allowlist.hasAllowlist(ruleContext, "enable_starlark_dex_desugar_proguard") - && Allowlist.isAvailable(ruleContext, "enable_starlark_dex_desugar_proguard")) { - return result.build(); - } - - int minSdkVersion = 0; - if (!params.getAttribute("min_sdk_version").isEmpty()) { - minSdkVersion = Integer.valueOf(params.getOnlyValueOfAttribute("min_sdk_version")); - } - - Function desugaredJars; - ImmutableList extraToolchainJars; - ImmutableCollection runtimeJars; - try { - extraToolchainJars = getPlatformBasedToolchainJars(ruleContext); - desugaredJars = - desugarJarsIfRequested(ct, ruleContext, minSdkVersion, result, extraToolchainJars); - runtimeJars = getProducedRuntimeJars(ct, ruleContext, extraToolchainJars); - } catch (RuleErrorException e) { - ruleContext.ruleError(e.getMessage()); - return null; - } - - TriState incrementalAttr = - TriState.valueOf(params.getOnlyValueOfAttribute("incremental_dexing")); - if (incrementalAttr == TriState.NO - || (!getAndroidConfig(ruleContext).useIncrementalDexing() - && incrementalAttr == TriState.AUTO)) { - // Dex archives will never be used, so don't bother setting them up. - return result.build(); - } - - if (JavaCommon.isNeverLink(ruleContext)) { - return result.addProvider(DexArchiveProvider.NEVERLINK).build(); - } - - DexArchiveProvider.Builder dexArchives = new DexArchiveProvider.Builder(); - collectPrerequisites( - ruleContext, DexArchiveProvider.class, dexArchives::addTransitiveProviders); - if (runtimeJars != null) { - boolean basenameClash = checkBasenameClash(runtimeJars); - Set> aspectDexopts = aspectDexopts(ruleContext); - String minSdkFilenamePart = minSdkVersion > 0 ? "--min_sdk_version=" + minSdkVersion : ""; - for (Artifact jar : runtimeJars) { - Artifact desugaredJar = desugaredJars.apply(jar); - for (Set incrementalDexopts : aspectDexopts) { - // Since we're potentially dexing the same jar multiple times with different flags, we - // need to write unique artifacts for each flag combination. Here, it is convenient to - // distinguish them by putting the flags that were used for creating the artifacts into - // their filenames. Since min_sdk_version is a parameter to the aspect from the - // android_binary target that the aspect originates from, it's handled separately so that - // the correct min sdk value is used. - String uniqueFilename = - (basenameClash ? jar.getRootRelativePathString() : jar.getFilename()) - + Joiner.on("").join(incrementalDexopts) - + minSdkFilenamePart - + ".dex.zip"; - Artifact dexArchive = - createDexArchiveAction( - ruleContext, - ASPECT_DEXBUILDER_PREREQ, - desugaredJar, - incrementalDexopts, - minSdkVersion, - AndroidBinary.getDxArtifact(ruleContext, uniqueFilename)); - dexArchives.addDexArchive(incrementalDexopts, dexArchive, jar); - } - } - } - return result.addProvider(dexArchives.build()).build(); - } - - /** - * Runs Jars in {@link JavaInfo#getDirectRuntimeJars()} through desugaring action if flag is set - * and adds the result to {@code result}. Note that this cannot happen in a separate aspect - * because aspects don't see providers added by other aspects executed on the same target. - */ - private Function desugarJarsIfRequested( - ConfiguredTarget base, - RuleContext ruleContext, - int minSdkVersion, - ConfiguredAspect.Builder result, - Iterable extraToolchainJars) - throws RuleErrorException { - if (!getAndroidConfig(ruleContext).desugarJava8()) { - return Functions.identity(); - } - Map newlyDesugared = new HashMap<>(); - if (JavaCommon.isNeverLink(ruleContext)) { - result.addProvider(AndroidRuntimeJarProvider.NEVERLINK); - return Functions.forMap(newlyDesugared); - } - AndroidRuntimeJarProvider.Builder desugaredJars = new AndroidRuntimeJarProvider.Builder(); - collectPrerequisites( - ruleContext, AndroidRuntimeJarProvider.class, desugaredJars::addTransitiveProviders); - if (isProtoLibrary(ruleContext)) { - // TODO(b/33557068): Desugar protos if needed instead of assuming they don't need desugaring - result.addProvider(desugaredJars.build()); - return Functions.identity(); - } - - JavaInfo javaInfo = JavaInfo.getJavaInfo(base); - if (javaInfo != null) { - // These are all transitive hjars of dependencies and hjar of the jar itself - NestedSet compileTimeClasspath = JavaInfo.transitiveCompileTimeJars(base); - ImmutableSet.Builder jars = ImmutableSet.builder(); - jars.addAll(javaInfo.getDirectRuntimeJars()); - - Artifact rJar = getAndroidLibraryRJar(base); - if (rJar != null) { - // TODO(b/124540821): Disable R.jar desugaring (with a flag). - jars.add(rJar); - } - - Artifact buildStampJar = getAndroidBuildStampJar(base); - if (buildStampJar != null) { - jars.add(buildStampJar); - } - - // For android_* targets we need to honor their bootclasspath (nicer in general to do so) - NestedSet bootclasspath = getBootclasspath(base, ruleContext); - - jars.addAll(extraToolchainJars); - ImmutableSet jarsToProcess = jars.build(); - boolean basenameClash = checkBasenameClash(jarsToProcess); - for (Artifact jar : jarsToProcess) { - Artifact desugared = - createDesugarAction( - ruleContext, - basenameClash, - jar, - bootclasspath, - compileTimeClasspath, - minSdkVersion); - newlyDesugared.put(jar, desugared); - desugaredJars.addDesugaredJar(jar, desugared); - } - } - result.addProvider(desugaredJars.build()); - - return key -> { - if (newlyDesugared.containsKey(key)) { - return newlyDesugared.get(key); - } - // Fall back to the original un-desugared artifact. - return key; - }; - } - - @Nullable - private static ImmutableCollection getProducedRuntimeJars( - ConfiguredTarget base, RuleContext ruleContext, Iterable extraToolchainJars) - throws RuleErrorException { - if (isProtoLibrary(ruleContext)) { - if (!ruleContext.getPrerequisites("srcs").isEmpty()) { - JavaInfo javaInfo = JavaInfo.getJavaInfo(base); - if (javaInfo != null) { - return javaInfo.getJavaOutputs().stream() - .map(JavaOutput::getClassJar) - .collect(toImmutableList()); - } - } - } else { - ImmutableSet.Builder jars = ImmutableSet.builder(); - JavaInfo javaInfo = JavaInfo.getJavaInfo(base); - if (javaInfo != null) { - jars.addAll(javaInfo.getDirectRuntimeJars()); - } - - Artifact rJar = getAndroidLibraryRJar(base); - if (rJar != null) { - jars.add(rJar); - } - - Artifact buildStampJar = getAndroidBuildStampJar(base); - if (buildStampJar != null) { - jars.add(buildStampJar); - } - - jars.addAll(extraToolchainJars); - return jars.build(); - } - return null; - } - - private static boolean isProtoLibrary(RuleContext ruleContext) { - return "proto_library".equals(ruleContext.getRule().getRuleClass()); - } - - @Nullable - private static Artifact getAndroidLibraryRJar(ConfiguredTarget base) { - AndroidIdeInfoProvider provider = - (AndroidIdeInfoProvider) base.get(AndroidIdeInfoProvider.PROVIDER.getKey()); - if (provider != null && provider.getResourceJarJavaOutput() != null) { - return provider.getResourceJarJavaOutput().getClassJar(); - } - return null; - } - - @Nullable - private static Artifact getAndroidBuildStampJar(ConfiguredTarget base) { - AndroidApplicationResourceInfo provider = - (AndroidApplicationResourceInfo) base.get(AndroidApplicationResourceInfo.PROVIDER.getKey()); - if (provider != null && provider.getBuildStampJar() != null) { - return provider.getBuildStampJar(); - } - return null; - } - - private static boolean checkBasenameClash(Iterable artifacts) { - HashSet seen = new HashSet<>(); - for (Artifact artifact : artifacts) { - if (!seen.add(artifact.getFilename())) { - return true; - } - } - return false; - } - - private static void collectPrerequisites( - RuleContext ruleContext, Class classType, Consumer> sink) { - for (String attr : TRANSITIVE_ATTRIBUTES) { - if (ruleContext.attributes().getAttributeType(attr) != null) { - sink.accept(ruleContext.getPrerequisites(attr, classType)); - } - } - } - - private NestedSet getBootclasspath(ConfiguredTarget base, RuleContext ruleContext) - throws RuleErrorException { - NestedSet bootClasspath = JavaInfo.bootClasspath(base); - if (!bootClasspath.isEmpty()) { - return bootClasspath; - } - Artifact androidJar = getAndroidJar(ruleContext); - if (androidJar != null) { - return NestedSetBuilder.naiveLinkOrder().add(androidJar).build(); - } - // This shouldn't ever be reached, but if it is, we should be clear about the error. - throw new IllegalStateException("no compilationInfo or androidJar"); - } - - @Nullable - private Artifact getAndroidJar(RuleContext ruleContext) throws RuleErrorException { - Label toolchainType = Label.parseCanonicalUnchecked(toolsRepository + sdkToolchainLabel); - AndroidSdkProvider androidSdk = AndroidSdkProvider.fromRuleContext(ruleContext, toolchainType); - if (androidSdk == null) { - // If the Android SDK is null, we don't have a valid toolchain. Expect a rule error reported - // from AndroidSdkProvider. - return null; - } - return androidSdk.getAndroidJar(); - } - - private Artifact createDesugarAction( - RuleContext ruleContext, - boolean disambiguateBasenames, - Artifact jar, - NestedSet bootclasspath, - NestedSet compileTimeClasspath, - int minSdkVersion) { - - String minSdkFilenamePart = minSdkVersion > 0 ? "_minsdk=" + minSdkVersion : ""; - return createDesugarAction( - ruleContext, - ASPECT_DESUGAR_PREREQ, - jar, - bootclasspath, - compileTimeClasspath, - minSdkVersion, - AndroidBinary.getDxArtifact( - ruleContext, - (disambiguateBasenames ? jar.getRootRelativePathString() : jar.getFilename()) - + minSdkFilenamePart - + "_desugared.jar")); - } - - private static Artifact createDesugarAction( - RuleContext ruleContext, - String desugarPrereqName, - Artifact jar, - NestedSet bootclasspath, - NestedSet classpath, - int minSdkVersion, - Artifact result) { - SpawnAction.Builder action = - new SpawnAction.Builder() - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite(desugarPrereqName)) - .addInput(jar) - .addTransitiveInputs(bootclasspath) - .addTransitiveInputs(classpath) - .addOutput(result) - .setMnemonic("Desugar") - .setProgressMessage("Desugaring %s for Android", jar.prettyPrint()) - .setExecutionInfo( - createDexingDesugaringExecRequirements(ruleContext) - .putAll(ExecutionRequirements.WORKER_MODE_ENABLED) - .buildKeepingLast()); - - CustomCommandLine.Builder args = - new CustomCommandLine.Builder() - .addExecPath("--input", jar) - .addExecPath("--output", result) - .addExecPaths(VectorArg.addBefore("--classpath_entry").each(classpath)) - .addExecPaths(VectorArg.addBefore("--bootclasspath_entry").each(bootclasspath)); - if (getAndroidConfig(ruleContext).checkDesugarDeps()) { - args.add("--emit_dependency_metadata_as_needed"); - } - if (getAndroidConfig(ruleContext).desugarJava8Libs()) { - args.add("--desugar_supported_core_libs"); - } - if (minSdkVersion > 0) { - args.add("--min_sdk_version", Integer.toString(minSdkVersion)); - } - - action.addCommandLine( - // Always use params file, so we don't need to compute command line length first - args.build(), ParamFileInfo.builder(UNQUOTED).setUseAlways(true).build()); - - ruleContext.registerAction(action.build(ruleContext)); - return result; - } - - /** - * Desugars the given Jar using an executable prerequisite {@code "$desugar"}. Rules calling this - * method must declare the appropriate prerequisite, similar to how {@link #getDefinition} does it - * for {@link DexArchiveAspect} under a different name. - * - *

It's useful to have this action separately since callers need to look up classpath and - * bootclasspath in a different way than this aspect does it. - * - * @return the artifact given as {@code result}, which can simplify calling code - */ - static Artifact desugar( - RuleContext ruleContext, - Artifact jar, - NestedSet bootclasspath, - NestedSet classpath, - int minSdkVersion, - Artifact result) { - return createDesugarAction( - ruleContext, "$desugar", jar, bootclasspath, classpath, minSdkVersion, result); - } - - /** - * Creates a dexbuilder action with the given input, output, and flags. Flags must have been - * filtered and normalized to a set that the dexbuilder tool can understand. - * - * @return the artifact given as {@code result}, which can simplify calling code - */ - // Package-private method for use in AndroidBinary - @CanIgnoreReturnValue - static Artifact createDexArchiveAction( - RuleContext ruleContext, - String dexbuilderPrereq, - Artifact jar, - Set incrementalDexopts, - int minSdkVersion, - Artifact dexArchive) { - SpawnAction.Builder dexbuilder = - new SpawnAction.Builder() - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite(dexbuilderPrereq)) - .setExecutionInfo( - createDexingDesugaringExecRequirements(ruleContext) - .putAll( - TargetUtils.getExecutionInfo( - ruleContext.getRule(), ruleContext.isAllowTagsPropagation())) - .buildKeepingLast()) - // WorkerSpawnStrategy expects the last argument to be @paramfile - .addInput(jar) - .addOutput(dexArchive) - .setMnemonic("DexBuilder") - .setProgressMessage( - "Dexing %s with applicable dexopts %s", jar.prettyPrint(), incrementalDexopts); - - CustomCommandLine.Builder args = - new CustomCommandLine.Builder() - .addExecPath("--input_jar", jar) - .addExecPath("--output_zip", dexArchive) - .addAll(ImmutableList.copyOf(incrementalDexopts)); - if (minSdkVersion > 0) { - args.add("--min_sdk_version", Integer.toString(minSdkVersion)); - } - - dexbuilder.addCommandLine( - args.build(), ParamFileInfo.builder(UNQUOTED).setUseAlways(true).build()); - ruleContext.registerAction(dexbuilder.build(ruleContext)); - return dexArchive; - } - - @CanIgnoreReturnValue - static Artifact createShardedOptimizedDexArchiveAction( - RuleContext ruleContext, - Artifact jar, - Set incrementalDexopts, - int minSdkVersion, - Artifact dexArchive) { - SpawnAction.Builder dexbuilder = - new SpawnAction.Builder() - .useDefaultShellEnvironment() - .setExecutable(ruleContext.getExecutablePrerequisite(":optimizing_dexer")) - .setExecutionInfo( - createDexingDesugaringExecRequirements(ruleContext) - .putAll( - TargetUtils.getExecutionInfo( - ruleContext.getRule(), ruleContext.isAllowTagsPropagation())) - .buildKeepingLast()) - .addInput(jar) - .addOutput(dexArchive) - .setMnemonic("ShardedOptimizingDex") - .setProgressMessage( - "Optimized dexing %s with applicable dexopts %s", - jar.prettyPrint(), incrementalDexopts); - - CustomCommandLine.Builder args = - new CustomCommandLine.Builder() - .add("--intermediate") - .add("--release") - .add("--no-desugaring") - .addExecPath("--output", dexArchive) - .addAll(ImmutableList.copyOf(incrementalDexopts)) - .addExecPath(jar); - if (minSdkVersion > 0) { - args.add("--min_sdk_version", Integer.toString(minSdkVersion)); - } - - dexbuilder.addCommandLine(args.build()); - ruleContext.registerAction(dexbuilder.build(ruleContext)); - return dexArchive; - } - - private static Set> aspectDexopts(RuleContext ruleContext) { - return Sets.powerSet( - normalizeDexopts(getAndroidConfig(ruleContext).getDexoptsSupportedInIncrementalDexing())); - } - - /** Creates the execution requires for the DexBuilder and Desugar actions */ - private static ImmutableMap.Builder createDexingDesugaringExecRequirements( - RuleContext ruleContext) { - final ImmutableMap.Builder executionInfo = ImmutableMap.builder(); - AndroidConfiguration androidConfiguration = getAndroidConfig(ruleContext); - if (androidConfiguration.persistentDexDesugar()) { - executionInfo.putAll(ExecutionRequirements.WORKER_MODE_ENABLED); - if (androidConfiguration.persistentMultiplexDexDesugar()) { - executionInfo.putAll(ExecutionRequirements.WORKER_MULTIPLEX_MODE_ENABLED); - } - } - - return executionInfo; - } - - /** - * Derives options to use in incremental dexing actions from the given context and dx flags, where - * the latter typically come from a {@code dexopts} attribute on a top-level target. This method - * only works reliably if the given dexopts were tokenized, e.g., using {@link - * RuleContext#getTokenizedStringListAttr}. - */ - static ImmutableSet incrementalDexopts( - RuleContext ruleContext, Iterable tokenizedDexopts) { - return normalizeDexopts( - Iterables.filter( - tokenizedDexopts, - // dexopts have to match exactly since aspect only creates archives for listed ones - Predicates.in(getAndroidConfig(ruleContext).getDexoptsSupportedInIncrementalDexing()))); - } - - /** - * Returns the subset of the given dexopts that are forbidden from using incremental dexing by - * default. - */ - static Iterable forbiddenDexopts(RuleContext ruleContext, List dexopts) { - return Iterables.filter( - dexopts, - new FlagMatcher( - getAndroidConfig(ruleContext).getTargetDexoptsThatPreventIncrementalDexing())); - } - - /** - * Derives options to use in DexBuilder actions from the given context and dx flags, where the - * latter typically come from a {@code dexopts} attribute on a top-level target. This should be a - * superset of {@link #incrementalDexopts}. - */ - static ImmutableSet topLevelDexbuilderDexopts(Iterable tokenizedDexopts) { - // We don't need an ordered set but might as well. - return normalizeDexopts(Iterables.filter(tokenizedDexopts, DEXOPTS_SUPPORTED_IN_DEXBUILDER)); - } - - /** - * Derives options to use in DexFileMerger actions from the given context and dx flags, where the - * latter typically come from a {@code dexopts} attribute on a top-level target. - */ - static ImmutableSet mergerDexopts( - RuleContext ruleContext, Iterable tokenizedDexopts) { - // We don't need an ordered set but might as well. Note we don't need to worry about coverage - // builds since the merger doesn't use --no-locals. - return normalizeDexopts( - Iterables.filter( - tokenizedDexopts, - new FlagMatcher(getAndroidConfig(ruleContext).getDexoptsSupportedInDexMerger()))); - } - - /** - * Derives options to use in DexFileSharder actions from the given context and dx flags, where the - * latter typically come from a {@code dexopts} attribute on a top-level target. - */ - static ImmutableSet sharderDexopts( - RuleContext ruleContext, Iterable tokenizedDexopts) { - // We don't need an ordered set but might as well. Note we don't need to worry about coverage - // builds since the merger doesn't use --no-locals. - return normalizeDexopts( - Iterables.filter( - tokenizedDexopts, - new FlagMatcher(getAndroidConfig(ruleContext).getDexoptsSupportedInDexSharder()))); - } - - private static ImmutableSet normalizeDexopts(Iterable tokenizedDexopts) { - // Sort and use ImmutableSet to drop duplicates and get fixed (sorted) order. Fixed order is - // important so we generate one dex archive per set of flag in create() method, regardless of - // how those flags are listed in all the top-level targets being built. - return Streams.stream(tokenizedDexopts) - .map(FlagConverter.DX_TO_DEXBUILDER) - .sorted() - .collect(ImmutableSet.toImmutableSet()); // collector with dedupe - } - - private static class FlagMatcher implements Predicate { - private final ImmutableList matching; - - FlagMatcher(ImmutableList matching) { - this.matching = matching; - } - - @Override - public boolean apply(String input) { - for (String match : matching) { - if (input.contains(match)) { - return true; - } - } - return false; - } - } - - private enum FlagConverter implements Function { - DX_TO_DEXBUILDER; - - @Override - public String apply(String input) { - return input.replace("--no-", "--no"); - } - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveProvider.java deleted file mode 100644 index c704c2c8f24195..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/DexArchiveProvider.java +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2016 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Function; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableTable; -import com.google.common.collect.Table; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -/** - * Provider of transitively available dex archives corresponding to Jars. A dex archive is a zip of - * {@code .dex} files that each encode exactly one {@code .class} file in an Android-readable form. - * The file names in a dex archive should match the file names in the originating Jar file, except - * with {@code .dex} appended, i.e., {@code For convenience this class implements a {@link Function} to map from Jars to dex archives if - * available (returns the given Jar otherwise). - */ -@Immutable -public class DexArchiveProvider implements TransitiveInfoProvider { - - /** - * Provider that doesn't provide any dex archives, which is what any neverlink target should use. - * It's not strictly necessary to handle neverlink specially, but doing so reduces the amount of - * processing done for targets that won't be used for dexing anyway. - */ - public static final DexArchiveProvider NEVERLINK = new DexArchiveProvider.Builder().build(); - - /** Builder for {@link DexArchiveProvider}. */ - public static class Builder { - - private final Table, Artifact, Artifact> dexArchives = - HashBasedTable.create(); - private final NestedSetBuilder, Artifact, Artifact>> - transitiveDexArchives = NestedSetBuilder.stableOrder(); - - public Builder() {} - - /** - * Adds all dex archives from the given providers, which is useful to aggregate providers from - * dependencies. - */ - @CanIgnoreReturnValue - public Builder addTransitiveProviders(Iterable providers) { - for (DexArchiveProvider provider : providers) { - transitiveDexArchives.addTransitive(provider.dexArchives); - } - return this; - } - - /** - * Adds the given dex archive as a replacement for the given Jar. - * - * @param dexopts - */ - @CanIgnoreReturnValue - public Builder addDexArchive(Set dexopts, Artifact dexArchive, Artifact dexedJar) { - checkArgument( - dexArchive.getFilename().endsWith(".dex.zip"), - "Doesn't look like a dex archive: %s", - dexArchive); - // Adding this artifact will fail iff dexArchive already appears as the value of another jar. - // It's ok and expected to put the same pair multiple times. Note that ImmutableBiMap fails - // in that situation, which is why we're not using it here. - // It's weird to put a dexedJar that's already in the map with a different value so we fail. - Artifact old = - dexArchives.put( - ImmutableSet.copyOf(dexopts), checkNotNull(dexedJar, "dexedJar"), dexArchive); - checkArgument( - old == null || old.equals(dexArchive), - "We already had mapping %s-%s for dexopts %s, so we don't also need %s", - dexedJar, - old, - dexopts, - dexArchive); - return this; - } - - /** Returns the finished {@link DexArchiveProvider}. */ - public DexArchiveProvider build() { - return new DexArchiveProvider( - transitiveDexArchives.add(ImmutableTable.copyOf(dexArchives)).build()); - } - } - - /** Map from Jar artifacts to the corresponding dex archives. */ - private final NestedSet, Artifact, Artifact>> dexArchives; - - private DexArchiveProvider( - NestedSet, Artifact, Artifact>> dexArchives) { - this.dexArchives = dexArchives; - } - - /** Returns a flat map from Jars to dex archives transitively produced for the given dexopts. */ - public Map archivesForDexopts(ImmutableSet dexopts) { - // Can't use ImmutableMap because we can encounter the same key-value pair multiple times. - // Use LinkedHashMap in case someone tries to iterate this map (not the case as of 2/2017). - LinkedHashMap result = new LinkedHashMap<>(); - for (ImmutableTable, Artifact, Artifact> partialMapping : - dexArchives.toList()) { - result.putAll(partialMapping.row(dexopts)); - } - return result; - } - - @Override - public int hashCode() { - return dexArchives.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - DexArchiveProvider other = (DexArchiveProvider) obj; - return dexArchives.equals(other.dexArchives); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java index 7fd39817f123a2..7a667c7976f726 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java @@ -13,16 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; -import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.RuleErrorConsumer; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.android.databinding.DataBinding; -import com.google.devtools.build.lib.rules.android.databinding.DataBindingContext; -import java.util.List; -import java.util.Map; import javax.annotation.Nullable; /** @@ -51,183 +42,6 @@ public class ProcessedAndroidData { private final Artifact resourceProguardConfig; @Nullable private final Artifact mainDexProguardConfig; - /** Processes Android data (assets, resources, and manifest) for android_binary targets. */ - public static ProcessedAndroidData processBinaryDataFrom( - AndroidDataContext dataContext, - RuleErrorConsumer errorConsumer, - StampedAndroidManifest manifest, - boolean conditionalKeepRules, - Map manifestValues, - AndroidResources resources, - AndroidAssets assets, - ResourceDependencies resourceDeps, - AssetDependencies assetDeps, - ResourceFilterFactory resourceFilterFactory, - List noCompressExtensions, - boolean crunchPng, - DataBindingContext dataBindingContext) - throws RuleErrorException, InterruptedException { - AndroidResourcesProcessorBuilder builder = - builderForNonIncrementalTopLevelTarget(dataContext, manifest, manifestValues) - .setManifestOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST)) - .setMergedResourcesOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP)) - .setMainDexProguardOut( - AndroidBinary.createMainDexProguardSpec( - dataContext.getLabel(), dataContext.getActionConstructionContext())) - .conditionalKeepRules(conditionalKeepRules); - return buildActionForBinary( - dataContext, - dataBindingContext, - errorConsumer, - builder, - manifest, - resources, - assets, - resourceDeps, - assetDeps, - resourceFilterFactory, - noCompressExtensions, - crunchPng); - } - - public static ProcessedAndroidData processIncrementalBinaryDataFrom( - RuleContext ruleContext, - AndroidDataContext dataContext, - StampedAndroidManifest manifest, - Artifact apkOut, - Artifact mergedResourcesOut, - String proguardPrefix, - Map manifestValues) - throws RuleErrorException, InterruptedException { - - AndroidResourcesProcessorBuilder builder = - builderForTopLevelTarget(dataContext, manifest, proguardPrefix, manifestValues) - .setApkOut(apkOut) - .setMergedResourcesOut(mergedResourcesOut); - - return buildActionForBinary( - dataContext, - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()), - ruleContext, - builder, - manifest, - AndroidResources.from(ruleContext, "resource_files"), - AndroidAssets.from(ruleContext), - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false), - AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false), - ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext), - ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"), - ruleContext.attributes().get("crunch_png", Type.BOOLEAN)); - } - - private static ProcessedAndroidData buildActionForBinary( - AndroidDataContext dataContext, - DataBindingContext dataBindingContext, - RuleErrorConsumer errorConsumer, - AndroidResourcesProcessorBuilder builder, - StampedAndroidManifest manifest, - AndroidResources resources, - AndroidAssets assets, - ResourceDependencies resourceDeps, - AssetDependencies assetDeps, - ResourceFilterFactory resourceFilterFactory, - List noCompressExtensions, - boolean crunchPng) - throws RuleErrorException { - - ResourceFilter resourceFilter = - resourceFilterFactory.getResourceFilter(errorConsumer, resourceDeps, resources); - - // Filter unwanted resources out - resources = resources.filterLocalResources(errorConsumer, resourceFilter); - resourceDeps = resourceDeps.filter(errorConsumer, resourceFilter); - - return builder - .setResourceFilterFactory(resourceFilterFactory) - .setUncompressedExtensions(noCompressExtensions) - .setCrunchPng(crunchPng) - .withResourceDependencies(resourceDeps) - .withAssetDependencies(assetDeps) - .build(dataContext, resources, assets, manifest, dataBindingContext); - } - - /** Processes Android data (assets, resources, and manifest) for android_test targets. */ - public static ProcessedAndroidData processTestDataFrom( - AndroidDataContext dataContext, - DataBindingContext dataBindingContext, - StampedAndroidManifest manifest, - String packageUnderTest, - boolean hasLocalResourceFiles, - AndroidResources resources, - ResourceDependencies resourceDeps, - AndroidAssets assets, - AssetDependencies assetDeps) - throws InterruptedException { - - AndroidResourcesProcessorBuilder builder = - builderForNonIncrementalTopLevelTarget(dataContext, manifest, ImmutableMap.of()) - .setMergedResourcesOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP)) - .setMainDexProguardOut( - AndroidBinary.createMainDexProguardSpec( - dataContext.getLabel(), dataContext.getActionConstructionContext())) - .setPackageUnderTest(packageUnderTest) - .setIsTestWithResources(hasLocalResourceFiles) - .withResourceDependencies(resourceDeps) - .withAssetDependencies(assetDeps); - - return builder.build(dataContext, resources, assets, manifest, dataBindingContext); - } - - /** - * Common {@link AndroidResourcesProcessorBuilder} builder for non-incremental top-level targets. - * - *

The builder will be populated with commonly-used settings and outputs. - */ - private static AndroidResourcesProcessorBuilder builderForNonIncrementalTopLevelTarget( - AndroidDataContext dataContext, - StampedAndroidManifest manifest, - Map manifestValues) - throws InterruptedException { - - return builderForTopLevelTarget(dataContext, manifest, "", manifestValues) - // Outputs - .setApkOut(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK)) - .setRTxtOut(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT)) - .setSourceJarOut( - dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_JAVA_SOURCE_JAR)) - .setSymbols(dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS)); - } - - /** - * Common {@link AndroidResourcesProcessorBuilder} builder for top-level targets. - * - *

The builder will be populated with commonly-used settings and outputs. - */ - private static AndroidResourcesProcessorBuilder builderForTopLevelTarget( - AndroidDataContext dataContext, - StampedAndroidManifest manifest, - String proguardPrefix, - Map manifestValues) { - return new AndroidResourcesProcessorBuilder() - // Settings - .setDebug(dataContext.useDebug()) - .setJavaPackage(manifest.getPackage()) - .setApplicationId(manifestValues.get("applicationId")) - .setVersionCode(manifestValues.get("versionCode")) - .setVersionName(manifestValues.get("versionName")) - .setThrowOnResourceConflict(dataContext.throwOnResourceConflict()) - - // Output - .setProguardOut( - ProguardHelper.getProguardConfigArtifact( - dataContext.getLabel(), - dataContext.getActionConstructionContext(), - proguardPrefix)); - } - static ProcessedAndroidData of( ParsedAndroidResources resources, MergedAndroidAssets assets, diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java deleted file mode 100644 index 31ad1c034da262..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java +++ /dev/null @@ -1,783 +0,0 @@ -// Copyright 2015 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Ascii; -import com.google.common.base.Joiner; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSortedSet; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; -import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.collect.nestedset.Order; -import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.packages.AttributeMap; -import com.google.devtools.build.lib.packages.BuildType; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder; -import com.google.devtools.build.lib.rules.java.JavaConfiguration; -import com.google.devtools.build.lib.rules.java.JavaSemantics; -import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; -import com.google.devtools.build.lib.rules.java.ProguardSpecProvider; -import javax.annotation.Nullable; - -/** Common code for proguarding. */ -public final class ProguardHelper { - - /** - * Attribute for attaching proguard specs explicitly to a rule, if such an attribute is desired. - */ - public static final String PROGUARD_SPECS = "proguard_specs"; - - /** A class collecting Proguard output artifacts. */ - @Immutable - public static final class ProguardOutput { - @Nullable private final Artifact outputJar; - @Nullable private final Artifact mapping; - @Nullable private final Artifact protoMapping; - @Nullable private final Artifact seeds; - @Nullable private final Artifact usage; - @Nullable private final Artifact constantStringObfuscatedMapping; - @Nullable private final Artifact libraryJar; - private final Artifact config; - @Nullable private final Artifact startupProfileRewritten; - @Nullable private final Artifact mergedBaselineProfileRewritten; - - public ProguardOutput( - @Nullable Artifact outputJar, - @Nullable Artifact mapping, - @Nullable Artifact protoMapping, - @Nullable Artifact seeds, - @Nullable Artifact usage, - @Nullable Artifact constantStringObfuscatedMapping, - @Nullable Artifact libraryJar, - Artifact config, - @Nullable Artifact startupProfileRewritten, - @Nullable Artifact mergedBaselineProfileRewritten) { - this.outputJar = outputJar; - this.mapping = mapping; - this.protoMapping = protoMapping; - this.seeds = seeds; - this.usage = usage; - this.constantStringObfuscatedMapping = constantStringObfuscatedMapping; - this.libraryJar = libraryJar; - this.config = config; - this.startupProfileRewritten = startupProfileRewritten; - this.mergedBaselineProfileRewritten = mergedBaselineProfileRewritten; - } - - public static ProguardOutput createEmpty(Artifact outputJar) { - return new ProguardOutput(outputJar, null, null, null, null, null, null, null, null, null); - } - - @Nullable - public Artifact getOutputJar() { - return outputJar; - } - - public boolean hasMapping() { - return mapping != null; - } - - @Nullable - public Artifact getMapping() { - return mapping; - } - - @Nullable - public Artifact getProtoMapping() { - return protoMapping; - } - - @Nullable - public Artifact getConstantStringObfuscatedMapping() { - return constantStringObfuscatedMapping; - } - - @Nullable - public Artifact getSeeds() { - return seeds; - } - - @Nullable - public Artifact getUsage() { - return usage; - } - - @Nullable - public Artifact getLibraryJar() { - return libraryJar; - } - - public Artifact getConfig() { - return config; - } - - public Artifact getMergedBaselineProfileRewritten() { - return mergedBaselineProfileRewritten; - } - - public Artifact getStartupProfileRewritten() { - return startupProfileRewritten; - } - - /** Adds the output artifacts to the given set builder. */ - public void addAllToSet(NestedSetBuilder filesBuilder) { - addAllToSet(filesBuilder, null); - } - - /** - * Adds the output artifacts to the given set builder. If the progaurd map was updated then add - * the updated map instead of the original proguard output map - */ - public void addAllToSet(NestedSetBuilder filesBuilder, Artifact finalProguardMap) { - if (outputJar != null) { - filesBuilder.add(outputJar); - } - if (protoMapping != null) { - filesBuilder.add(protoMapping); - } - if (constantStringObfuscatedMapping != null) { - filesBuilder.add(constantStringObfuscatedMapping); - } - if (seeds != null) { - filesBuilder.add(seeds); - } - if (usage != null) { - filesBuilder.add(usage); - } - if (config != null) { - filesBuilder.add(config); - } - if (finalProguardMap != null) { - filesBuilder.add(finalProguardMap); - } else if (mapping != null) { - filesBuilder.add(mapping); - } - } - } - - /** - * Retrieves the full set of proguard specs that should be applied to this binary, including the - * specs passed in, if Proguard should run on the given rule. {@link #createProguardAction} relies - * on this method returning an empty list if the given rule doesn't declare specs in - * --java_optimization_mode=legacy. - * - *

If there are no proguard_specs on this rule, an empty list will be returned, regardless of - * any given specs or specs from dependencies. {@link - * com.google.devtools.build.lib.rules.android.AndroidBinary#createAndroidBinary} relies on that - * behavior. - */ - public static ImmutableList collectTransitiveProguardSpecs( - RuleContext ruleContext, Iterable specsToInclude) { - return collectTransitiveProguardSpecs( - ruleContext, - specsToInclude, - ruleContext.attributes().has(PROGUARD_SPECS, BuildType.LABEL_LIST) - ? ruleContext.getPrerequisiteArtifacts(PROGUARD_SPECS).list() - : ImmutableList.of(), - ruleContext.getPrerequisites("deps", ProguardSpecProvider.PROVIDER)); - } - - /** - * Retrieves the full set of proguard specs that should be applied to this binary, including the - * specs passed in, if Proguard should run on the given rule. - * - *

Unlike {@link #collectTransitiveProguardSpecs(RuleContext, Iterable)}, this method requires - * values to be passed in explicitly, and does not extract them from rule attributes. - * - *

If there are no proguard_specs on this rule, an empty list will be returned, regardless of - * any given specs or specs from dependencies. {@link - * com.google.devtools.build.lib.rules.android.AndroidBinary#createAndroidBinary} relies on that - * behavior. - */ - public static ImmutableList collectTransitiveProguardSpecs( - RuleContext context, - Iterable specsToInclude, - ImmutableList localProguardSpecs, - Iterable proguardDeps) { - return collectTransitiveProguardSpecs( - context.getLabel(), context, specsToInclude, localProguardSpecs, proguardDeps); - } - /** - * Retrieves the full set of proguard specs that should be applied to this binary, including the - * specs passed in, if Proguard should run on the given rule. - * - *

Unlike {@link #collectTransitiveProguardSpecs(RuleContext, Iterable)}, this method requires - * values to be passed in explicitly, and does not extract them from rule attributes. - * - *

If there are no proguard_specs on this rule, an empty list will be returned, regardless of - * any given specs or specs from dependencies. {@link - * com.google.devtools.build.lib.rules.android.AndroidBinary#createAndroidBinary} relies on that - * behavior. - */ - public static ImmutableList collectTransitiveProguardSpecs( - Label label, - ActionConstructionContext context, - Iterable specsToInclude, - ImmutableList localProguardSpecs, - Iterable proguardDeps) { - if (localProguardSpecs.isEmpty()) { - return ImmutableList.of(); - } - - ImmutableSortedSet.Builder builder = - ImmutableSortedSet.orderedBy(Artifact.EXEC_PATH_COMPARATOR) - .addAll(localProguardSpecs) - .addAll(specsToInclude); - for (ProguardSpecProvider dep : proguardDeps) { - builder.addAll(dep.getTransitiveProguardSpecs().toList()); - } - - return builder.build().asList(); - } - - /** @return true if proguard_generate_mapping is specified. */ - public static final boolean genProguardMapping(AttributeMap rule) { - return rule.has("proguard_generate_mapping", Type.BOOLEAN) - && rule.get("proguard_generate_mapping", Type.BOOLEAN); - } - - public static final boolean genObfuscatedConstantStringMap(AttributeMap rule) { - return rule.has("proguard_generate_obfuscated_constant_string_mapping", Type.BOOLEAN) - && rule.get("proguard_generate_obfuscated_constant_string_mapping", Type.BOOLEAN); - } - - public static ProguardOutput getProguardOutputs( - Artifact outputJar, - @Nullable Artifact proguardSeeds, - @Nullable Artifact proguardUsage, - RuleContext ruleContext, - AndroidSemantics androidSemantics, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact libraryJar, - @Nullable Artifact startupProfileRewritten, - @Nullable Artifact mergedBaselineProfileRewritten) - throws InterruptedException { - boolean mappingRequested = genProguardMapping(ruleContext.attributes()); - - Artifact proguardOutputProtoMap = null; - Artifact proguardConstantStringMap = null; - - if (mappingRequested) { - // TODO(bazel-team): if rex is enabled, the proguard map will change and then will no - // longer correspond to the proto map - proguardOutputProtoMap = androidSemantics.getProtoMapping(ruleContext); - } - - if (genObfuscatedConstantStringMap(ruleContext.attributes())) { - proguardConstantStringMap = androidSemantics.getObfuscatedConstantStringMap(ruleContext); - } - - Artifact proguardConfigOutput = - ruleContext.getImplicitOutputArtifact(AndroidSemantics.ANDROID_BINARY_PROGUARD_CONFIG); - - return new ProguardOutput( - outputJar, - proguardOutputMap, - proguardOutputProtoMap, - proguardSeeds, - proguardUsage, - proguardConstantStringMap, - libraryJar, - proguardConfigOutput, - startupProfileRewritten, - mergedBaselineProfileRewritten); - } - - /** - * Creates an action to run Proguard over the given {@code programJar} with various other given - * inputs to produce {@code proguardOutputJar}. If requested explicitly, or implicitly with - * --java_optimization_mode, the action also produces a mapping file (which shows what methods and - * classes in the output Jar correspond to which methods and classes in the input). The "pair" - * returned by this method indicates whether a mapping is being produced. - * - *

See the Proguard manual for the meaning of the various artifacts in play. - * - * @param proguard Proguard executable to use - * @param proguardSpecs Proguard specification files to pass to Proguard - * @param proguardMapping optional mapping file for Proguard to apply - * @param proguardDictionary Optional dictionary file for Proguard to apply - * @param libraryJars any other Jar files that the {@code programJar} will run against - * @param optimizationPasses if not null specifies to break proguard up into multiple passes with - * the given number of optimization passes. - * @param proguardOutputMap mapping generated by Proguard if requested. could be null. - * @param startupProfileIn Profiles provided by the startup_profiles attribute. Their existence - * enables feedback directed optimization in optimization tools. These are rewritten by the - * optimizer. - * @param baselineProfileIn Profile to pass the optimizer to rewrite through optimization. - * @param baselineProfileDir Directory to write baseline profile artifacts if baseline profile is - * provided. - */ - public static ProguardOutput createOptimizationActions( - RuleContext ruleContext, - FilesToRunProvider proguard, - Artifact programJar, - ImmutableList proguardSpecs, - @Nullable Artifact proguardSeeds, - @Nullable Artifact proguardUsage, - @Nullable Artifact proguardMapping, - @Nullable Artifact proguardDictionary, - NestedSet libraryJars, - Artifact proguardOutputJar, - AndroidSemantics androidSemantics, - JavaSemantics javaSemantics, - @Nullable Integer optimizationPasses, - @Nullable Artifact proguardOutputMap, - @Nullable Artifact startupProfileIn, - @Nullable Artifact baselineProfileIn, - String baselineProfileDir) - throws InterruptedException, RuleErrorException { - Preconditions.checkArgument(!proguardSpecs.isEmpty()); - Artifact libraryJar = null; - - if (!libraryJars.isEmpty() && !libraryJars.isSingleton()) { - JavaTargetAttributes attributes = new JavaTargetAttributes.Builder(javaSemantics).build(); - Artifact combinedLibraryJar = - getProguardTempArtifact(ruleContext, "combined_library_jars.jar"); - new DeployArchiveBuilder(javaSemantics, ruleContext) - .setOutputJar(combinedLibraryJar) - .setAttributes(attributes) - .addRuntimeJars(libraryJars) - .build(); - libraryJars = NestedSetBuilder.create(Order.STABLE_ORDER, combinedLibraryJar); - libraryJar = combinedLibraryJar; - } else if (libraryJars.isSingleton()) { - libraryJar = libraryJars.getSingleton(); - } - - boolean filterLibraryJarWithProgramJar = - ruleContext.getFragment(AndroidConfiguration.class).filterLibraryJarWithProgramJar(); - - if (filterLibraryJarWithProgramJar) { - Preconditions.checkState(libraryJars.isSingleton()); - Artifact singletonLibraryJar = libraryJars.getSingleton(); - - Artifact filteredLibraryJar = - getProguardTempArtifact(ruleContext, "combined_library_jars_filtered.jar"); - - new ZipFilterBuilder(ruleContext) - .setInputZip(singletonLibraryJar) - .setOutputZip(filteredLibraryJar) - .addFilterZips(ImmutableList.of(programJar)) - .setCheckHashMismatchMode(ZipFilterBuilder.CheckHashMismatchMode.NONE) - .build(); - - libraryJars = NestedSetBuilder.create(Order.STABLE_ORDER, filteredLibraryJar); - libraryJar = filteredLibraryJar; - } - Artifact startupProfileRewritten = - startupProfileIn == null - ? null - : ruleContext.getBinArtifact(baselineProfileDir + "rewritten-startup-prof.txt"); - Artifact baselineProfileRewritten = - baselineProfileIn == null && startupProfileIn == null - ? null - : ruleContext.getBinArtifact(baselineProfileDir + "rewritten-merged-prof.txt"); - ProguardOutput output = - getProguardOutputs( - proguardOutputJar, - proguardSeeds, - proguardUsage, - ruleContext, - androidSemantics, - proguardOutputMap, - libraryJar, - startupProfileRewritten, - baselineProfileRewritten); - - JavaConfiguration javaConfiguration = - ruleContext.getConfiguration().getFragment(JavaConfiguration.class); - JavaConfiguration.NamedLabel optimizer = javaConfiguration.getBytecodeOptimizer(); - String mnemonic = optimizer.name(); - if (optimizationPasses == null) { - // Run the optimizer as a single step. - SpawnAction.Builder proguardAction = new SpawnAction.Builder(); - CustomCommandLine.Builder commandLine = CustomCommandLine.builder(); - defaultAction( - proguardAction, - commandLine, - proguard, - programJar, - proguardSpecs, - proguardMapping, - proguardDictionary, - libraryJars, - output.getOutputJar(), - output.getMapping(), - output.getProtoMapping(), - output.getSeeds(), - output.getUsage(), - output.getConstantStringObfuscatedMapping(), - output.getConfig(), - startupProfileIn, - startupProfileRewritten, - baselineProfileIn, - baselineProfileRewritten, - mnemonic); - proguardAction - .setProgressMessage("Trimming binary with %s: %s", mnemonic, ruleContext.getLabel()) - .addOutput(proguardOutputJar); - proguardAction.addCommandLine(commandLine.build()); - ruleContext.registerAction(proguardAction.build(ruleContext)); - } else { - Optional

This only provides the first-level of testing: that --platforms settings directly - * impact toolchain selection in expected ways. Devs can lean on this test for quick interactive - * feedback on their changes. - */ -@RunWith(JUnit4.class) -public class AndroidPlatformsTest extends AndroidBuildViewTestCase { - - private static final String EXTRA_SDK_TOOLCHAINS_FLAG = - "--extra_toolchains=//platform_selected_android_sdks/toolchains:all"; - - @Before - public void setupPlatformsAndToolchains() throws Exception { - scratch.file( - "android_platforms/BUILD", - "platform(", - " name = 'x86_platform',", - " constraint_values = [", - " '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "cpu:x86_64',", - " ])", - "platform(", - " name = 'arm_platform',", - " constraint_values = [", - " '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "cpu:armv7',", - " ])"); - BazelMockAndroidSupport.setupPlatformResolvableSdks(mockToolsConfig); - - analysisMock.setupMockClient(mockToolsConfig); - // This line is necessary so an ARM C++ toolchain is available for dependencies under an Android - // split transition. - analysisMock.ccSupport().setupCcToolchainConfigForCpu(mockToolsConfig, "armeabi-v7a"); - } - - @Test - public void chooseSdk() throws Exception { - scratch.file( - "java/a/BUILD", - """ - android_binary( - name = "a", - srcs = ["A.java"], - manifest = "AndroidManifest.xml", - ) - """); - - useConfiguration(EXTRA_SDK_TOOLCHAINS_FLAG, "--platforms=//android_platforms:x86_platform"); - Artifact apkX86 = - getImplicitOutputArtifact( - getConfiguredTarget("//java/a:a"), AndroidRuleClasses.ANDROID_BINARY_APK); - assertThat(getGeneratingSpawnActionArgs(apkX86).get(0)) - .isEqualTo("platform_selected_android_sdks/apksigner_x86_64"); - - useConfiguration(EXTRA_SDK_TOOLCHAINS_FLAG, "--platforms=//android_platforms:arm_platform"); - Artifact apkArm = - getImplicitOutputArtifact( - getConfiguredTarget("//java/a:a"), AndroidRuleClasses.ANDROID_BINARY_APK); - assertThat(getGeneratingSpawnActionArgs(apkArm).get(0)) - .isEqualTo("platform_selected_android_sdks/apksigner_arm"); - } - - @Test - public void chooseNdk() throws Exception { - scratch.file( - "java/a/BUILD", - """ - cc_library( - name = "cclib", - srcs = ["cclib.cc"], - ) - - android_binary( - name = "a", - srcs = ["A.java"], - manifest = "AndroidManifest.xml", - deps = [":cclib"], - ) - """); - - useConfiguration(EXTRA_SDK_TOOLCHAINS_FLAG, "--platforms=//android_platforms:x86_platform"); - ConfiguredTarget x86Binary = getConfiguredTarget("//java/a:a"); - SpawnAction x86Link = - (SpawnAction) getGeneratingAction(getPrerequisiteArtifacts(x86Binary, "deps").get(0)); - // TODO(blaze-team): replace with the commented line below when platform-based resolution works. - assertThat(x86Link.getArguments().get(0)).isEqualTo("/usr/bin/mock-ar"); - // assertThat(cppLinkAction.getLinkCommandLine().getLinkerPathString()) - // .isEqualTo("android/crosstool/x86/bin/i686-linux-android-ar"); - - useConfiguration(EXTRA_SDK_TOOLCHAINS_FLAG, "--platforms=//android_platforms:arm_platform"); - ConfiguredTarget armBinary = getConfiguredTarget("//java/a:a"); - SpawnAction armLink = - (SpawnAction) getGeneratingAction(getPrerequisiteArtifacts(armBinary, "deps").get(0)); - // TODO(blaze-team): replace with the commented line below when platform-based resolution works. - assertThat(armLink.getArguments().get(0)).isEqualTo("/usr/bin/mock-ar"); - // assertThat(cppLinkAction.getLinkCommandLine().getLinkerPathString()) - // .isEqualTo("android/crosstool/arm/bin/arm-linux-androideabi-ar"); - } -} diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java deleted file mode 100644 index d1592ca6c1bb15..00000000000000 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.rules.android.databinding.DataBinding; -import com.google.devtools.build.lib.rules.android.databinding.DataBindingContext; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.Optional; -import java.util.Set; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests {@link AndroidResources} */ -@RunWith(JUnit4.class) -public class AndroidResourcesTest extends ResourceTestBase { - - private static final PathFragment DEFAULT_RESOURCE_ROOT = PathFragment.create(RESOURCE_ROOT); - private static final ImmutableList RESOURCES_ROOTS = - ImmutableList.of(DEFAULT_RESOURCE_ROOT); - - @Before - public void setupCcToolchain() throws Exception { - getAnalysisMock().ccSupport().setupCcToolchainConfigForCpu(mockToolsConfig, "armeabi-v7a"); - } - - @Before - @Test - public void testGetResourceRootsNoResources() throws Exception { - assertThat(getResourceRoots()).isEmpty(); - } - - @Test - public void testGetResourceRootsInvalidResourceDirectory() throws Exception { - try { - getResourceRoots("is-this-drawable-or-values/foo.xml"); - assertWithMessage("Expected exception not thrown!").fail(); - } catch (RuleErrorException e) { - // expected - } - - errorConsumer.assertAttributeError( - "resource_files", "is not in the expected resource directory structure"); - } - - @Test - public void testGetResourceRootsMultipleRoots() throws Exception { - try { - getResourceRoots("subdir/values/foo.xml", "otherdir/values/bar.xml"); - assertWithMessage("Expected exception not thrown!").fail(); - } catch (RuleErrorException e) { - // expected - } - - errorConsumer.assertAttributeError( - "resource_files", "All resources must share a common directory"); - } - - @Test - public void testGetResourceRoots() throws Exception { - assertThat(getResourceRoots("values-hdpi/foo.xml", "values-mdpi/bar.xml")) - .isEqualTo(RESOURCES_ROOTS); - } - - @Test - public void testGetResourceRootsCommonSubdirectory() throws Exception { - assertThat(getResourceRoots("subdir/values-hdpi/foo.xml", "subdir/values-mdpi/bar.xml")) - .containsExactly(DEFAULT_RESOURCE_ROOT.getRelative("subdir")); - } - - private ImmutableList getResourceRoots(String... pathResourceStrings) - throws Exception { - return getResourceRoots(getResources(pathResourceStrings)); - } - - private ImmutableList getResourceRoots(ImmutableList artifacts) - throws Exception { - return AndroidResources.getResourceRoots(errorConsumer, artifacts, "resource_files"); - } - - @Test - public void testFilterEmpty() throws Exception { - assertFilter(ImmutableList.of(), ImmutableList.of()); - } - - @Test - public void testFilterNoop() throws Exception { - ImmutableList resources = getResources("values-en/foo.xml", "values-es/bar.xml"); - assertFilter(resources, resources); - } - - @Test - public void testFilterToEmpty() throws Exception { - assertFilter(getResources("values-en/foo.xml", "values-es/bar.xml"), ImmutableList.of()); - } - - @Test - public void testPartiallyFilter() throws Exception { - Artifact keptResource = getResource("values-en/foo.xml"); - assertFilter( - ImmutableList.of(keptResource, getResource("values-es/bar.xml")), - ImmutableList.of(keptResource)); - } - - @Test - public void testFilterIsDependency() throws Exception { - Artifact keptResource = getResource("values-en/foo.xml"); - assertFilter( - ImmutableList.of(keptResource, getResource("drawable/bar.png")), - ImmutableList.of(keptResource), - /* isDependency = */ true); - } - - @Test - public void testFilterValidatedNoop() throws Exception { - ImmutableList resources = getResources("values-en/foo.xml", "values-es/bar.xml"); - assertFilterValidated(resources, resources); - } - - @Test - public void testFilterValidated() throws Exception { - Artifact keptResource = getResource("values-en/foo.xml"); - assertFilterValidated( - ImmutableList.of(keptResource, getResource("drawable/bar.png")), - ImmutableList.of(keptResource)); - } - - private void assertFilterValidated( - ImmutableList unfilteredResources, ImmutableList filteredResources) - throws Exception { - RuleContext ruleContext = getRuleContext(); - final AndroidDataContext dataContext = AndroidDataContext.forNative(ruleContext); - ValidatedAndroidResources unfiltered = - new AndroidResources(unfilteredResources, getResourceRoots(unfilteredResources)) - .process( - ruleContext, - dataContext, - getManifest(), - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()), - /* neverlink = */ false); - Optional maybeFiltered = - assertFilter(unfiltered, filteredResources, /* isDependency = */ true); - - if (maybeFiltered.isPresent()) { - AndroidResources filtered = maybeFiltered.get(); - assertThat(filtered instanceof ValidatedAndroidResources).isTrue(); - ValidatedAndroidResources validated = ((ValidatedAndroidResources) filtered); - - // Validate fields related to validation are unchanged - assertThat(validated.getRTxt()).isEqualTo(unfiltered.getRTxt()); - assertThat(validated.getAapt2RTxt()).isEqualTo(unfiltered.getAapt2RTxt()); - } - } - - private void assertFilter( - ImmutableList unfilteredResources, ImmutableList filteredResources) - throws Exception { - assertFilter(unfilteredResources, filteredResources, /* isDependency = */ false); - } - - private void assertFilter( - ImmutableList unfilteredResources, - ImmutableList filteredResources, - boolean isDependency) - throws Exception { - AndroidResources unfiltered = - new AndroidResources(unfilteredResources, getResourceRoots(unfilteredResources)); - assertFilter(unfiltered, filteredResources, isDependency); - } - - private Optional assertFilter( - AndroidResources unfiltered, ImmutableList filteredResources, boolean isDependency) - throws Exception { - - ImmutableList.Builder filteredDepsBuilder = ImmutableList.builder(); - - ResourceFilter fakeFilter = - ResourceFilter.of(ImmutableSet.copyOf(filteredResources), filteredDepsBuilder::add); - - Optional filtered = - unfiltered.maybeFilter(errorConsumer, fakeFilter, isDependency); - - if (filteredResources.equals(unfiltered.getResources())) { - // We expect filtering to have been a no-op - assertThat(filtered.isPresent()).isFalse(); - } else { - // The resources and their roots should be filtered - assertThat(filtered.get().getResources()) - .containsExactlyElementsIn(filteredResources) - .inOrder(); - assertThat(filtered.get().getResourceRoots()) - .containsExactlyElementsIn(getResourceRoots(filteredResources)) - .inOrder(); - } - - if (!isDependency) { - // The filter should not record any filtered dependencies - assertThat(filteredDepsBuilder.build()).isEmpty(); - } else { - // The filtered dependencies should be exactly the list of filtered resources - assertThat(unfiltered.getResources()) - .containsExactlyElementsIn( - Iterables.concat(filteredDepsBuilder.build(), filteredResources)); - } - - return filtered; - } - - @Test - public void testParseAndCompile() throws Exception { - RuleContext ruleContext = getRuleContext(); - ParsedAndroidResources parsed = assertParse(ruleContext); - - assertThat(parsed.getCompiledSymbols()).isNotNull(); - - // Since there was no data binding, the compile action should just take in resources and output - // compiled symbols. - assertActionArtifacts( - ruleContext, - /* inputs = */ parsed.getResources(), - /* outputs = */ ImmutableList.of(parsed.getCompiledSymbols())); - } - - @Test - public void testMergeCompiled() throws Exception { - RuleContext ruleContext = getRuleContext(); - ParsedAndroidResources parsed = assertParse(ruleContext); - MergedAndroidResources merged = - parsed.merge( - AndroidDataContext.forNative(ruleContext), - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false)); - - // Besides processed manifest, inherited values should be equal - assertThat(parsed).isEqualTo(new ParsedAndroidResources(merged, parsed.getStampedManifest())); - - // There should be a new processed manifest - assertThat(merged.getManifest()).isNotEqualTo(parsed.getManifest()); - - assertThat(merged.getDataBindingInfoZip()).isNull(); - assertThat(merged.getCompiledSymbols()).isNotNull(); - - // We use the compiled symbols file to build the resource class jar - assertActionArtifacts( - ruleContext, - /*inputs=*/ ImmutableList.of(merged.getCompiledSymbols(), parsed.getManifest()), - /*outputs=*/ ImmutableList.of(merged.getClassJar(), merged.getManifest())); - } - - @Test - public void testValidateAapt2() throws Exception { - RuleContext ruleContext = getRuleContext(); - - MergedAndroidResources merged = makeMergedResources(ruleContext); - ValidatedAndroidResources validated = - merged.validate(AndroidDataContext.forNative(ruleContext)); - - // Inherited values should be equal - assertThat(merged).isEqualTo(new MergedAndroidResources(validated)); - - // aapt artifacts should be generated - assertActionArtifacts( - ruleContext, - /* inputs = */ ImmutableList.of(validated.getCompiledSymbols(), validated.getManifest()), - /* outputs = */ ImmutableList.of( - validated.getRTxt(), validated.getJavaSourceJar(), validated.getApk())); - - // aapt2 artifacts should be recorded - assertThat(validated.getCompiledSymbols()).isNotNull(); - assertThat(validated.getAapt2RTxt()).isNotNull(); - assertThat(validated.getAapt2SourceJar()).isNotNull(); - assertThat(validated.getStaticLibrary()).isNotNull(); - - // Compile the resources into compiled symbols files - assertActionArtifacts( - ruleContext, - /* inputs = */ validated.getResources(), - /* outputs = */ ImmutableList.of(validated.getCompiledSymbols())); - - // Use the compiled symbols and manifest to build aapt2 packaging outputs - assertActionArtifacts( - ruleContext, - /* inputs = */ ImmutableList.of(validated.getCompiledSymbols(), validated.getManifest()), - /* outputs = */ ImmutableList.of( - validated.getAapt2RTxt(), validated.getAapt2SourceJar(), validated.getStaticLibrary())); - } - - @Test - public void testValidate() throws Exception { - RuleContext ruleContext = getRuleContext(); - - makeMergedResources(ruleContext).validate(AndroidDataContext.forNative(ruleContext)); - - Set actionMnemonics = - ruleContext.getAnalysisEnvironment().getRegisteredActions().stream() - .map(ActionAnalysisMetadata::getMnemonic) - .collect(ImmutableSet.toImmutableSet()); - // These are unfortunately the mnemonics used in Bazel; these should be changed once aapt1 is - // removed. - assertThat(actionMnemonics).contains("AndroidResourceLink"); // aapt2 validation - assertThat(actionMnemonics).doesNotContain("AndroidResourceValidator"); // aapt1 validation - } - - @Test - public void testGenerateRClass() throws Exception { - RuleContext ruleContext = getRuleContext(); - Artifact rTxt = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT); - ProcessedAndroidManifest manifest = getManifest(); - - ProcessedAndroidData processedData = - ProcessedAndroidData.of( - makeParsedResources(ruleContext), - AndroidAssets.from(ruleContext) - .process(AndroidDataContext.forNative(ruleContext), AssetDependencies.empty()), - manifest, - rTxt, - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_JAVA_SOURCE_JAR), - ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK), - /* dataBindingInfoZip = */ null, - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false), - null, - null); - - ValidatedAndroidResources validated = - processedData - .generateRClass(AndroidDataContext.forNative(ruleContext)) - .getValidatedResources(); - - // An action to generate the R.class file should be registered. - assertActionArtifacts( - ruleContext, - /* inputs = */ ImmutableList.of(rTxt, manifest.getManifest()), - /* outputs = */ ImmutableList.of(validated.getJavaClassJar())); - } - - @Test - public void testProcessBinaryDataGeneratesProguardOutput() throws Exception { - RuleContext ruleContext = getRuleContext("android_binary", "manifest='AndroidManifest.xml',"); - AndroidDataContext dataContext = AndroidDataContext.forNative(ruleContext); - - ResourceApk resourceApk = - ProcessedAndroidData.processBinaryDataFrom( - dataContext, - ruleContext, - getManifest(), - false, - ImmutableMap.of(), - AndroidResources.empty(), - AndroidAssets.empty(), - ResourceDependencies.empty(), - AssetDependencies.empty(), - ResourceFilterFactory.empty(), - ImmutableList.of(), - false, - DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig())) - .generateRClass(dataContext); - - assertThat(resourceApk.getResourceProguardConfig()).isNotNull(); - assertThat(resourceApk.getMainDexProguardConfig()).isNotNull(); - } - - /** - * Validates that a parse action was invoked correctly. Returns the {@link ParsedAndroidResources} - * for further validation. - */ - private ParsedAndroidResources assertParse(RuleContext ruleContext) throws Exception { - return assertParse( - ruleContext, - DataBinding.contextFrom( - ruleContext, ruleContext.getConfiguration().getFragment(AndroidConfiguration.class))); - } - - private ParsedAndroidResources assertParse( - RuleContext ruleContext, DataBindingContext dataBindingContext) throws Exception { - ImmutableList resources = getResources("values-en/foo.xml", "drawable-hdpi/bar.png"); - AndroidResources raw = - new AndroidResources( - resources, AndroidResources.getResourceRoots(ruleContext, resources, "resource_files")); - StampedAndroidManifest manifest = getManifest(); - - ParsedAndroidResources parsed = - raw.parse( - AndroidDataContext.forNative(ruleContext), - manifest, - dataBindingContext); - - // Inherited values should be equal - assertThat(raw).isEqualTo(new AndroidResources(parsed)); - - // Label should be set from RuleContext - assertThat(parsed.getLabel()).isEqualTo(ruleContext.getLabel()); - - return parsed; - } - - private MergedAndroidResources makeMergedResources(RuleContext ruleContext) - throws RuleErrorException, InterruptedException { - return makeParsedResources(ruleContext) - .merge( - AndroidDataContext.forNative(ruleContext), - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false)); - } - - private ParsedAndroidResources makeParsedResources(RuleContext ruleContext) - throws RuleErrorException, InterruptedException { - DataBindingContext dataBindingContext = - DataBinding.contextFrom( - ruleContext, ruleContext.getConfiguration().getFragment(AndroidConfiguration.class)); - return makeParsedResources(ruleContext, dataBindingContext); - } - - private ParsedAndroidResources makeParsedResources( - RuleContext ruleContext, DataBindingContext dataBindingContext) - throws RuleErrorException, InterruptedException { - ImmutableList resources = getResources("values-en/foo.xml", "drawable-hdpi/bar.png"); - return new AndroidResources( - resources, AndroidResources.getResourceRoots(ruleContext, resources, "resource_files")) - .parse( - AndroidDataContext.forNative(ruleContext), - getManifest(), - dataBindingContext); - } - - private ProcessedAndroidManifest getManifest() { - return new ProcessedAndroidManifest( - getResource("some/path/AndroidManifest.xml"), "some.java.pkg", /* exported = */ true); - } - - /** Gets a dummy rule context object by creating a dummy target. */ - private RuleContext getRuleContext() throws Exception { - return getRuleContext("android_library"); - } - - /** Gets a dummy rule context object by creating a dummy target. */ - private RuleContext getRuleContext(String kind, String... additionalLines) throws Exception { - ConfiguredTarget target = - scratchConfiguredTarget( - "java/foo", - "target", - ImmutableList.builder() - .add(kind + "(name = 'target',") - .add(additionalLines) - .add(")") - .build() - .toArray(new String[0])); - return getRuleContextForActionTesting(target); - } -} diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/BUILD b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD index 4b59082722e5e0..8fba7eca3eadc4 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD @@ -24,17 +24,6 @@ java_test( ], ) -java_test( - name = "AndroidCommonTest", - srcs = ["AndroidCommonTest.java"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//third_party:junit4", - "//third_party:truth", - ], -) - java_library( name = "AndroidBuildViewTestCase", srcs = ["AndroidBuildViewTestCase.java"], @@ -63,107 +52,6 @@ java_library( ], ) -java_test( - name = "AndroidBinaryTest", - timeout = "long", - srcs = ["AndroidBinaryTest.java"], - shard_count = 5, - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/actions", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:actions/parameter_file_write_action", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/analysis:file_provider", - "//src/main/java/com/google/devtools/build/lib/analysis:required_config_fragments_provider", - "//src/main/java/com/google/devtools/build/lib/cmdline", - "//src/main/java/com/google/devtools/build/lib/collect/nestedset", - "//src/main/java/com/google/devtools/build/lib/events", - "//src/main/java/com/google/devtools/build/lib/packages", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/main/java/com/google/devtools/build/lib/rules/cpp", - "//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation", - "//src/main/java/com/google/devtools/build/lib/skyframe:configured_target_and_data", - "//src/main/java/com/google/devtools/build/lib/util:filetype", - "//src/main/java/com/google/devtools/build/lib/vfs", - "//src/main/protobuf:android_deploy_info_java_proto", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//src/test/java/com/google/devtools/build/lib/analysis/util", - "//src/test/java/com/google/devtools/build/lib/packages:testutil", - "//src/test/java/com/google/devtools/build/lib/rules/java:java_compile_action_test_helper", - "//src/test/java/com/google/devtools/build/lib/testutil", - "//src/test/java/com/google/devtools/build/lib/testutil:JunitUtils", - "//src/test/java/com/google/devtools/build/lib/testutil:TestConstants", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidPlatformsTest", - srcs = ["AndroidPlatformsTest.java"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/test/java/com/google/devtools/build/lib/packages:testutil", - "//src/test/java/com/google/devtools/build/lib/testutil:TestConstants", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "ResourceFilterFactoryTest", - srcs = ["ResourceFilterFactoryTest.java"], - deps = [ - ":ResourceTestBase", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidResourcesTest", - srcs = ["AndroidResourcesTest.java"], - deps = [ - ":ResourceTestBase", - "//src/main/java/com/google/devtools/build/lib/actions", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/packages", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidAssetsTest", - srcs = ["AndroidAssetsTest.java"], - deps = [ - ":ResourceTestBase", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/collect/nestedset", - "//src/main/java/com/google/devtools/build/lib/packages", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - java_library( name = "ResourceTestBase", srcs = ["ResourceTestBase.java"], @@ -190,109 +78,6 @@ java_library( ], ) -java_test( - name = "AndroidDeviceScriptFixtureTest", - srcs = ["AndroidDeviceScriptFixtureTest.java"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidHostServiceFixtureTest", - srcs = ["AndroidHostServiceFixtureTest.java"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidLibraryTest", - srcs = ["AndroidLibraryTest.java"], - shard_count = 5, - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/actions", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:config/core_option_converters", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/cmdline", - "//src/main/java/com/google/devtools/build/lib/collect/nestedset", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation", - "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//src/test/java/com/google/devtools/build/lib/rules/java:java_compile_action_test_helper", - "//src/test/java/com/google/devtools/build/lib/testutil:TestConstants", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_library( - name = "AndroidMultidexBaseTest", - srcs = ["AndroidMultidexBaseTest.java"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/cmdline", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - -java_test( - name = "AndroidBinaryMultidexTest", - srcs = ["AndroidBinaryMultidexTest.java"], - deps = [ - ":AndroidMultidexBaseTest", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//third_party:junit4", - ], -) - -java_test( - name = "AndroidDataBindingV2Test", - timeout = "long", - srcs = ["AndroidDataBindingV2Test.java"], - tags = ["manual"], - deps = [ - ":AndroidBuildViewTestCase", - "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", - "//src/main/java/com/google/devtools/build/lib/cmdline", - "//src/main/java/com/google/devtools/build/lib/collect/nestedset", - "//src/main/java/com/google/devtools/build/lib/rules/android", - "//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation", - "//src/main/protobuf:extra_actions_base_java_proto", - "//src/test/java/com/google/devtools/build/lib/actions/util", - "//src/test/java/com/google/devtools/build/lib/packages:testutil", - "//src/test/java/com/google/devtools/build/lib/rules/java:java_compile_action_test_helper", - "//third_party:guava", - "//third_party:junit4", - "//third_party:truth", - ], -) - java_test( name = "AndroidSdkTest", srcs = ["AndroidSdkTest.java"], diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java deleted file mode 100644 index 31da8c0284f67a..00000000000000 --- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// -// 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.google.devtools.build.lib.rules.android; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests {@link ResourceFilterFactory}. */ -@RunWith(JUnit4.class) -public class ResourceFilterFactoryTest extends ResourceTestBase { - - @Before - public void setupCcToolchain() throws Exception { - getAnalysisMock().ccSupport().setupCcToolchainConfigForCpu(mockToolsConfig, "armeabi-v7a"); - } - - @Test - public void parseRuleAttributes() throws Exception { - ConfiguredTarget target = - scratchConfiguredTarget( - "java/com/pkg", - "pkg", - "android_binary(", - " name = 'pkg',", - " manifest = 'AndroidManifest.xml',", - " resource_configuration_filters = ['en', 'es'],", - " densities = ['hdpi', 'ldpi'],", - ")"); - - ResourceFilterFactory rff = - ResourceFilterFactory.fromRuleContextAndAttrs(getRuleContext(target)); - - assertThat(rff.getConfigurationFilterString()).isEqualTo("en,es"); - assertThat(rff.getDensityString()).isEqualTo("hdpi,ldpi"); - } -} diff --git a/src/test/shell/bazel/android/BUILD b/src/test/shell/bazel/android/BUILD index a64f9397968c96..2c7a20ea0f641b 100644 --- a/src/test/shell/bazel/android/BUILD +++ b/src/test/shell/bazel/android/BUILD @@ -27,128 +27,7 @@ sh_library( ], ) -android_sh_test( - name = "android_integration_test", - size = "enormous", - srcs = ["android_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], - tags = [ - # See https://github.com/bazelbuild/bazel/issues/18431. - "no-remote", - "no_windows", - # bzlmod test requires network - "requires-network", - ], -) - -android_sh_test( - name = "aapt_integration_test", - size = "large", - srcs = ["aapt_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], -) - -android_sh_test( - name = "proguard_integration_test", - size = "medium", - srcs = ["proguard_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], -) - -android_sh_test( - name = "android_sdk_integration_test", - size = "large", - srcs = ["android_sdk_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], - shard_count = 3, - tags = [ - "no_windows", - ], -) - -android_sh_test( - name = "aidl_integration_test", - size = "medium", - srcs = ["aidl_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], -) - -android_sh_test( - name = "desugarer_integration_test", - size = "large", - srcs = ["desugarer_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], - tags = [ - "no_windows", - ], -) - -android_sh_test( - name = "library_desugarer_integration_test", - size = "small", - srcs = ["library_desugarer_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], - tags = [ - "manual", # TODO(b/299338002): D8 library desugaring is broken. - "no_windows", - ], -) - -android_sh_test( - name = "android_instrumentation_test_integration_test", - size = "medium", - srcs = ["android_instrumentation_test_integration_test.sh"], - data = [ - ":android_helper", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], - shard_count = 4, - tags = [ - "no_windows", - ], -) - -android_sh_test( - name = "resource_processing_integration_test", - size = "large", - srcs = ["resource_processing_integration_test.sh"], - data = [ - ":android_helper", - ":testdata/roboto.ttf", - "//external:android_sdk_for_testing", - "//src/test/shell/bazel:test-deps", - ], -) - +# TODO(ahumesky): Migrate this to the rules_android repo and refactor it to use the Starlark rules when DexFileSplitter is migrated to rules_android android_sh_test( name = "DexFileSplitter_synthetic_classes_test", size = "large", @@ -162,6 +41,7 @@ android_sh_test( ], shard_count = 2, tags = [ + "manual", "no_windows", ], ) diff --git a/src/test/shell/bazel/android/aapt_integration_test.sh b/src/test/shell/bazel/android/aapt_integration_test.sh deleted file mode 100755 index 9132f3b4f5b453..00000000000000 --- a/src/test/shell/bazel/android/aapt_integration_test.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# 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. - -# For these tests to run do the following: -# -# 1. Install an Android SDK from https://developer.android.com -# 2. Set the $ANDROID_HOME environment variable -# 3. Uncomment the line in WORKSPACE containing android_sdk_repository -# -# Note that if the environment is not set up as above android_integration_test -# will silently be ignored and will be shown as passing. - -# --- begin runfiles.bash initialization v2 --- -# Copy-pasted from the Bazel Bash runfiles library v2. -set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash -source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -# TODO(#8169): Make this test compatible with Python toolchains. Blocked on the -# fact that there's no PY3 environment on our Mac workers -# (bazelbuild/continuous-integration#578). -add_to_bazelrc "build --incompatible_use_python_toolchains=false" - -resolve_android_toolchains - -function test_build_with_aapt2() { - create_new_workspace - setup_android_sdk_support - create_android_binary - - assert_build //java/bazel:bin -} - -run_suite "aapt2 integration test" diff --git a/src/test/shell/bazel/android/aidl_integration_test.sh b/src/test/shell/bazel/android/aidl_integration_test.sh deleted file mode 100755 index 6a35a4827ee49b..00000000000000 --- a/src/test/shell/bazel/android/aidl_integration_test.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Bazel Authors. All rights reserved. -# -# 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. - -# --- begin runfiles.bash initialization v2 --- -# Copy-pasted from the Bazel Bash runfiles library v2. -set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash -source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function test_simple_idl_srcs() { - create_new_workspace - setup_android_sdk_support - - mkdir -p java/com/example - cat > java/com/example/BUILD < java/com/example/AndroidManifest.xml < -EOF - cat > java/com/example/ILib.aidl < java/com/example/Lib.java < java/com/example/Bin.java <&2; exit 1; } -fail_if_no_android_sdk - -source "${CURRENT_DIR}/../../integration_test_setup.sh" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -# TODO(#8169): Make this test compatible with Python toolchains. Blocked on the -# fact that there's no PY3 environment on our Mac workers -# (bazelbuild/continuous-integration#578). -add_to_bazelrc "build --incompatible_use_python_toolchains=false" - -resolve_android_toolchains - -function setup_android_instrumentation_test_env() { - mkdir -p java/com/bin/res/values - mkdir -p javatests/com/bin - - # Targets for android_binary application under test - cat > java/com/bin/BUILD < java/com/bin/AndroidManifest.xml < - -EOF - cat > java/com/bin/Bar.java < java/com/bin/res/values/values.xml < - - -EOF - - # Targets for instrumentation android_binary - cat > javatests/com/bin/BUILD < javatests/com/bin/AndroidManifest.xml < - - - -EOF - cat > javatests/com/bin/BarTest.java < javatests/com/bin/AndroidManifest.xml < - - - -EOF - - assert_build_fails //javatests/com/bin:instr \ - "does not match the package name of" -} - -function test_multiple_instrumentations_with_different_package_names_build_failure() { - create_new_workspace - setup_android_sdk_support - setup_android_instrumentation_test_env - - cat > javatests/com/bin/AndroidManifest.xml < - - - - -EOF - - assert_build_fails //javatests/com/bin:instr \ - "do not reference the same target package" -} - -function test_android_instrumentation_binary_class_filtering() { - create_new_workspace - setup_android_sdk_support - mkdir -p java/com/bin - cat > java/com/bin/BUILD < java/com/bin/AndroidManifest.xml < -EOF - cat > java/com/bin/TestAndroidManifest.xml < - - - -EOF - cat > java/com/bin/Foo.java < java/com/bin/Bar.java < java/com/bin/Baz.java < java/com/bin/res/values/values.xml < - - -EOF - assert_build //java/com/bin:instr - output_classes=$(zipinfo -1 bazel-bin/java/com/bin/instr_filtered.jar) - assert_one_of $output_classes "META-INF/MANIFEST.MF" - assert_one_of $output_classes "com/bin/Foo.class" - assert_not_one_of $output_classes "com/bin/R.class" - assert_not_one_of $output_classes "com/bin/Bar.class" - assert_not_one_of $output_classes "com/bin/Baz.class" -} - -run_suite "android_instrumentation_test integration tests" - diff --git a/src/test/shell/bazel/android/android_integration_test.sh b/src/test/shell/bazel/android/android_integration_test.sh deleted file mode 100755 index cee113600725ad..00000000000000 --- a/src/test/shell/bazel/android/android_integration_test.sh +++ /dev/null @@ -1,444 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Bazel Authors. All rights reserved. -# -# 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. - -# For these tests to run do the following: -# -# 1. Install an Android SDK from https://developer.android.com -# 2. Set the $ANDROID_HOME environment variable -# 3. Uncomment the line in WORKSPACE containing android_sdk_repository -# -# Note that if the environment is not set up as above android_integration_test -# will silently be ignored and will be shown as passing. - -# Load the test setup defined in the parent directory -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -source "${CURRENT_DIR}/android_helper.sh" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "${CURRENT_DIR}/../../integration_test_setup.sh" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function test_allow_custom_manifest_name() { - create_new_workspace - setup_android_sdk_support - create_android_binary - mv java/bazel/AndroidManifest.xml java/bazel/SomeOtherName.xml - - # macOS requires an argument for the backup file extension. - sed -i'' -e 's/AndroidManifest/SomeOtherName/' java/bazel/BUILD - - bazel build //java/bazel:bin || fail "Build failed" \ - "Failed to build android_binary with custom Android manifest file name" -} - -function test_legacy_multidex() { - create_new_workspace - setup_android_sdk_support - create_android_binary - mkdir -p java/bazel/multidex - cat > java/bazel/multidex/BUILD < java/bazel/multidex/AndroidManifest.xml < -EOF - assert_build //java/bazel/multidex:bin -} - -function write_hello_android_files() { - mkdir -p java/com/example/hello - mkdir -p java/com/example/hello/res/values - cat > java/com/example/hello/res/values/strings.xml <<'EOF' - - HelloWorld - Hello Main - -EOF - - cat > java/com/example/hello/AndroidManifest.xml <<'EOF' - - - - - - - - - - - - - -EOF - - cat > java/com/example/hello/MainActivity.java <<'EOF' -package com.example.hello; - -import android.app.Activity; - -public class MainActivity extends Activity { -} -EOF - -} - -function test_apk_manifest_created_by() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = 'hello', - manifest = "AndroidManifest.xml", - srcs = ['MainActivity.java'], - resource_files = glob(["res/**"]), -) -EOF - - bazel clean - bazel build //java/com/example/hello:hello || fail "build failed" - jar xf bazel-bin/java/com/example/hello/hello.apk - # Check that the apk manifest contains Created-By: Bazel. - assert_contains "Created\-By: Bazel" META-INF/MANIFEST.MF - # Clean up the extracted manifest. - rm META-INF/MANIFEST.MF -} - -function test_d8_dexes_hello_android() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = 'hello', - manifest = "AndroidManifest.xml", - srcs = ['MainActivity.java'], - resource_files = glob(["res/**"]), -) -EOF - - bazel clean - bazel build --define=android_standalone_dexing_tool=d8_compat_dx \ - //java/com/example/hello:hello || fail "build failed" -} - -function test_d8_dexes_and_sandbox_desugars_hello_android() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = 'hello', - manifest = "AndroidManifest.xml", - srcs = ['MainActivity.java'], - resource_files = glob(["res/**"]), -) -EOF - - bazel clean - bazel build --define=android_standalone_dexing_tool=d8_compat_dx \ - --strategy=Desugar=sandboxed \ - //java/com/example/hello:hello || fail "build failed" -} - -function test_d8_dexes_and_worker_desugars_hello_android() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = 'hello', - manifest = "AndroidManifest.xml", - srcs = ['MainActivity.java'], - resource_files = glob(["res/**"]), -) -EOF - - bazel clean - bazel build --define=android_standalone_dexing_tool=d8_compat_dx \ - --strategy=Desugar=worker \ - //java/com/example/hello:hello || fail "build failed" -} - -function test_hello_android_bzlmod() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = 'hello', - manifest = "AndroidManifest.xml", - srcs = ['MainActivity.java'], - resource_files = glob(["res/**"]), -) -EOF - - # The next line ensures that the test passes in IPv6-only networks. - export JAVA_TOOL_OPTIONS="-Djava.net.preferIPv6Addresses=true" - - bazel clean - # Check that android builds with bzlmod enable work. - bazel build --experimental_enable_bzlmod \ - //java/com/example/hello:hello || fail "build failed" -} - -function test_android_tools_version() { - create_new_workspace - setup_android_sdk_support - - cat >> WORKSPACE < "$f" - echo "public class $class {" >> "$f" - for i in $(seq 33000); do - echo "public int foo_$i() { return $i ; }" >> "$f" - done - echo "}" >> "$f" -} - -function assert_multiple_dex_files() { - apk="bazel-bin/java/com/example/hello/hello.apk" - count=$(unzip -l ${apk} | grep classes | wc -l) - [ "${count}" -gt 1 ] || \ - fail "Expected multiple dex files in apk, found ${count}" -} - -function test_native_multidex() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - multidex = "native", -) -EOF - - write_large_java_file java/com/example/hello/Lib1.java - write_large_java_file java/com/example/hello/Lib2.java - - bazel build java/com/example/hello:hello || fail "build failed" - assert_multiple_dex_files -} - -function test_manual_main_dex() { - # Substantially cribbed from test_native_multidex() - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -genrule( - name = "main_dex_list_txt", - cmd = "echo com.example.hello > $@", - outs = ["main_dex_list.txt"], -) -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - multidex = "manual_main_dex", - main_dex_list = ":main_dex_list_txt", -) -EOF - - write_large_java_file java/com/example/hello/Lib1.java - write_large_java_file java/com/example/hello/Lib2.java - - bazel build java/com/example/hello:hello || fail "build failed" - assert_multiple_dex_files -} - -function test_native_multidex_proguard() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - multidex = "native", - proguard_specs = ["proguard.cfg"], -) -EOF - - cat > java/com/example/hello/proguard.cfg <<'EOF' --keep class com.example.hello.** --keep class com.example.hello.Lib1 { - public int foo*(); -} --keep class com.example.hello.Lib2 { - public int foo*(); -} -EOF - - write_large_java_file java/com/example/hello/Lib1.java - write_large_java_file java/com/example/hello/Lib2.java - - bazel build java/com/example/hello:hello || fail "build failed" - # Ensures that we didn't accidentally optimize away all the unused methods. - assert_multiple_dex_files -} - -function test_native_multidex_dex_shards() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - multidex = "native", - dex_shards = 10, -) -EOF - - write_large_java_file java/com/example/hello/Lib1.java - write_large_java_file java/com/example/hello/Lib2.java - - bazel build java/com/example/hello:hello || fail "build failed" - assert_multiple_dex_files -} - -function test_native_multidex_dex_shards_proguard() { - write_hello_android_files - setup_android_sdk_support - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - multidex = "native", - proguard_specs = ["proguard.cfg"], - dex_shards = 10, -) -EOF - - cat > java/com/example/hello/proguard.cfg <<'EOF' --keep class com.example.hello.** --keep class com.example.hello.Lib1 { - public int foo*(); -} --keep class com.example.hello.Lib2 { - public int foo*(); -} -EOF - - write_large_java_file java/com/example/hello/Lib1.java - write_large_java_file java/com/example/hello/Lib2.java - - bazel build java/com/example/hello:hello || fail "build failed" - # Ensures that we didn't accidentally optimize away all the unused methods. - assert_multiple_dex_files -} - -function test_reduce_merged_assets() { - write_hello_android_files - setup_android_sdk_support - mkdir -p java/com/example/hello/assets - echo hello > java/com/example/hello/assets/hello.txt - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - deps = [":hello_lib"], -) -android_library( - name = "hello_lib", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - assets_dir = "assets", - assets = glob(["assets/**"]), -) -EOF - # The standard behavior is to output the merged assets as assets.zip - bazel build //java/com/example/hello:hello_lib --output_library_merged_assets || fail "build failed" - local tmpdir=$(mktemp -d) - # Expect the assets.zip to exist. - unzip bazel-bin/java/com/example/hello/hello_lib_files/assets.zip -d $tmpdir - # Expect that hello.txt contains hello. - assert_contains "hello" $tmpdir/assets/hello.txt - rm -rf $tmpdir -} - -function test_dont_reduce_merged_assets() { - write_hello_android_files - setup_android_sdk_support - mkdir -p java/com/example/hello/assets - echo hello > java/com/example/hello/assets/hello.txt - cat > java/com/example/hello/BUILD <<'EOF' -android_binary( - name = "hello", - manifest = "AndroidManifest.xml", - deps = [":hello_lib"], -) -android_library( - name = "hello_lib", - manifest = "AndroidManifest.xml", - srcs = glob(["*.java"]), - resource_files = glob(["res/**"]), - assets_dir = "assets", - assets = glob(["assets/**"]), -) -EOF - bazel build //java/com/example/hello:hello --nooutput_library_merged_assets || fail "build failed" - # Expect assets.zip to NOT exist. - if [[ -f bazel-bin/java/com/example/hello/hello_lib_files/assets.zip ]]; then - fail "assets.zip should NOT exist!" - fi -} - -run_suite "Android integration tests" diff --git a/src/test/shell/bazel/android/android_sdk_integration_test.sh b/src/test/shell/bazel/android/android_sdk_integration_test.sh deleted file mode 100755 index 4eab214d26efb9..00000000000000 --- a/src/test/shell/bazel/android/android_sdk_integration_test.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Bazel Authors. All rights reserved. -# -# 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. - -# For these tests to run do the following: -# -# 1. Install an Android SDK from https://developer.android.com -# 2. Set the $ANDROID_HOME environment variable -# 3. Uncomment the line in WORKSPACE containing android_sdk_repository -# -# Note that if the environment is not set up as above android_integration_test -# will silently be ignored and will be shown as passing. - -# Load the test setup defined in the parent directory -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -source "${CURRENT_DIR}/android_helper.sh" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "${CURRENT_DIR}/../../integration_test_setup.sh" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function test_android_sdk_repository_path_from_environment() { - create_new_workspace - setup_android_sdk_support - # Overwrite WORKSPACE that was created by setup_android_sdk_support with one - # that does not set the path attribute of android_sdk_repository. - rm WORKSPACE - cat >> WORKSPACE <> WORKSPACE <& $TEST_log && fail "Should have failed" || true - expect_log "Either the path attribute of android_sdk_repository" -} - -function test_android_sdk_repository_wrong_path() { - create_new_workspace - setup_android_platforms - mkdir "$TEST_SRCDIR/some_dir" - cat >> WORKSPACE <& $TEST_log && fail "Should have failed" || true - expect_log "Unable to read the Android SDK at $TEST_SRCDIR/some_dir, the path may be invalid." \ - " Is the path in android_sdk_repository() or \$ANDROID_SDK_HOME set correctly?" -} - -# Regression test for https://github.com/bazelbuild/bazel/issues/2621. -function test_android_sdk_repository_returns_null_if_env_vars_missing() { - create_new_workspace - setup_android_sdk_support - ANDROID_HOME=/does_not_exist_1 bazel build @androidsdk//:files || \ - fail "Build failed" - sed -i -e 's/path =/#path =/g' WORKSPACE - ANDROID_HOME=/does_not_exist_2 bazel build @androidsdk//:files && \ - fail "Build should have failed" - ANDROID_HOME=$ANDROID_SDK bazel build @androidsdk//:files || fail "Build failed" -} - -# Regression test for https://github.com/bazelbuild/bazel/issues/12069 -function test_android_sdk_repository_present_not_set() { - create_new_workspace - setup_android_platforms - cat >> WORKSPACE < a/BUILD < a/helper.sh </dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function create_java_8_android_binary() { - mkdir -p java/bazel - cat > java/bazel/BUILD < java/bazel/AndroidManifest.xml < - - - - - - - - - - - - -EOF - - cat > java/bazel/MainActivity.java < a * b; - } - - int someHashcode() { - // JDK 8 language feature depending on primitives desugar - return java.lang.Long.hashCode(42L); - } - - int getSumOfInts() { - // JDK 8 language feature depending on streams desugar - return Arrays - .asList("x1", "x2", "x3") - .stream() - .map(s -> s.substring(1)) - .mapToInt(Integer::parseInt) - .sum(); - } -} -EOF -} - -function test_java_8_android_binary() { - create_new_workspace - setup_android_sdk_support - create_java_8_android_binary - - # Test desugar in sandboxed mode, or fallback to standalone for Windows. - bazel build \ - --strategy=Desugar=sandboxed \ - --desugar_for_android //java/bazel:bin \ - || fail "build failed" -} - -function test_java_8_android_binary_worker_strategy() { - create_new_workspace - setup_android_sdk_support - create_java_8_android_binary - - assert_build //java/bazel:bin \ - --persistent_android_dex_desugar \ - --worker_verbose &> $TEST_log - expect_log "Created new non-sandboxed Desugar worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed DexBuilder worker (id [0-9]\+, key hash -\?[0-9]\+)" -} - -function test_java_8_android_binary_multiplex_worker_strategy() { - create_new_workspace - setup_android_sdk_support - create_java_8_android_binary - - assert_build //java/bazel:bin \ - --worker_multiplex \ - --persistent_multiplex_android_dex_desugar \ - --worker_verbose &> $TEST_log - expect_log "Created new non-sandboxed Desugar multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed DexBuilder multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" -} - -run_suite "Android desugarer integration tests" diff --git a/src/test/shell/bazel/android/library_desugarer_integration_test.sh b/src/test/shell/bazel/android/library_desugarer_integration_test.sh deleted file mode 100755 index b8b5000066d35d..00000000000000 --- a/src/test/shell/bazel/android/library_desugarer_integration_test.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# -# Copyright 2023 The Bazel Authors. All rights reserved. -# -# 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. - -# To run this test, ensure that //external:android_sdk_for_testing is set to -# the @androidsdk//:files filegroup created by the AndroidSdkRepositoryFunction. -# If this is not set, this test will silently pass so as to prevent compile.sh -# from failing for developers without an Android SDK. See the BUILD file for -# more details. - -# --- begin runfiles.bash initialization v2 --- -# Copy-pasted from the Bazel Bash runfiles library v2. -set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash -source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function test_library_desugar_lib_builds() { - # TODO(b/299338002): Move this to the main desugarer test suite. - create_new_workspace - setup_android_sdk_support - create_android_binary - - assert_build @bazel_tools//tools/android:desugar_java8_legacy_libs -} - -function test_library_desugaring() { - # TODO(b/299338002): Move this to the main desugarer test suite. - create_new_workspace - setup_android_sdk_support - create_android_binary - - assert_build //java/bazel:bin --desugar_java8_libs --experimental_check_desugar_deps -} - -run_suite "Android library desugaring integration tests" - diff --git a/src/test/shell/bazel/android/proguard_integration_test.sh b/src/test/shell/bazel/android/proguard_integration_test.sh deleted file mode 100755 index 869589de67919a..00000000000000 --- a/src/test/shell/bazel/android/proguard_integration_test.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Bazel Authors. All rights reserved. -# -# 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. - -# For these tests to run do the following: -# -# 1. Install an Android SDK from https://developer.android.com -# 2. Set the $ANDROID_HOME environment variable -# 3. Uncomment the line in WORKSPACE containing android_sdk_repository - -# --- begin runfiles.bash initialization v2 --- -# Copy-pasted from the Bazel Bash runfiles library v2. -set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash -source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function test_proguard() { - create_new_workspace - setup_android_sdk_support - mkdir -p java/com/bin - cat > java/com/bin/BUILD < java/com/bin/AndroidManifest.xml < -EOF - cat > java/com/bin/Bin.java < java/com/bin/Filtered.java < java/com/bin/NotUsed.java < java/com/bin/Renamed.java < java/com/bin/Lib.java < java/com/bin/proguard.config </dev/null || \ - source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ - source "$0.runfiles/$f" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ - { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e -# --- end runfiles.bash initialization v2 --- - -source "$(rlocation io_bazel/src/test/shell/bazel/android/android_helper.sh)" \ - || { echo "android_helper.sh not found!" >&2; exit 1; } -fail_if_no_android_sdk - -source "$(rlocation io_bazel/src/test/shell/integration_test_setup.sh)" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -resolve_android_toolchains - -function setup_font_resources() { - rm java/bazel/BUILD - - cat > java/bazel/BUILD < java/bazel/res/values/styles.xml < - - - -EOF - - cat > java/bazel/AndroidManifest.xml < - - - - - - - - -EOF -} - -function test_font_support() { - create_new_workspace - setup_android_sdk_support - create_android_binary - setup_font_resources - - assert_build //java/bazel:bin -} - -function test_persistent_resource_processor() { - create_new_workspace - setup_android_sdk_support - create_android_binary - setup_font_resources - - assert_build //java/bazel:bin --persistent_android_resource_processor \ - --worker_verbose &> $TEST_log - expect_log "Created new non-sandboxed AndroidResourceParser worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidResourceCompiler worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidCompiledResourceMerger worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidAapt2 worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed ManifestMerger worker (id [0-9]\+, key hash -\?[0-9]\+)" -} - -function test_persistent_multiplex_resource_processor() { - create_new_workspace - setup_android_sdk_support - create_android_binary - setup_font_resources - - assert_build //java/bazel:bin --worker_multiplex \ - --persistent_multiplex_android_tools \ - --worker_verbose &> $TEST_log - expect_log "Created new non-sandboxed AndroidResourceParser multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidResourceCompiler multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidCompiledResourceMerger multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed AndroidAapt2 multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" - expect_log "Created new non-sandboxed ManifestMerger multiplex-worker (id [0-9]\+, key hash -\?[0-9]\+)" -} - -run_suite "Resource processing integration tests"