Add Android platform build API.
Bug: b/232073181
Change-Id: Ie65bf484b8e2934e90d0b3ca9b9f4427d4bc0193
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index b2e0f6d..471988a 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -54,6 +54,7 @@
private final DumpInputFlags dumpInputFlags;
private final MapIdProvider mapIdProvider;
private final SourceFileProvider sourceFileProvider;
+ private final boolean isAndroidPlatformBuild;
BaseCompilerCommand(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
@@ -72,6 +73,7 @@
dumpInputFlags = DumpInputFlags.noDump();
mapIdProvider = null;
sourceFileProvider = null;
+ isAndroidPlatformBuild = false;
}
BaseCompilerCommand(
@@ -90,7 +92,8 @@
int threadCount,
DumpInputFlags dumpInputFlags,
MapIdProvider mapIdProvider,
- SourceFileProvider sourceFileProvider) {
+ SourceFileProvider sourceFileProvider,
+ boolean isAndroidPlatformBuild) {
super(app);
assert minApiLevel > 0;
assert mode != null;
@@ -109,6 +112,7 @@
this.dumpInputFlags = dumpInputFlags;
this.mapIdProvider = mapIdProvider;
this.sourceFileProvider = sourceFileProvider;
+ this.isAndroidPlatformBuild = isAndroidPlatformBuild;
}
/**
@@ -197,6 +201,10 @@
return threadCount;
}
+ public boolean getAndroidPlatformBuild() {
+ return isAndroidPlatformBuild;
+ }
+
DumpInputFlags getDumpInputFlags() {
return dumpInputFlags;
}
@@ -237,6 +245,7 @@
private DumpInputFlags dumpInputFlags = DumpInputFlags.noDump();
private MapIdProvider mapIdProvider = null;
private SourceFileProvider sourceFileProvider = null;
+ private boolean isAndroidPlatformBuild = false;
abstract CompilationMode defaultCompilationMode();
@@ -635,6 +644,23 @@
return self();
}
+ /**
+ * Configure the present build as a "Android platform build".
+ *
+ * <p>A platform build, is a build where the runtime "bootclasspath" is known at compile time.
+ * In other words, the specified <i>min-api</i> is also known to be the <i>max-api</i>. In this
+ * mode the compiler will disable various features that provide support for newer runtimes as
+ * well as disable workarounds for older runtimes.
+ */
+ public B setAndroidPlatformBuild(boolean isAndroidPlatformBuild) {
+ this.isAndroidPlatformBuild = isAndroidPlatformBuild;
+ return self();
+ }
+
+ public boolean getAndroidPlatformBuild() {
+ return isAndroidPlatformBuild;
+ }
+
B dumpInputToFile(Path file) {
dumpInputFlags = DumpInputFlags.dumpToFile(file);
return self();
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 1495071..d6dec04 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -425,6 +425,7 @@
getMapIdProvider(),
proguardMapConsumer,
enableMissingLibraryApiModeling,
+ getAndroidPlatformBuild(),
factory);
}
}
@@ -516,6 +517,7 @@
MapIdProvider mapIdProvider,
StringConsumer proguardMapConsumer,
boolean enableMissingLibraryApiModeling,
+ boolean isAndroidPlatformBuild,
DexItemFactory factory) {
super(
inputApp,
@@ -533,7 +535,8 @@
threadCount,
dumpInputFlags,
mapIdProvider,
- null);
+ null,
+ isAndroidPlatformBuild);
this.intermediate = intermediate;
this.globalSyntheticsConsumer = globalSyntheticsConsumer;
this.desugarGraphConsumer = desugarGraphConsumer;
@@ -654,6 +657,8 @@
horizontalClassMergerOptions.disable();
}
+ internal.configureAndroidPlatformBuild(getAndroidPlatformBuild());
+
internal.setDumpInputFlags(getDumpInputFlags(), skipDump);
internal.dumpOptions = dumpOptions();
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 2b50253..dce9604 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -116,7 +116,8 @@
threadCount,
dumpInputFlags,
mapIdProvider,
- null);
+ null,
+ false);
this.d8Command = d8Command;
this.r8Command = r8Command;
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
@@ -302,6 +303,11 @@
}
@Override
+ public Builder setAndroidPlatformBuild(boolean isAndroidPlatformBuild) {
+ throw getReporter().fatalError("L8 does not support configuring Android platform builds.");
+ }
+
+ @Override
void validate() {
if (isPrintHelp()) {
return;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 8d323ab..50b5de8 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -634,7 +634,8 @@
getDumpInputFlags(),
getMapIdProvider(),
getSourceFileProvider(),
- enableMissingLibraryApiModeling);
+ enableMissingLibraryApiModeling,
+ getAndroidPlatformBuild());
if (inputDependencyGraphConsumer != null) {
inputDependencyGraphConsumer.finished();
@@ -821,7 +822,8 @@
DumpInputFlags dumpInputFlags,
MapIdProvider mapIdProvider,
SourceFileProvider sourceFileProvider,
- boolean enableMissingLibraryApiModeling) {
+ boolean enableMissingLibraryApiModeling,
+ boolean isAndroidPlatformBuild) {
super(
inputApp,
mode,
@@ -838,7 +840,8 @@
threadCount,
dumpInputFlags,
mapIdProvider,
- sourceFileProvider);
+ sourceFileProvider,
+ isAndroidPlatformBuild);
assert proguardConfiguration != null;
assert mainDexKeepRules != null;
this.mainDexKeepRules = mainDexKeepRules;
@@ -1038,6 +1041,8 @@
SourceFileRewriter.computeSourceFileProvider(
getSourceFileProvider(), proguardConfiguration, internal);
+ internal.configureAndroidPlatformBuild(getAndroidPlatformBuild());
+
if (!DETERMINISTIC_DEBUGGING) {
assert internal.threadCount == ThreadUtils.NOT_SPECIFIED;
internal.threadCount = getThreadCount();
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index f0a8d56..10ef955 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -260,6 +260,16 @@
horizontalClassMergerOptions.setRestrictToSynthetics();
}
+ public void configureAndroidPlatformBuild(boolean isAndroidPlatformBuild) {
+ if (!isAndroidPlatformBuild) {
+ return;
+ }
+ // Configure options according to platform build assumptions.
+ // See go/r8platformflag and b/232073181.
+ minApiLevel = ANDROID_PLATFORM;
+ apiModelingOptions().disableMissingApiModeling();
+ }
+
public boolean printTimes = System.getProperty("com.android.tools.r8.printtimes") != null;
// To print memory one also have to enable printtimes.
public boolean printMemory = System.getProperty("com.android.tools.r8.printmemory") != null;
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
index 0dcd986..017c652 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -8,6 +8,7 @@
import static com.android.tools.r8.ToolHelper.isTestingR8Lib;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.compilerapi.androidplatformbuild.AndroidPlatformBuildApiTest;
import com.android.tools.r8.compilerapi.assertionconfiguration.AssertionConfigurationTest;
import com.android.tools.r8.compilerapi.desugardependencies.DesugarDependenciesTest;
import com.android.tools.r8.compilerapi.globalsynthetics.GlobalSyntheticsTest;
@@ -45,7 +46,8 @@
ImmutableList.of(
GlobalSyntheticsTest.ApiTest.class,
CommandLineParserTest.ApiTest.class,
- EnableMissingLibraryApiModelingTest.ApiTest.class);
+ EnableMissingLibraryApiModelingTest.ApiTest.class,
+ AndroidPlatformBuildApiTest.ApiTest.class);
private final TemporaryFolder temp;
diff --git a/src/test/java/com/android/tools/r8/compilerapi/androidplatformbuild/AndroidPlatformBuildApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/androidplatformbuild/AndroidPlatformBuildApiTest.java
new file mode 100644
index 0000000..07d01cc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/androidplatformbuild/AndroidPlatformBuildApiTest.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.compilerapi.androidplatformbuild;
+
+import static com.android.tools.r8.MarkerMatcher.markerMinApi;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+public class AndroidPlatformBuildApiTest extends CompilerApiTestRunner {
+
+ public AndroidPlatformBuildApiTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<? extends CompilerApiTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ ApiTest test = new ApiTest(ApiTest.PARAMETERS);
+ runTest(test::runD8);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ ApiTest test = new ApiTest(ApiTest.PARAMETERS);
+ runTest(test::runR8);
+ }
+
+ private void runTest(ThrowingConsumer<ProgramConsumer, Exception> test) throws Exception {
+ Path output = temp.newFolder().toPath().resolve("out.jar");
+ test.accept(new DexIndexedConsumer.ArchiveConsumer(output));
+ assertThat(
+ new CodeInspector(output).getMarkers(),
+ CoreMatchers.everyItem(markerMinApi(AndroidApiLevel.ANDROID_PLATFORM)));
+ }
+
+ public static class ApiTest extends CompilerApiTest {
+
+ public ApiTest(Object parameters) {
+ super(parameters);
+ }
+
+ public void runD8(ProgramConsumer programConsumer) throws Exception {
+ D8.run(
+ D8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setProgramConsumer(programConsumer)
+ .setAndroidPlatformBuild(true)
+ .build());
+ }
+
+ public void runR8(ProgramConsumer programConsumer) throws Exception {
+ R8.run(
+ R8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addProguardConfiguration(getKeepMainRules(getMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setProgramConsumer(programConsumer)
+ .setAndroidPlatformBuild(true)
+ .build());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ runD8(DexIndexedConsumer.emptyConsumer());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runR8(DexIndexedConsumer.emptyConsumer());
+ }
+ }
+}