Skip to content

Commit 9337dfe

Browse files
dawassercopybara-github
authored andcommitted
Add support in Blaze for running a monolithic "optimizing" dexer action.
PiperOrigin-RevId: 538401036 Change-Id: I244bfb99bd21c21367ac88ca197a916c1d034088
1 parent 32795ee commit 9337dfe

File tree

5 files changed

+210
-20
lines changed

5 files changed

+210
-20
lines changed

src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -507,13 +507,16 @@ public static RuleConfiguredTargetBuilder createAndroidBinary(
507507
boolean postprocessingRewritesMap = androidSemantics.postprocessClassesRewritesMap(ruleContext);
508508
boolean desugarJava8LibsGeneratesMap =
509509
AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs();
510+
boolean optimizingDexing = ruleContext.getExecutablePrerequisite(":optimizing_dexer") != null;
510511
if (generateProguardMap) {
511512
// Determine the output of the Proguard map from shrinking the app. This depends on the
512513
// additional steps which can process the map before the final Proguard map artifact is
513514
// generated.
514515
if (!hasProguardSpecs && !postprocessingRewritesMap) {
515516
// When no shrinking happens a generating rule for the output map artifact is still needed.
516517
proguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext);
518+
} else if (optimizingDexing) {
519+
proguardOutputMap = ProguardHelper.getProguardTempArtifact(ruleContext, "pre_dexing.map");
517520
} else if (postprocessingRewritesMap) {
518521
// Proguard map from shrinking goes to postprocessing.
519522
proguardOutputMap =
@@ -545,13 +548,13 @@ public static RuleConfiguredTargetBuilder createAndroidBinary(
545548
if (proguardOutput.hasMapping()) {
546549
// Determine the Proguard map artifacts for the additional steps (if any) if shrinking of
547550
// the app is enabled.
548-
if (postprocessingRewritesMap && desugarJava8LibsGeneratesMap) {
551+
if ((optimizingDexing || postprocessingRewritesMap) && desugarJava8LibsGeneratesMap) {
549552
// Proguard map from preprocessing will be merged with Proguard map for desugared
550553
// library.
551554
postProcessingOutputMap =
552555
getDxArtifact(ruleContext, "_proguard_output_for_desugared_library.map");
553556
finalProguardOutputMap = androidSemantics.getProguardOutputMap(ruleContext);
554-
} else if (postprocessingRewritesMap) {
557+
} else if (optimizingDexing || postprocessingRewritesMap) {
555558
// No desugared library, Proguard map from preprocessing is the final Proguard map.
556559
postProcessingOutputMap = androidSemantics.getProguardOutputMap(ruleContext);
557560
finalProguardOutputMap = postProcessingOutputMap;
@@ -592,7 +595,10 @@ public static RuleConfiguredTargetBuilder createAndroidBinary(
592595
resourceApk.getMainDexProguardConfig(),
593596
resourceClasses,
594597
derivedJarFunction,
595-
proguardOutputMap);
598+
proguardOutputMap,
599+
postProcessingOutputMap,
600+
proguardOutput.getLibraryJar(),
601+
!proguardSpecs.isEmpty());
596602

597603
DexPostprocessingOutput dexPostprocessingOutput =
598604
androidSemantics.postprocessClassesDexZip(
@@ -1120,11 +1126,12 @@ private static ProguardOutput createEmptyProguardAction(
11201126
ProguardOutput outputs =
11211127
ProguardHelper.getProguardOutputs(
11221128
proguardOutputJar,
1123-
/*proguardSeeds=*/ null,
1124-
/*proguardUsage=*/ null,
1129+
/* proguardSeeds= */ null,
1130+
/* proguardUsage= */ null,
11251131
ruleContext,
11261132
semantics,
1127-
proguardOutputMap);
1133+
proguardOutputMap,
1134+
null);
11281135
outputs.addAllToSet(failures);
11291136
ruleContext.registerAction(
11301137
new FailAction(
@@ -1318,8 +1325,12 @@ private static DexingOutput dex(
13181325
@Nullable Artifact mainDexProguardSpec,
13191326
JavaTargetAttributes attributes,
13201327
Function<Artifact, Artifact> derivedJarFunction,
1321-
@Nullable Artifact proguardOutputMap)
1328+
@Nullable Artifact proguardOutputMap,
1329+
@Nullable Artifact postProcessingOutputMap,
1330+
@Nullable Artifact libraryJar,
1331+
boolean isOptimizedBuild)
13221332
throws InterruptedException, RuleErrorException {
1333+
FilesToRunProvider optimizingDexer = ruleContext.getExecutablePrerequisite(":optimizing_dexer");
13231334
List<String> dexopts = ruleContext.getExpander().withDataLocations().tokenized("dexopts");
13241335
MultidexMode multidexMode = getMultidexMode(ruleContext);
13251336
if (!supportsMultidexMode(ruleContext, multidexMode)) {
@@ -1370,7 +1381,55 @@ private static DexingOutput dex(
13701381
}
13711382

13721383
Artifact classesDex = getDxArtifact(ruleContext, "classes.dex.zip");
1373-
if (dexShards > 1) {
1384+
if (optimizingDexer != null && isOptimizedBuild) {
1385+
SpawnAction.Builder dexAction =
1386+
new SpawnAction.Builder()
1387+
.useDefaultShellEnvironment()
1388+
.setExecutable(optimizingDexer)
1389+
.setProgressMessage("Optimized dexing for %{label}")
1390+
.setMnemonic("OptimizingDex")
1391+
.addInput(proguardedJar)
1392+
.addOutput(classesDex);
1393+
1394+
boolean nativeMultidex = multidexMode == MultidexMode.NATIVE;
1395+
CustomCommandLine.Builder dexCommand =
1396+
CustomCommandLine.builder()
1397+
.addExecPath(proguardedJar)
1398+
.add("--release")
1399+
.add("--no-desugaring")
1400+
.addExecPath("--output", classesDex)
1401+
.addAll(dexopts);
1402+
1403+
if (proguardOutputMap != null) {
1404+
dexAction.addInput(proguardOutputMap).addOutput(postProcessingOutputMap);
1405+
dexCommand
1406+
.addExecPath("--pg-map", proguardOutputMap)
1407+
.addExecPath("--pg-map-output", postProcessingOutputMap);
1408+
}
1409+
1410+
// TODO(b/261110876): Pass min SDK through here based on the value in the merged manifest. The
1411+
// current value is statically defined for the entire depot.
1412+
// We currently set the minimum SDK version to 21 if you are doing native multidex as that is
1413+
// required for native multidex to work in the first place and as a result is required for
1414+
// correct behavior from the dexer.
1415+
int sdk = nativeMultidex ? Math.max(21, minSdkVersion) : minSdkVersion;
1416+
if (sdk != 0) {
1417+
dexCommand.add("--min-api", Integer.toString(sdk));
1418+
}
1419+
if (mainDexList != null) {
1420+
dexCommand.addExecPath("--main-dex-list", mainDexList);
1421+
dexAction.addInput(mainDexList);
1422+
}
1423+
if (libraryJar != null) {
1424+
dexCommand.addExecPath("--lib", libraryJar);
1425+
dexAction.addInput(libraryJar);
1426+
}
1427+
1428+
dexAction.addCommandLine(dexCommand.build());
1429+
ruleContext.registerAction(dexAction.build(ruleContext));
1430+
return new DexingOutput(
1431+
classesDex, javaResourceSourceJar, ImmutableList.of(classesDex), mainDexList);
1432+
} else if (dexShards > 1) {
13741433
ImmutableList<Artifact> shards =
13751434
makeShardArtifacts(ruleContext, dexShards, usesDexArchives ? ".jar.dex.zip" : ".jar");
13761435

src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,15 @@ public static class Options extends FragmentOptions {
10601060
+ " dex when compiling legacy multidex.")
10611061
public Label legacyMainDexListGenerator;
10621062

1063+
@Option(
1064+
name = "optimizing_dexer",
1065+
defaultValue = "null",
1066+
converter = LabelConverter.class,
1067+
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
1068+
effectTags = {OptionEffectTag.UNKNOWN},
1069+
help = "Specifies a binary to use to do dexing without sharding.")
1070+
public Label optimizingDexer;
1071+
10631072
@Option(
10641073
name = "experimental_disable_instrumentation_manifest_merge",
10651074
defaultValue = "false",
@@ -1185,6 +1194,7 @@ public FragmentOptions getExec() {
11851194
private final boolean useRTxtFromMergedResources;
11861195
private final boolean outputLibraryMergedAssets;
11871196
private final Label legacyMainDexListGenerator;
1197+
private final Label optimizingDexer;
11881198
private final boolean disableInstrumentationManifestMerging;
11891199
private final boolean incompatibleUseToolchainResolution;
11901200
private final boolean hwasan;
@@ -1249,6 +1259,7 @@ public AndroidConfiguration(BuildOptions buildOptions) throws InvalidConfigurati
12491259
this.useRTxtFromMergedResources = options.useRTxtFromMergedResources;
12501260
this.outputLibraryMergedAssets = options.outputLibraryMergedAssets;
12511261
this.legacyMainDexListGenerator = options.legacyMainDexListGenerator;
1262+
this.optimizingDexer = options.optimizingDexer;
12521263
this.disableInstrumentationManifestMerging = options.disableInstrumentationManifestMerging;
12531264
this.incompatibleUseToolchainResolution = options.incompatibleUseToolchainResolution;
12541265
this.hwasan = options.hwasan;
@@ -1562,4 +1573,13 @@ boolean outputLibraryMergedAssets() {
15621573
public Label getLegacyMainDexListGenerator() {
15631574
return legacyMainDexListGenerator;
15641575
}
1576+
1577+
/** Returns the label provided with --optimizing_dexer, if any. */
1578+
@StarlarkConfigurationField(
1579+
name = "optimizing_dexer",
1580+
doc = "Returns the label provided with --optimizing_dexer, if any.")
1581+
@Nullable
1582+
public Label getOptimizingDexer() {
1583+
return optimizingDexer;
1584+
}
15651585
}

src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ public static LabelLateBoundDefault<?> getAndroidSdkLabel(Label androidSdk) {
223223
null,
224224
(rule, attributes, androidConfig) -> androidConfig.getLegacyMainDexListGenerator());
225225

226+
@SerializationConstant
227+
static final LabelLateBoundDefault<AndroidConfiguration> OPTIMIZING_DEXER =
228+
LabelLateBoundDefault.fromTargetConfiguration(
229+
AndroidConfiguration.class,
230+
null,
231+
(rule, attributes, androidConfig) -> androidConfig.getOptimizingDexer());
232+
226233
public static final FileType ANDROID_IDL = FileType.of(".aidl");
227234

228235
public static final String[] ALLOWED_DEPENDENCIES = {
@@ -902,6 +909,12 @@ public Object getDefault(AttributeMap rule) {
902909
.cfg(ExecutionTransitionFactory.createFactory())
903910
.value(LEGACY_MAIN_DEX_LIST_GENERATOR)
904911
.exec())
912+
// This comes from the --optimizing_dexer flag.
913+
.add(
914+
attr(":optimizing_dexer", LABEL)
915+
.cfg(ExecutionTransitionFactory.createFactory())
916+
.value(OPTIMIZING_DEXER)
917+
.exec())
905918
.removeAttribute("data")
906919
.advertiseStarlarkProvider(StarlarkProviderIdentifier.forKey(ApkInfo.PROVIDER.getKey()))
907920
.advertiseStarlarkProvider(StarlarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey()))

src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static final class ProguardOutput {
6161
@Nullable private final Artifact seeds;
6262
@Nullable private final Artifact usage;
6363
@Nullable private final Artifact constantStringObfuscatedMapping;
64+
@Nullable private final Artifact libraryJar;
6465
private final Artifact config;
6566

6667
public ProguardOutput(
@@ -70,18 +71,20 @@ public ProguardOutput(
7071
@Nullable Artifact seeds,
7172
@Nullable Artifact usage,
7273
@Nullable Artifact constantStringObfuscatedMapping,
74+
@Nullable Artifact libraryJar,
7375
Artifact config) {
7476
this.outputJar = checkNotNull(outputJar);
7577
this.mapping = mapping;
7678
this.protoMapping = protoMapping;
7779
this.seeds = seeds;
7880
this.usage = usage;
7981
this.constantStringObfuscatedMapping = constantStringObfuscatedMapping;
82+
this.libraryJar = libraryJar;
8083
this.config = config;
8184
}
8285

8386
public static ProguardOutput createEmpty(Artifact outputJar) {
84-
return new ProguardOutput(outputJar, null, null, null, null, null, null);
87+
return new ProguardOutput(outputJar, null, null, null, null, null, null, null);
8588
}
8689

8790
public Artifact getOutputJar() {
@@ -117,6 +120,11 @@ public Artifact getUsage() {
117120
return usage;
118121
}
119122

123+
@Nullable
124+
public Artifact getLibraryJar() {
125+
return libraryJar;
126+
}
127+
120128
public Artifact getConfig() {
121129
return config;
122130
}
@@ -247,7 +255,8 @@ public static ProguardOutput getProguardOutputs(
247255
@Nullable Artifact proguardUsage,
248256
RuleContext ruleContext,
249257
JavaSemantics semantics,
250-
@Nullable Artifact proguardOutputMap)
258+
@Nullable Artifact proguardOutputMap,
259+
@Nullable Artifact libraryJar)
251260
throws InterruptedException {
252261
boolean mappingRequested = genProguardMapping(ruleContext.attributes());
253262

@@ -274,6 +283,7 @@ public static ProguardOutput getProguardOutputs(
274283
proguardSeeds,
275284
proguardUsage,
276285
proguardConstantStringMap,
286+
libraryJar,
277287
proguardConfigOutput);
278288
}
279289

@@ -312,14 +322,7 @@ public static ProguardOutput createOptimizationActions(
312322
throws InterruptedException {
313323
Preconditions.checkArgument(!proguardSpecs.isEmpty());
314324

315-
ProguardOutput output =
316-
getProguardOutputs(
317-
proguardOutputJar,
318-
proguardSeeds,
319-
proguardUsage,
320-
ruleContext,
321-
semantics,
322-
proguardOutputMap);
325+
Artifact libraryJar = null;
323326

324327
if (!libraryJars.isEmpty() && !libraryJars.isSingleton()) {
325328
JavaTargetAttributes attributes = new JavaTargetAttributes.Builder(semantics).build();
@@ -331,28 +334,42 @@ public static ProguardOutput createOptimizationActions(
331334
.addRuntimeJars(libraryJars)
332335
.build();
333336
libraryJars = NestedSetBuilder.create(Order.STABLE_ORDER, combinedLibraryJar);
337+
libraryJar = combinedLibraryJar;
338+
} else if (libraryJars.isSingleton()) {
339+
libraryJar = libraryJars.getSingleton();
334340
}
335341

336342
boolean filterLibraryJarWithProgramJar =
337343
ruleContext.getFragment(AndroidConfiguration.class).filterLibraryJarWithProgramJar();
338344

339345
if (filterLibraryJarWithProgramJar) {
340346
Preconditions.checkState(libraryJars.isSingleton());
341-
Artifact libraryJar = libraryJars.getSingleton();
347+
Artifact singletonLibraryJar = libraryJars.getSingleton();
342348

343349
Artifact filteredLibraryJar =
344350
getProguardTempArtifact(ruleContext, "combined_library_jars_filtered.jar");
345351

346352
new ZipFilterBuilder(ruleContext)
347-
.setInputZip(libraryJar)
353+
.setInputZip(singletonLibraryJar)
348354
.setOutputZip(filteredLibraryJar)
349355
.addFilterZips(ImmutableList.of(programJar))
350356
.setCheckHashMismatchMode(ZipFilterBuilder.CheckHashMismatchMode.NONE)
351357
.build();
352358

353359
libraryJars = NestedSetBuilder.create(Order.STABLE_ORDER, filteredLibraryJar);
360+
libraryJar = filteredLibraryJar;
354361
}
355362

363+
ProguardOutput output =
364+
getProguardOutputs(
365+
proguardOutputJar,
366+
proguardSeeds,
367+
proguardUsage,
368+
ruleContext,
369+
semantics,
370+
proguardOutputMap,
371+
libraryJar);
372+
356373
JavaConfiguration javaConfiguration =
357374
ruleContext.getConfiguration().getFragment(JavaConfiguration.class);
358375
JavaConfiguration.NamedLabel optimizer = javaConfiguration.getBytecodeOptimizer();

0 commit comments

Comments
 (0)