Skip to content

Commit 4c3219e

Browse files
timpeutcopybara-github
authored andcommitted
Add new min_sdk_version attribute on android_binary and pipe to dex/desugar actions.
Also introduce an allowlist to restrict packages able to set this new attribute. Eventually we may roll this out more broadly, but there are outstanding concerns around useability and scalability. RELNOTES: None PiperOrigin-RevId: 451524093 Change-Id: I9383cac05a20c5115b2202828ca0cea951244d53
1 parent e0e5896 commit 4c3219e

File tree

6 files changed

+209
-32
lines changed

6 files changed

+209
-32
lines changed

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

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ private static void validateRuleContext(RuleContext ruleContext, AndroidDataCont
184184
ruleContext.attributeError("multidex", "Multidex must be enabled");
185185
}
186186

187+
if (ruleContext.attributes().isAttributeValueExplicitlySpecified("min_sdk_version")
188+
&& Allowlist.hasAllowlist(ruleContext, "allow_min_sdk_version")
189+
&& !Allowlist.isAvailable(ruleContext, "allow_min_sdk_version")) {
190+
ruleContext.attributeError(
191+
"min_sdk_version", "Target is not permitted to set min_sdk_version");
192+
}
193+
187194
if (AndroidCommon.getAndroidConfig(ruleContext).desugarJava8Libs()
188195
&& getMultidexMode(ruleContext) == MultidexMode.OFF) {
189196
// Multidex is required so we can include legacy libs as a separate .dex file.
@@ -263,30 +270,6 @@ private static RuleConfiguredTargetBuilder init(
263270
: null);
264271
}
265272

266-
Artifact manifestValidation = null;
267-
if (Allowlist.hasAllowlist(ruleContext, "android_multidex_native_min_sdk_allowlist")
268-
&& !Allowlist.isAvailable(ruleContext, "android_multidex_native_min_sdk_allowlist")
269-
&& getMultidexMode(ruleContext) == MultidexMode.NATIVE
270-
&& ruleContext.isAttrDefined("$validate_manifest", LABEL)) {
271-
manifestValidation =
272-
ruleContext.getPackageRelativeArtifact(
273-
ruleContext.getLabel().getName() + "_manifest_validation_output",
274-
ruleContext.getBinOrGenfilesDirectory());
275-
ruleContext.registerAction(
276-
createSpawnActionBuilder(ruleContext)
277-
.setExecutable(ruleContext.getExecutablePrerequisite("$validate_manifest"))
278-
.setProgressMessage("Validating %{input}")
279-
.setMnemonic("ValidateManifest")
280-
.addInput(manifest.getManifest())
281-
.addOutput(manifestValidation)
282-
.addCommandLine(
283-
CustomCommandLine.builder()
284-
.addExecPath("--manifest", manifest.getManifest())
285-
.addExecPath("--output", manifestValidation)
286-
.build())
287-
.build(ruleContext));
288-
}
289-
290273
boolean shrinkResourceCycles =
291274
shouldShrinkResourceCycles(
292275
dataContext.getAndroidConfig(), ruleContext, dataContext.isResourceShrinkingEnabled());
@@ -415,6 +398,38 @@ && getMultidexMode(ruleContext) == MultidexMode.NATIVE
415398
AndroidBinaryMobileInstall.createMobileInstallResourceApks(
416399
ruleContext, dataContext, manifest);
417400

401+
Artifact manifestValidation = null;
402+
boolean shouldValidateMultidex =
403+
(Allowlist.hasAllowlist(ruleContext, "android_multidex_native_min_sdk_allowlist")
404+
&& !Allowlist.isAvailable(ruleContext, "android_multidex_native_min_sdk_allowlist")
405+
&& getMultidexMode(ruleContext) == MultidexMode.NATIVE);
406+
boolean shouldValidateMinSdk = getMinSdkVersion(ruleContext) > 0;
407+
if (ruleContext.isAttrDefined("$validate_manifest", LABEL)
408+
&& (shouldValidateMultidex || shouldValidateMinSdk)) {
409+
manifestValidation =
410+
ruleContext.getPackageRelativeArtifact(
411+
ruleContext.getLabel().getName() + "_manifest_validation_output",
412+
ruleContext.getBinOrGenfilesDirectory());
413+
ruleContext.registerAction(
414+
createSpawnActionBuilder(ruleContext)
415+
.setExecutable(ruleContext.getExecutablePrerequisite("$validate_manifest"))
416+
.setProgressMessage("Validating %{input}")
417+
.setMnemonic("ValidateManifest")
418+
.addInput(manifest.getManifest())
419+
.addOutput(manifestValidation)
420+
.addCommandLine(
421+
CustomCommandLine.builder()
422+
.addExecPath("--manifest", manifest.getManifest())
423+
.addExecPath("--output", manifestValidation)
424+
.addFormatted(
425+
"--validate_multidex=%s", Boolean.toString(shouldValidateMultidex))
426+
.add(
427+
"--expected_min_sdk_version",
428+
Integer.toString(getMinSdkVersion(ruleContext)))
429+
.build())
430+
.build(ruleContext));
431+
}
432+
418433
return createAndroidBinary(
419434
ruleContext,
420435
dataContext,
@@ -1267,6 +1282,8 @@ private static DexingOutput dex(
12671282
+ "\" not supported by this version of the Android SDK");
12681283
}
12691284

1285+
int minSdkVersion = getMinSdkVersion(ruleContext);
1286+
12701287
int dexShards = ruleContext.attributes().get("dex_shards", Type.INTEGER).toIntUnchecked();
12711288
if (dexShards > 1) {
12721289
if (multidexMode == MultidexMode.OFF) {
@@ -1306,6 +1323,7 @@ private static DexingOutput dex(
13061323
common,
13071324
inclusionFilterJar,
13081325
dexopts,
1326+
minSdkVersion,
13091327
androidSemantics,
13101328
attributes,
13111329
derivedJarFunction,
@@ -1320,6 +1338,7 @@ private static DexingOutput dex(
13201338
proguardedJar,
13211339
classesDex,
13221340
dexopts,
1341+
minSdkVersion,
13231342
/*multidex=*/ false,
13241343
/*mainDexList=*/ null);
13251344
}
@@ -1356,6 +1375,7 @@ private static DexingOutput dex(
13561375
common,
13571376
inclusionFilterJar,
13581377
dexopts,
1378+
minSdkVersion,
13591379
androidSemantics,
13601380
attributes,
13611381
derivedJarFunction,
@@ -1381,7 +1401,13 @@ private static DexingOutput dex(
13811401
dexopts);
13821402
} else {
13831403
AndroidCommon.createDexAction(
1384-
ruleContext, shard, shardDex, dexopts, /*multidex=*/ true, /*mainDexList=*/ null);
1404+
ruleContext,
1405+
shard,
1406+
shardDex,
1407+
dexopts,
1408+
minSdkVersion,
1409+
/*multidex=*/ true,
1410+
/*mainDexList=*/ null);
13851411
}
13861412
}
13871413
ImmutableList<Artifact> shardDexes = shardDexesBuilder.build();
@@ -1417,6 +1443,7 @@ private static DexingOutput dex(
14171443
common,
14181444
inclusionFilterJar,
14191445
dexopts,
1446+
minSdkVersion,
14201447
androidSemantics,
14211448
attributes,
14221449
derivedJarFunction,
@@ -1436,6 +1463,7 @@ private static DexingOutput dex(
14361463
proguardedJar,
14371464
classesDexIntermediate,
14381465
dexopts,
1466+
minSdkVersion,
14391467
/*multidex=*/ true,
14401468
mainDexList);
14411469
createCleanDexZipAction(ruleContext, classesDexIntermediate, classesDex);
@@ -1455,6 +1483,7 @@ private static void createIncrementalDexingActions(
14551483
AndroidCommon common,
14561484
@Nullable Artifact inclusionFilterJar,
14571485
List<String> dexopts,
1486+
int minSdkVersion,
14581487
AndroidSemantics androidSemantics,
14591488
JavaTargetAttributes attributes,
14601489
Function<Artifact, Artifact> derivedJarFunction,
@@ -1471,7 +1500,12 @@ private static void createIncrementalDexingActions(
14711500
ruleContext,
14721501
collectRuntimeJars(common, attributes),
14731502
collectDexArchives(
1474-
ruleContext, common, dexopts, androidSemantics, derivedJarFunction));
1503+
ruleContext,
1504+
common,
1505+
dexopts,
1506+
minSdkVersion,
1507+
androidSemantics,
1508+
derivedJarFunction));
14751509
} else {
14761510
if (proguardedJar != null
14771511
&& AndroidCommon.getAndroidConfig(ruleContext).incrementalDexingShardsAfterProguard()
@@ -1493,6 +1527,7 @@ private static void createIncrementalDexingActions(
14931527
"$dexbuilder_after_proguard",
14941528
proguardedJar,
14951529
DexArchiveAspect.topLevelDexbuilderDexopts(dexopts),
1530+
minSdkVersion,
14961531
dexArchives.get(0));
14971532
} else {
14981533
createShuffleJarActions(
@@ -1503,6 +1538,7 @@ private static void createIncrementalDexingActions(
15031538
common,
15041539
inclusionFilterJar,
15051540
dexopts,
1541+
minSdkVersion,
15061542
androidSemantics,
15071543
attributes,
15081544
derivedJarFunction,
@@ -1771,6 +1807,7 @@ public static Function<Artifact, Artifact> collectDesugaredJars(
17711807
jar,
17721808
attributes.getBootClassPath().bootclasspath(),
17731809
attributes.getCompileTimeClassPath(),
1810+
getMinSdkVersion(ruleContext),
17741811
ruleContext.getDerivedArtifact(
17751812
jarPath.replaceName(jarPath.getBaseName() + "_desugared.jar"), jar.getRoot()));
17761813
result.addDesugaredJar(jar, desugared);
@@ -1797,6 +1834,7 @@ private static Map<Artifact, Artifact> collectDexArchives(
17971834
RuleContext ruleContext,
17981835
AndroidCommon common,
17991836
List<String> dexopts,
1837+
int minSdkVersion,
18001838
AndroidSemantics semantics,
18011839
Function<Artifact, Artifact> derivedJarFunction) {
18021840
DexArchiveProvider.Builder result = new DexArchiveProvider.Builder();
@@ -1820,6 +1858,7 @@ private static Map<Artifact, Artifact> collectDexArchives(
18201858
"$dexbuilder",
18211859
derivedJarFunction.apply(jar),
18221860
incrementalDexopts,
1861+
minSdkVersion,
18231862
ruleContext.getDerivedArtifact(
18241863
jarPath.replaceName(jarPath.getBaseName() + ".dex.zip"), jar.getRoot()));
18251864
result.addDexArchive(incrementalDexopts, dexArchive, jar);
@@ -1835,6 +1874,7 @@ private static Artifact createShuffleJarActions(
18351874
AndroidCommon common,
18361875
@Nullable Artifact inclusionFilterJar,
18371876
List<String> dexopts,
1877+
int minSdkVersion,
18381878
AndroidSemantics semantics,
18391879
JavaTargetAttributes attributes,
18401880
Function<Artifact, Artifact> derivedJarFunction,
@@ -1889,7 +1929,8 @@ private static Artifact createShuffleJarActions(
18891929
// there should be very few or no Jar files that still end up in shards. The dexing
18901930
// step below will have to deal with those in addition to merging .dex files together.
18911931
Map<Artifact, Artifact> dexArchives =
1892-
collectDexArchives(ruleContext, common, dexopts, semantics, derivedJarFunction);
1932+
collectDexArchives(
1933+
ruleContext, common, dexopts, minSdkVersion, semantics, derivedJarFunction);
18931934
classpath = toDexedClasspath(ruleContext, classpath, dexArchives);
18941935
shardCommandLine.add("--split_dexed_classes");
18951936
} else {
@@ -1916,6 +1957,7 @@ private static Artifact createShuffleJarActions(
19161957
"$dexbuilder_after_proguard",
19171958
shuffleOutputs.get(i),
19181959
DexArchiveAspect.topLevelDexbuilderDexopts(dexopts),
1960+
minSdkVersion,
19191961
shards.get(i));
19201962
}
19211963
}
@@ -2178,6 +2220,13 @@ public static MultidexMode getMultidexMode(RuleContext ruleContext) {
21782220
}
21792221
}
21802222

2223+
private static int getMinSdkVersion(RuleContext ruleContext) {
2224+
if (ruleContext.getRule().isAttrDefined("min_sdk_version", Type.INTEGER)) {
2225+
return ruleContext.attributes().get("min_sdk_version", Type.INTEGER).toIntUnchecked();
2226+
}
2227+
return 0;
2228+
}
2229+
21812230
/**
21822231
* List of Android SDKs that contain runtimes that do not support the native multidexing
21832232
* introduced in Android L. If someone tries to build an android_binary that has multidex=native

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ private static Artifact getStubDex(
369369
ruleContext,
370370
split ? "split_stub_application/classes.dex" : "stub_application/classes.dex");
371371
AndroidCommon.createDexAction(
372-
ruleContext, stubDeployJar, stubDex, ImmutableList.<String>of(), false, null);
372+
ruleContext, stubDeployJar, stubDex, ImmutableList.<String>of(), 0, false, null);
373373

374374
return stubDex;
375375
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ public static void createDexAction(
187187
Artifact jarToDex,
188188
Artifact classesDex,
189189
List<String> dexOptions,
190+
int minSdkVersion,
190191
boolean multidex,
191192
Artifact mainDexList) {
192193
CustomCommandLine.Builder commandLine = CustomCommandLine.builder();
@@ -201,6 +202,9 @@ public static void createDexAction(
201202
}
202203

203204
commandLine.addAll(dexOptions);
205+
if (minSdkVersion > 0) {
206+
commandLine.add("--min_sdk_version", Integer.toString(minSdkVersion));
207+
}
204208
if (multidex) {
205209
commandLine.add("--multi-dex");
206210
if (mainDexList != null) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,15 @@ Do PNG crunching (or not). This is independent of nine-patch processing, which i
571571
<code>en_XA</code> and/or <code>ar_XB</code> pseudo-locales.
572572
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
573573
.add(attr(ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME, STRING_LIST))
574+
/* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(min_sdk_version) -->
575+
The minSdkVersion. This must match the minSdkVersion specified in the AndroidManifest.xml.
576+
If set, will be used for dex/desugaring.
577+
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
578+
.add(
579+
attr("min_sdk_version", INTEGER)
580+
.undocumented("experimental")
581+
.value(StarlarkInt.of(0))
582+
.nonconfigurable("AspectParameters don't support configurations."))
574583
/* <!-- #BLAZE_RULE($android_binary_base).ATTRIBUTE(shrink_resources) -->
575584
Whether to perform resource shrinking. Resources that are not used by the binary will be
576585
removed from the APK. This is only supported for rules using local resources (i.e. the

0 commit comments

Comments
 (0)