From 98f9c4f765e0eb4d5d1b63e4f58642aa9aea2bb8 Mon Sep 17 00:00:00 2001 From: Zhaoqing Xu Date: Wed, 8 Mar 2023 09:37:52 -0800 Subject: [PATCH 1/2] Creates an AndroidDexInfo provider to pass dex related artifacts from Starlark to Native Bazel. PiperOrigin-RevId: 515061110 Change-Id: Ieefe430582c01264fb510de3ac1017d3332f51aa --- .../bazel/rules/BazelRuleClassProvider.java | 4 +- .../lib/rules/android/AndroidDexInfo.java | 80 ++++++++++++++ .../android/AndroidBootstrap.java | 4 +- .../android/AndroidDexInfoApi.java | 100 ++++++++++++++++++ 4 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java create mode 100644 src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java 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 55e0b1178b05b1..3e8c2fd7ae074c 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 @@ -69,6 +69,7 @@ import com.google.devtools.build.lib.rules.android.AndroidDeviceBrokerInfo; import com.google.devtools.build.lib.rules.android.AndroidDeviceRule; 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; @@ -423,7 +424,8 @@ public void init(ConfiguredRuleClassProvider.Builder builder) { ProguardMappingProvider.PROVIDER, AndroidBinaryDataInfo.PROVIDER, AndroidBinaryNativeLibsInfo.PROVIDER, - BaselineProfileProvider.PROVIDER); + BaselineProfileProvider.PROVIDER, + AndroidDexInfo.PROVIDER); builder.addStarlarkBootstrap(bootstrap); try { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java new file mode 100644 index 00000000000000..8ee0db2b272a13 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java @@ -0,0 +1,80 @@ +// 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. +package com.google.devtools.build.lib.rules.android; + +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.BuiltinProvider; +import com.google.devtools.build.lib.packages.NativeInfo; +import com.google.devtools.build.lib.starlarkbuildapi.android.AndroidDexInfoApi; +import net.starlark.java.eval.EvalException; + +/** A provider for Android Dex artifacts */ +@Immutable +public class AndroidDexInfo extends NativeInfo implements AndroidDexInfoApi { + + public static final String PROVIDER_NAME = "AndroidDexInfo"; + public static final Provider PROVIDER = new Provider(); + + private final Artifact deployJar; + private final Artifact finalClassesDexZip; + private final Artifact javaResourceJar; + + public AndroidDexInfo(Artifact deployJar, Artifact finalClassesDexZip, Artifact javaResourceJar) { + this.deployJar = deployJar; + this.finalClassesDexZip = finalClassesDexZip; + this.javaResourceJar = javaResourceJar; + } + + @Override + public Provider getProvider() { + return PROVIDER; + } + + @Override + public Artifact getDeployJar() { + return deployJar; + } + + @Override + public Artifact getFinalClassesDexZip() { + return finalClassesDexZip; + } + + @Override + public Artifact getJavaResourceJar() { + return javaResourceJar; + } + + /** Provider for {@link AndroidDexInfo}. */ + public static class Provider extends BuiltinProvider + implements AndroidDexInfoApi.Provider { + + private Provider() { + super(PROVIDER_NAME, AndroidDexInfo.class); + } + + public String getName() { + return PROVIDER_NAME; + } + + @Override + public AndroidDexInfo createInfo( + Artifact deployJar, Artifact finalClassesDexZip, Artifact javaResourceJar) + throws EvalException { + + return new AndroidDexInfo(deployJar, finalClassesDexZip, javaResourceJar); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidBootstrap.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidBootstrap.java index 69edd3acc58e40..5e2860fd41cf71 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidBootstrap.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidBootstrap.java @@ -64,7 +64,8 @@ public AndroidBootstrap( ProguardMappingProviderApi.Provider proguardMappingProviderApiProvider, AndroidBinaryDataInfoApi.Provider androidBinaryDataInfoProvider, AndroidBinaryNativeLibsInfoApi.Provider androidBinaryInternalNativeLibsInfoApiProvider, - BaselineProfileProviderApi.Provider baselineProfileProvider) { + BaselineProfileProviderApi.Provider baselineProfileProvider, + AndroidDexInfoApi.Provider androidDexInfoApiProvider) { this.androidCommon = androidCommon; ImmutableMap.Builder builder = ImmutableMap.builder(); @@ -93,6 +94,7 @@ public AndroidBootstrap( builder.put(ProguardMappingProviderApi.NAME, proguardMappingProviderApiProvider); builder.put(AndroidBinaryDataInfoApi.NAME, androidBinaryDataInfoProvider); builder.put(BaselineProfileProviderApi.NAME, baselineProfileProvider); + builder.put(AndroidDexInfoApi.NAME, androidDexInfoApiProvider); providers = builder.build(); } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java new file mode 100644 index 00000000000000..d93563655f500e --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java @@ -0,0 +1,100 @@ +// 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. +package com.google.devtools.build.lib.starlarkbuildapi.android; + +import com.google.devtools.build.docgen.annot.StarlarkConstructor; +import com.google.devtools.build.lib.starlarkbuildapi.FileApi; +import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; +import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi; +import net.starlark.java.annot.Param; +import net.starlark.java.annot.ParamType; +import net.starlark.java.annot.StarlarkBuiltin; +import net.starlark.java.annot.StarlarkMethod; +import net.starlark.java.eval.EvalException; + +/** An Info that can provides dex artifacts. */ +@StarlarkBuiltin( + name = "AndroidDexInfo", + doc = + "Do not use this module. It is intended for migration purposes only. If you depend on it, " + + "you will be broken when it is removed.", + documented = false) +public interface AndroidDexInfoApi extends StructApi { + + /** Name of this info object. */ + String NAME = "AndroidDexInfo"; + + @StarlarkMethod( + name = "deploy_jar", + doc = "The deploy jar.", + documented = false, + structField = true) + FileT getDeployJar(); + + @StarlarkMethod( + name = "final_classes_dex_zip", + doc = "The zip file containing the final dex classes.", + documented = false, + structField = true) + FileT getFinalClassesDexZip(); + + @StarlarkMethod( + name = "java_resource_jar", + doc = "The final Java resource jar.", + documented = false, + structField = true) + FileT getJavaResourceJar(); + + /** Provider for {@link AndroidDexInfoApi}. */ + @StarlarkBuiltin( + name = "Provider", + doc = + "Do not use this module. It is intended for migration purposes only. If you depend on " + + "it, you will be broken when it is removed.", + documented = false) + interface Provider extends ProviderApi { + + @StarlarkMethod( + name = NAME, + doc = "The AndroidDexInfo constructor.", + documented = false, + parameters = { + @Param( + name = "deploy_jar", + allowedTypes = { + @ParamType(type = FileApi.class), + }, + named = true, + doc = "The \"_deploy\" jar suitable for deployment."), + @Param( + name = "final_classes_dex_zip", + allowedTypes = { + @ParamType(type = FileApi.class), + }, + named = true, + doc = "The zip file containing the final dex classes."), + @Param( + name = "java_resource_jar", + allowedTypes = { + @ParamType(type = FileApi.class), + }, + named = true, + doc = "The final Java resource jar."), + }, + selfCall = true) + @StarlarkConstructor + AndroidDexInfoApi createInfo( + FileT deployJar, FileT finalClassesDexZip, FileT javaResourceJar) throws EvalException; + } +} From ca79a84e3d412322a73bdccae2d9838514041fbd Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 10 May 2023 14:03:46 -0700 Subject: [PATCH 2/2] Enable android_binary to use AndroidDexInfo from its application_resources attribute. android_binary will use the dexes, jar resources, and deploy jar from AndroidDexInfo if it is present. RELNOTES: None. PiperOrigin-RevId: 531000013 Change-Id: I67c3457d131041aa4bab5db0892cdc0f0584f2dc --- .../lib/rules/android/AndroidBinary.java | 52 +++++++++++++++---- .../lib/rules/android/AndroidDexInfo.java | 9 +++- .../android/AndroidDexInfoApi.java | 9 +++- .../android/AndroidBuildViewTestCase.java | 5 ++ 4 files changed, 60 insertions(+), 15 deletions(-) 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 index a6612d83fca5dd..1a621beac7ee27 100644 --- 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 @@ -59,6 +59,7 @@ 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; @@ -601,11 +602,16 @@ public static RuleConfiguredTargetBuilder createAndroidBinary( proguardOutput, postProcessingOutputMap); + AndroidDexInfo androidDexInfo = + ruleContext.getPrerequisite("application_resources", AndroidDexInfo.PROVIDER); + // Compute the final DEX files by appending Java 8 legacy .dex if used. - Artifact finalClassesDex; + final Artifact finalClassesDex; Java8LegacyDexOutput java8LegacyDexOutput; ImmutableList finalShardDexZips = dexingOutput.shardDexZips; - if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs() + if (androidDexInfo != null) { + finalClassesDex = androidDexInfo.getFinalClassesDexZip(); + } else if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs() && dexPostprocessingOutput.classesDexZip().getFilename().endsWith(".zip")) { if (binaryJar.equals(jarToDex)) { // No shrinking: use canned Java 8 legacy .dex file @@ -690,7 +696,11 @@ public static RuleConfiguredTargetBuilder createAndroidBinary( ApkActionsBuilder.create("apk") .setClassesDex(finalClassesDex) .addInputZip(resourceApk.getArtifact()) - .setJavaResourceZip(dexingOutput.javaResourceJar, resourceExtractor) + .setJavaResourceZip( + androidDexInfo == null + ? dexingOutput.javaResourceJar + : androidDexInfo.getJavaResourceJar(), + resourceExtractor) .addInputZips(nativeLibsAar.toList()) .setNativeLibs(nativeLibs) .setUnsignedApk(unsignedApk) @@ -979,7 +989,10 @@ public static NestedSet getLibraryResourceJars(RuleContext ruleContext return libraryResourceJarsBuilder.build(); } - /** Generates an uncompressed _deploy.jar of all the runtime jars. */ + /** + * 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, @@ -988,15 +1001,32 @@ public static Artifact createDeployJar( boolean checkDesugarDeps, Function derivedJarFunction) throws InterruptedException { + Artifact deployJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_DEPLOY_JAR); - new DeployArchiveBuilder(javaSemantics, ruleContext) - .setOutputJar(deployJar) - .setAttributes(attributes) - .addRuntimeJars(common.getRuntimeJars()) - .setDerivedJarFunction(derivedJarFunction) - .setCheckDesugarDeps(checkDesugarDeps) - .build(); + + 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; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java index 8ee0db2b272a13..8f04e94b7c0a37 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDexInfo.java @@ -13,11 +13,14 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import static com.google.devtools.build.lib.rules.android.AndroidStarlarkData.fromNoneable; + import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuiltinProvider; import com.google.devtools.build.lib.packages.NativeInfo; import com.google.devtools.build.lib.starlarkbuildapi.android.AndroidDexInfoApi; +import javax.annotation.Nullable; import net.starlark.java.eval.EvalException; /** A provider for Android Dex artifacts */ @@ -53,6 +56,7 @@ public Artifact getFinalClassesDexZip() { } @Override + @Nullable public Artifact getJavaResourceJar() { return javaResourceJar; } @@ -71,10 +75,11 @@ public String getName() { @Override public AndroidDexInfo createInfo( - Artifact deployJar, Artifact finalClassesDexZip, Artifact javaResourceJar) + Artifact deployJar, Artifact finalClassesDexZip, Object javaResourceJar) throws EvalException { - return new AndroidDexInfo(deployJar, finalClassesDexZip, javaResourceJar); + return new AndroidDexInfo( + deployJar, finalClassesDexZip, fromNoneable(javaResourceJar, Artifact.class)); } } } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java index d93563655f500e..7e8e5bb0244f7e 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidDexInfoApi.java @@ -17,11 +17,13 @@ import com.google.devtools.build.lib.starlarkbuildapi.FileApi; import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi; +import javax.annotation.Nullable; import net.starlark.java.annot.Param; import net.starlark.java.annot.ParamType; import net.starlark.java.annot.StarlarkBuiltin; import net.starlark.java.annot.StarlarkMethod; import net.starlark.java.eval.EvalException; +import net.starlark.java.eval.NoneType; /** An Info that can provides dex artifacts. */ @StarlarkBuiltin( @@ -49,11 +51,13 @@ public interface AndroidDexInfoApi extends StructApi { structField = true) FileT getFinalClassesDexZip(); + @Nullable @StarlarkMethod( name = "java_resource_jar", doc = "The final Java resource jar.", documented = false, - structField = true) + structField = true, + allowReturnNones = true) FileT getJavaResourceJar(); /** Provider for {@link AndroidDexInfoApi}. */ @@ -88,6 +92,7 @@ interface Provider extends ProviderApi { name = "java_resource_jar", allowedTypes = { @ParamType(type = FileApi.class), + @ParamType(type = NoneType.class), }, named = true, doc = "The final Java resource jar."), @@ -95,6 +100,6 @@ interface Provider extends ProviderApi { selfCall = true) @StarlarkConstructor AndroidDexInfoApi createInfo( - FileT deployJar, FileT finalClassesDexZip, FileT javaResourceJar) throws EvalException; + FileT deployJar, FileT finalClassesDexZip, Object javaResourceJar) throws EvalException; } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java index 3e735a6d3397e8..00d2cb12342659 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java @@ -189,6 +189,11 @@ protected Artifact getFinalUnsignedApk(ConfiguredTarget target) { target.getProvider(FileProvider.class).getFilesToBuild(), "_unsigned.apk"); } + protected Artifact getDeployJar(ConfiguredTarget target) { + return getFirstArtifactEndingWith( + target.getProvider(FileProvider.class).getFilesToBuild(), "_deploy.jar"); + } + protected Artifact getResourceApk(ConfiguredTarget target) { Artifact resourceApk = getFirstArtifactEndingWith(