Add UncheckedApiLevel (replacing int).
AndroidApiLevel.getAndroidApiLevel(42, 42) returns 38.0. So this can't
be used for the frontend as it is. And it can't be made stricter for
unrelated reasons (tests rely on the rounding).
This is the cleanest way to introduce minor versions everywhere without
sorting out the issues around AndroidApiLevel.
This is not a complete removal of major-only code, but one step towards
it.
Bug: b/356841164
Change-Id: Ia12d7194d7b758bac24341dd4afe6b9e118f6a04
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 6a6d5f3..684b315 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.FileUtils;
import com.android.tools.r8.utils.internal.ListUtils;
import java.nio.file.Path;
@@ -54,7 +55,7 @@
private final CompilationMode mode;
private final ProgramConsumer programConsumer;
private final StringConsumer mainDexListConsumer;
- private final int minApiLevel;
+ private final UncheckedApiLevel minApiLevel;
private final Reporter reporter;
private final DesugarState desugarState;
private final boolean includeClassesChecksum;
@@ -79,7 +80,7 @@
programConsumer = null;
mainDexListConsumer = null;
mode = null;
- minApiLevel = 0;
+ minApiLevel = new UncheckedApiLevel(1, 0);
reporter = new Reporter();
desugarState = DesugarState.ON;
includeClassesChecksum = false;
@@ -105,7 +106,7 @@
CompilationMode mode,
ProgramConsumer programConsumer,
StringConsumer mainDexListConsumer,
- int minApiLevel,
+ UncheckedApiLevel minApiLevel,
Reporter reporter,
DesugarState desugarState,
boolean optimizeMultidexForLinearAlloc,
@@ -125,7 +126,6 @@
boolean enableVerboseSyntheticNames,
Path apiDatabasePath) {
super(app);
- assert minApiLevel > 0;
assert mode != null;
this.mode = mode;
this.programConsumer = programConsumer;
@@ -159,8 +159,17 @@
return mode;
}
- /** Get the minimum API level to compile against. */
+ /**
+ * Get the minimum API level to compile against.
+ *
+ * <p>Deprecation: Should not be used since it ignores minor versions.
+ */
+ @Deprecated
public int getMinApiLevel() {
+ return getUncheckedMinApiLevel().getMajor();
+ }
+
+ UncheckedApiLevel getUncheckedMinApiLevel() {
return minApiLevel;
}
@@ -168,7 +177,7 @@
builder
.setBackend(ProgramConsumerUtils.getBackend(programConsumer))
.setCompilationMode(getMode())
- .setMinApi(getMinApiLevel())
+ .setMinApi(getUncheckedMinApiLevel())
.setOptimizeMultidexForLinearAlloc(isOptimizeMultidexForLinearAlloc())
.setThreadCount(getThreadCount())
.setDesugarState(getDesugarState())
@@ -294,10 +303,7 @@
private OutputMode outputMode = OutputMode.DexIndexed;
private CompilationMode mode;
- private int minMajorApiLevel = 0;
-
- @SuppressWarnings("UnusedVariable")
- private int minMinorApiLevel = 0;
+ private UncheckedApiLevel minApiLevel = null;
private int threadCount = ThreadUtils.NOT_SPECIFIED;
protected DesugarState desugarState = DesugarState.ON;
@@ -553,35 +559,50 @@
return self();
}
- /** Get the minimum API level (aka SDK version). */
+ /**
+ * Get the minimum API level (aka SDK version).
+ *
+ * <p>Deprecation: Should not be used since it ignores minor versions.
+ */
+ @Deprecated
public int getMinApiLevel() {
- return isMinApiLevelSet() ? minMajorApiLevel : AndroidApiLevel.getDefault().getMajor();
+ return getUncheckedMinApiLevel().getMajor();
+ }
+
+ UncheckedApiLevel getUncheckedMinApiLevel() {
+ if (isMinApiLevelSet()) {
+ return minApiLevel;
+ } else {
+ var base = AndroidApiLevel.getDefault();
+ return new UncheckedApiLevel(base.getMajor(), base.getMinor());
+ }
}
boolean isMinApiLevelSet() {
- return minMajorApiLevel != 0;
+ return minApiLevel != null;
}
/** Set the minimum required API level (aka SDK version). */
- public B setMinApiLevel(int minMajorApiLevel) {
- if (minMajorApiLevel <= 0) {
- getReporter().error("Invalid minApiLevel: " + minMajorApiLevel);
- return self();
- }
- return setMinApiLevel(minMajorApiLevel, 0);
+ public B setMinApiLevel(int major) {
+ return setMinApiLevel(major, 0);
}
/** Set the minimum required API level (aka SDK version). */
- public B setMinApiLevel(int minMajorApiLevel, int minMinorApiLevel) {
- if (minMajorApiLevel <= 0 || minMinorApiLevel < 0) {
- getReporter().error("Invalid minApiLevel: " + minMajorApiLevel + "." + minMinorApiLevel);
+ public B setMinApiLevel(int major, int minor) {
+ if (major <= 0 || minor < 0) {
+ getReporter().error("Invalid minApiLevel: " + major + "." + minor);
} else {
- this.minMajorApiLevel = minMajorApiLevel;
- this.minMinorApiLevel = minMinorApiLevel;
+ this.minApiLevel = new UncheckedApiLevel(major, minor);
}
return self();
}
+ /** Set the minimum required API level (aka SDK version). */
+ B setMinApiLevel(UncheckedApiLevel minApiLevel) {
+ this.minApiLevel = minApiLevel;
+ return self();
+ }
+
@Deprecated
public B setEnableDesugaring(boolean enableDesugaring) {
this.desugarState = enableDesugaring ? DesugarState.ON : DesugarState.OFF;
@@ -674,12 +695,15 @@
}
StringResource desugaredLibrarySpecificationResource =
desugaredLibrarySpecificationResources.get(0);
+ // TODO(b/356841164): Support minor version.
+ assert getUncheckedMinApiLevel().getMinor() == 0
+ : "Minor API version not yet supported: " + getUncheckedMinApiLevel();
return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
desugaredLibrarySpecificationResource,
factory,
getReporter(),
libraryCompilation,
- getMinApiLevel());
+ getUncheckedMinApiLevel().getMajor());
}
boolean hasDesugaredLibraryConfiguration() {
@@ -862,9 +886,11 @@
}
reporter.error(builder.toString());
}
- if (getMinApiLevel() > AndroidApiLevel.LATEST.getMajor()) {
- if (getMinApiLevel() != AndroidApiLevel.ANDROID_PLATFORM_CONSTANT) {
- reporter.warning(new UnsupportedAndroidApiLevelDiagnostic(getMinApiLevel(), 0));
+ UncheckedApiLevel apiLevel = getUncheckedMinApiLevel();
+ if (apiLevel.isGreaterThan(AndroidApiLevel.LATEST.asUnchecked())) {
+ if (!(apiLevel.equals(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT))) {
+ reporter.warning(
+ new UnsupportedAndroidApiLevelDiagnostic(apiLevel.getMajor(), apiLevel.getMinor()));
}
}
if (hasDesugaredLibraryConfiguration() && getAndroidPlatformBuild()) {
@@ -917,7 +943,8 @@
}
boolean hasNativeMultidex() {
- return isMinApiLevelSet() && getMinApiLevel() >= AndroidApiLevel.L.getMajor();
+ return isMinApiLevelSet()
+ && getUncheckedMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L.asUnchecked());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index bf81738..f1c0418 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.SystemPropertyUtils;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.internal.FileUtils;
import com.google.common.collect.ImmutableList;
@@ -511,13 +512,13 @@
reporter.error(
"Option --main-dex-list-output requires --main-dex-rules and/or --main-dex-list");
}
- if (getMinApiLevel() >= AndroidApiLevel.L_MR1.getMajor()) {
+ if (getUncheckedMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1.asUnchecked())) {
if (getMainDexListConsumer() != null || getAppBuilder().hasMainDexList()) {
reporter.error(
"D8 does not support main-dex inputs and outputs when compiling to API level "
- + AndroidApiLevel.L_MR1.getMajor()
+ + AndroidApiLevel.L_MR1.getNumericString()
+ " and above (min API level "
- + getMinApiLevel()
+ + getUncheckedMinApiLevel()
+ " was provided)");
}
}
@@ -533,12 +534,12 @@
if (intermediate) {
reporter.error("D8 startup layout is not supported in intermediate mode");
}
- if (getMinApiLevel() < AndroidApiLevel.L.getMajor()) {
+ if (getUncheckedMinApiLevel().isLessThan(AndroidApiLevel.L.asUnchecked())) {
reporter.error(
"D8 startup layout requires native multi dex support (API level "
- + AndroidApiLevel.L.getMajor()
+ + AndroidApiLevel.L.getNumericString()
+ " and above, min API level "
- + getMinApiLevel()
+ + getUncheckedMinApiLevel()
+ " was provided)");
}
}
@@ -580,10 +581,10 @@
}
// If compiling to CF with --no-desugaring then the target API is B for consistency with R8.
- int minApiLevel =
+ var minApiLevel =
programConsumer instanceof ClassFileConsumer && getDisableDesugaring()
- ? AndroidApiLevel.B.getMajor()
- : getMinApiLevel();
+ ? AndroidApiLevel.B.asUnchecked()
+ : getUncheckedMinApiLevel();
GlobalSyntheticsConsumer globalConsumer =
GlobalSyntheticsUtils.determineGlobalSyntheticsConsumer(
@@ -698,7 +699,7 @@
CompilationMode mode,
ProgramConsumer programConsumer,
StringConsumer mainDexListConsumer,
- int minApiLevel,
+ UncheckedApiLevel minApiLevel,
Reporter diagnosticsHandler,
DesugarState enableDesugaring,
boolean intermediate,
@@ -814,7 +815,7 @@
internal.mainDexListConsumer = getMainDexListConsumer();
internal.minimalMainDex = internal.debug || minimalMainDex;
internal.enableMainDexListCheck = enableMainDexListCheck;
- internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
+ internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getUncheckedMinApiLevel()));
internal.apiModelingOptions().apiDatabasePath = getApiDatabasePath();
internal.intermediate = intermediate;
if (reoptimizeDex) { // Respect potential system property.
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 4ba58d0..2025ec4 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.collections.Pair;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
@@ -91,7 +92,7 @@
CompilationMode mode,
ProgramConsumer programConsumer,
StringConsumer mainDexListConsumer,
- int minApiLevel,
+ UncheckedApiLevel minApiLevel,
Reporter diagnosticsHandler,
boolean encodeChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
@@ -186,7 +187,7 @@
internal.debug = getMode() == CompilationMode.DEBUG;
assert internal.mainDexListConsumer == null;
assert !internal.minimalMainDex;
- internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
+ internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getUncheckedMinApiLevel()));
assert !internal.intermediate;
assert internal.retainCompileTimeAnnotations;
internal.programConsumer = getProgramConsumer();
@@ -408,7 +409,7 @@
.enableLegacyFullModeForKeepRules(false)
.setSynthesizedClassesPrefix(
desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix())
- .setMinApiLevel(getMinApiLevel())
+ .setMinApiLevel(getUncheckedMinApiLevel())
.setMode(getMode())
.setIncludeClassesChecksum(getIncludeClassesChecksum())
.setDexClassChecksumFilter(getDexClassChecksumFilter())
@@ -449,7 +450,7 @@
.addProgramResourceProvider((ProgramResourceProvider) l8CfConsumer)
.setSynthesizedClassesPrefix(
desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix())
- .setMinApiLevel(getMinApiLevel())
+ .setMinApiLevel(getUncheckedMinApiLevel())
.setMode(getMode())
.setIncludeClassesChecksum(getIncludeClassesChecksum())
.setDexClassChecksumFilter(getDexClassChecksumFilter())
@@ -476,7 +477,7 @@
getMode(),
l8CfConsumer,
getMainDexListConsumer(),
- getMinApiLevel(),
+ getUncheckedMinApiLevel(),
getReporter(),
getIncludeClassesChecksum(),
getDexClassChecksumFilter(),
diff --git a/src/main/java/com/android/tools/r8/R8AssistantCommand.java b/src/main/java/com/android/tools/r8/R8AssistantCommand.java
index f0dd30e..ef2a8b4 100644
--- a/src/main/java/com/android/tools/r8/R8AssistantCommand.java
+++ b/src/main/java/com/android/tools/r8/R8AssistantCommand.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import java.nio.file.Path;
import java.util.Collections;
@@ -37,11 +38,12 @@
private final String reflectiveReceiverDescriptor;
- public R8AssistantCommand(
+ @SuppressWarnings("InconsistentOverloads")
+ private R8AssistantCommand(
AndroidApp app,
CompilationMode mode,
ProgramConsumer programConsumer,
- int minApiLevel,
+ UncheckedApiLevel minApiLevel,
Reporter reporter,
String reflectiveReceiverDescriptor,
Path apiDatabasePath) {
@@ -72,6 +74,26 @@
this.reflectiveReceiverDescriptor = reflectiveReceiverDescriptor;
}
+ /** Deprecation: Use {@link #builder()} or {@link #builder(DiagnosticsHandler)}. */
+ @Deprecated
+ public R8AssistantCommand(
+ AndroidApp app,
+ CompilationMode mode,
+ ProgramConsumer programConsumer,
+ int minApiLevelMajor,
+ Reporter reporter,
+ String reflectiveReceiverDescriptor,
+ Path apiDatabasePath) {
+ this(
+ app,
+ mode,
+ programConsumer,
+ new UncheckedApiLevel(minApiLevelMajor, 0),
+ reporter,
+ reflectiveReceiverDescriptor,
+ apiDatabasePath);
+ }
+
public static Builder builder(DiagnosticsHandler reporter) {
return new Builder(reporter);
}
@@ -84,13 +106,13 @@
InternalOptions getInternalOptions() {
DexItemFactory factory = new DexItemFactory();
InternalOptions options = new InternalOptions(factory, getReporter());
- options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
+ options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getUncheckedMinApiLevel()));
options.apiModelingOptions().apiDatabasePath = getApiDatabasePath();
options.passthroughDexCode = true;
options.tool = Tool.R8Assistant;
Marker marker = new Marker(Tool.R8Assistant);
marker.setBackend(Backend.DEX);
- marker.setMinApi(getMinApiLevel());
+ marker.setMinApi(getUncheckedMinApiLevel());
options.setMarker(marker);
options.programConsumer = getProgramConsumer();
return options;
@@ -171,7 +193,7 @@
getAppBuilder().build(),
getMode(),
getProgramConsumer(),
- getMinApiLevel(),
+ getUncheckedMinApiLevel(),
getReporter(),
reflectiveReceiverDescriptor,
getApiDatabasePath());
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 4782395..bdb8e2a 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -68,6 +68,7 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.SystemPropertyUtils;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.Box;
import com.android.tools.r8.utils.internal.FileUtils;
import com.android.tools.r8.utils.internal.ListUtils;
@@ -930,7 +931,7 @@
getMainDexListConsumer(),
configuration,
getMode(),
- getMinApiLevel(),
+ getUncheckedMinApiLevel(),
reporter,
desugaring,
configuration.isShrinking(),
@@ -1312,7 +1313,7 @@
StringConsumer mainDexListConsumer,
ProguardConfiguration proguardConfiguration,
CompilationMode mode,
- int minApiLevel,
+ UncheckedApiLevel minApiLevel,
Reporter reporter,
DesugarState enableDesugaring,
boolean enableTreeShaking,
@@ -1476,7 +1477,7 @@
internal.created = created;
assert !internal.testing.allowOutlinerInterfaceArrayArguments; // Only allow in tests.
internal.programConsumer = getProgramConsumer();
- internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
+ internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getUncheckedMinApiLevel()));
internal.apiModelingOptions().apiDatabasePath = getApiDatabasePath();
internal.desugarState = getDesugarState();
internal.desugarSpecificOptions().enableVerboseSyntheticNames = enableVerboseSyntheticNames;
diff --git a/src/main/java/com/android/tools/r8/dex/Marker.java b/src/main/java/com/android/tools/r8/dex/Marker.java
index bb483ca..064ca0f 100644
--- a/src/main/java/com/android/tools/r8/dex/Marker.java
+++ b/src/main/java/com/android/tools/r8/dex/Marker.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.StringUtils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -120,12 +122,23 @@
return jsonObject.get(MIN_API).getAsLong();
}
- public Marker setMinApi(long minApi) {
+ public Marker setMinApi(int major, int minor) {
+ // TODO(b/356841164): Support minor version.
+ assert minor == 0
+ : "Minor version not yet supported: " + UncheckedApiLevel.toString(major, minor);
assert !jsonObject.has(MIN_API);
- jsonObject.addProperty(MIN_API, minApi);
+ jsonObject.addProperty(MIN_API, major);
return this;
}
+ public Marker setMinApi(UncheckedApiLevel apiLevel) {
+ return setMinApi(apiLevel.getMajor(), apiLevel.getMinor());
+ }
+
+ public Marker setMinApi(AndroidApiLevel apiLevel) {
+ return setMinApi(apiLevel.getMajor(), apiLevel.getMinor());
+ }
+
public boolean hasDesugaredLibraryIdentifiers() {
return jsonObject.has(DESUGARED_LIBRARY_IDENTIFIERS);
}
diff --git a/src/main/java/com/android/tools/r8/dump/DumpOptions.java b/src/main/java/com/android/tools/r8/dump/DumpOptions.java
index 10dc346..3623860 100644
--- a/src/main/java/com/android/tools/r8/dump/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/dump/DumpOptions.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
@@ -247,7 +248,7 @@
}
return;
case MIN_API_KEY:
- builder.setMinApi(Integer.parseInt(value));
+ builder.setMinApi(Integer.parseInt(value), 0);
return;
case OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY:
builder.setOptimizeMultidexForLinearAlloc(Boolean.parseBoolean(value));
@@ -461,8 +462,13 @@
return this;
}
- public Builder setMinApi(int minApi) {
- this.minApi = minApi;
+ public Builder setMinApi(int major, int minor) {
+ return setMinApi(new UncheckedApiLevel(major, minor));
+ }
+
+ public Builder setMinApi(UncheckedApiLevel apiLevel) {
+ assert apiLevel.getMinor() == 0 : "minor versions not yet supported: " + apiLevel;
+ this.minApi = apiLevel.getMajor();
return this;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 15c0919..208dec3 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -65,7 +65,8 @@
public static final AndroidApiLevel UNKNOWN;
/** Constant used to signify some unknown min api when compiling platform. */
- public static final int ANDROID_PLATFORM_CONSTANT = 10_000;
+ public static final UncheckedApiLevel ANDROID_PLATFORM_CONSTANT =
+ new UncheckedApiLevel(10_000, 0);
static {
ImmutableList.Builder<AndroidApiLevel> builder = ImmutableList.builder();
@@ -212,6 +213,14 @@
return getAndroidApiLevel(major, 0);
}
+ public static AndroidApiLevel getAndroidApiLevel(UncheckedApiLevel apiLevel) {
+ return getAndroidApiLevel(apiLevel.getMajor(), apiLevel.getMinor());
+ }
+
+ public UncheckedApiLevel asUnchecked() {
+ return new UncheckedApiLevel(major, minor);
+ }
+
/**
* @throws IllegalArgumentException if the parsed API version is invalid (e.g. 99.99).
*/
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 888e610..50cc102 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -669,7 +669,7 @@
// since the output depends on the min API in this case. There is basically no min API entry
// in R8 cf to cf.
if (isGeneratingDex() || desugarState == DesugarState.ON) {
- marker.setMinApi(getMinApiLevel().getMajor());
+ marker.setMinApi(getMinApiLevel());
}
if (libraryDesugaringOptions.hasIdentifier()) {
marker.setDesugaredLibraryIdentifiers(libraryDesugaringOptions.getIdentifier());
diff --git a/src/main/java/com/android/tools/r8/utils/UncheckedApiLevel.java b/src/main/java/com/android/tools/r8/utils/UncheckedApiLevel.java
new file mode 100644
index 0000000..7c0f744
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/UncheckedApiLevel.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2026, 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.utils;
+
+import com.android.tools.r8.utils.internal.ObjectUtils;
+import com.android.tools.r8.utils.structural.Ordered;
+
+public class UncheckedApiLevel implements Ordered<UncheckedApiLevel> {
+
+ protected final int major;
+ protected final int minor;
+
+ public UncheckedApiLevel(int major, int minor) {
+ if (major <= 0 || minor < 0) {
+ throw new RuntimeException("Invalid API version: " + toString(major, minor));
+ }
+ this.major = major;
+ this.minor = minor;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public static String toString(int major, int minor) {
+ return major + "." + minor;
+ }
+
+ @Override
+ public String toString() {
+ return toString(major, minor);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (!(obj instanceof UncheckedApiLevel)) {
+ return false;
+ } else {
+ var other = (UncheckedApiLevel) obj;
+ return major == other.major && minor == other.minor;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return ObjectUtils.hashII(major, minor);
+ }
+
+ @Override
+ public int compareTo(UncheckedApiLevel other) {
+ if (major == other.major) {
+ return Integer.compare(minor, other.minor);
+ } else {
+ return Integer.compare(major, other.major);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index 45e7629..fc8630c 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -166,7 +166,7 @@
BackportedMethodListCommand.Builder builder =
BackportedMethodListCommand.builder().setMinApiLevel(apiLevel).setConsumer(consumer);
if (mode == Mode.LIBRARY) {
- builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getMajor()));
+ builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P));
} else if (mode == Mode.LIBRARY_DESUGAR || mode == Mode.LIBRARY_DESUGAR_11) {
addLibraryDesugaring(builder);
}
@@ -183,7 +183,7 @@
BackportedMethodListCommand.Builder builder =
BackportedMethodListCommand.builder().setMinApiLevel(apiLevel).setOutputPath(output);
if (mode == Mode.LIBRARY) {
- builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getMajor()));
+ builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P));
} else if (mode == Mode.LIBRARY_DESUGAR || mode == Mode.LIBRARY_DESUGAR_11) {
addLibraryDesugaring(builder);
}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index b2dea8b..7dc2014 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -80,7 +80,9 @@
private void verifyEmptyCommand(D8Command command) throws Throwable {
assertEquals(CompilationMode.DEBUG, command.getMode());
- assertEquals(AndroidVersion.DEFAULT.getApiLevel(), command.getMinApiLevel());
+ assertEquals(
+ AndroidVersion.DEFAULT.getApiLevel(), command.getUncheckedMinApiLevel().getMajor());
+ assertEquals(0, command.getUncheckedMinApiLevel().getMinor());
assertTrue(command.getProgramConsumer() instanceof DexIndexedConsumer);
AndroidApp app = ToolHelper.getApp(command);
assertEquals(0, app.getDexProgramResourcesForTesting().size());
diff --git a/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java b/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
index f1de061..742a6ee 100644
--- a/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/d8/D8FrameworkDexPassthroughMarkerTest.java
@@ -44,23 +44,19 @@
@Parameters(name = "Min api = {0}")
public static Collection<Object[]> data() {
return Arrays.asList(
- new Object[][] {
- {AndroidApiLevel.N.getMajor()},
- {AndroidApiLevel.O.getMajor()},
- {AndroidApiLevel.O_MR1.getMajor()}
- });
+ new Object[][] {{AndroidApiLevel.N}, {AndroidApiLevel.O}, {AndroidApiLevel.O_MR1}});
}
- private final int minApi;
+ private final AndroidApiLevel minApi;
- public D8FrameworkDexPassthroughMarkerTest(int minApi) {
+ public D8FrameworkDexPassthroughMarkerTest(AndroidApiLevel minApi) {
this.minApi = minApi;
}
@Test
public void compile() throws Exception {
- D8Command.Builder command =
- D8Command.builder().setMinApiLevel(minApi).addProgramFiles(FRAMEWORK_JAR);
+ D8Command.Builder command = D8Command.builder().addProgramFiles(FRAMEWORK_JAR);
+ ToolHelper.setMinApiLevel(command, minApi.asUnchecked());
Marker marker = new Marker(Tool.D8)
.setVersion("1.0.0")
.setMinApi(minApi);
diff --git a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyFirstOutlineTest.java b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyFirstOutlineTest.java
index a5bfcd5..757d049 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyFirstOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyFirstOutlineTest.java
@@ -59,7 +59,8 @@
testForR8(Backend.DEX)
.addInnerClasses(getClass())
.addKeepAllClassesRule()
- .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT)
+ // TODO(b/356841164): Use full version.
+ .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT.getMajor())
.compile()
.apply(x -> System.out.println(x.getProguardMap()))
.inspect(inspector -> inspect(inspector, true, false));
@@ -71,7 +72,8 @@
.addInnerClasses(getClass())
.addKeepAllClassesRule()
.addOptionsModification(options -> options.testing.forcePcBasedEncoding = true)
- .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT)
+ // TODO(b/356841164): Use full version.
+ .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT.getMajor())
.compile()
.apply(x -> System.out.println(x.getProguardMap()))
.inspect(inspector -> inspect(inspector, true, true));
diff --git a/src/test/java/com/android/tools/r8/examples/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/examples/D8IncrementalRunExamplesAndroidOTest.java
index a990e60..91c8a00 100644
--- a/src/test/java/com/android/tools/r8/examples/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/examples/D8IncrementalRunExamplesAndroidOTest.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.internal.Box;
import com.android.tools.r8.utils.internal.FileUtils;
import com.android.tools.r8.utils.internal.StringUtils;
@@ -200,8 +201,8 @@
androidJarVersion != null || b.getMinApiLevel() >= 0
? ToolHelper.getAndroidJar(
androidJarVersion != null
- ? androidJarVersion.getMajor()
- : b.getMinApiLevel())
+ ? androidJarVersion.asUnchecked()
+ : new UncheckedApiLevel(b.getMinApiLevel(), 0))
: ToolHelper.getMostRecentAndroidJar(),
b::addLibraryFiles,
b::addLibraryResourceProviders);
diff --git a/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidNTest.java b/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidNTest.java
index 02490d0..9f649ec 100644
--- a/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidNTest.java
+++ b/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidNTest.java
@@ -32,7 +32,7 @@
builder = transformation.apply(builder);
}
builder
- .addLibraryFiles(ToolHelper.getAndroidJar(builder.getMinApiLevel()))
+ .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getUncheckedMinApiLevel(builder)))
.addProgramFiles(inputFile)
.setOutput(out, OutputMode.DexIndexed);
try {
diff --git a/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidOTest.java
index c410636..6c0412d 100644
--- a/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/examples/D8RunExamplesAndroidOTest.java
@@ -48,7 +48,9 @@
}
builder.addLibraryFiles(
ToolHelper.getAndroidJar(
- androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion.getMajor()));
+ androidJarVersion == null
+ ? ToolHelper.getUncheckedMinApiLevel(builder)
+ : androidJarVersion.asUnchecked()));
builder.addProgramFiles(inputFile);
visitFiles(getLegacyClassesRoot(inputFile, packageName), builder::addProgramFiles);
ToolHelper.runD8(builder, this::combinedOptionConsumer);
diff --git a/src/test/java/com/android/tools/r8/examples/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/examples/R8RunExamplesAndroidOTest.java
index 5b0920c..c01cb0d 100644
--- a/src/test/java/com/android/tools/r8/examples/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/examples/R8RunExamplesAndroidOTest.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.OffOrAuto;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -441,8 +442,8 @@
b.addLibraryFiles(
ToolHelper.getAndroidJar(
androidJarVersion == null
- ? b.getMinApiLevel()
- : androidJarVersion.getMajor()));
+ ? new UncheckedApiLevel(b.getMinApiLevel(), 0)
+ : androidJarVersion.asUnchecked()));
})
.collectSyntheticItems()
.compile()
diff --git a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticGeneratorAGPUseTest.java b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticGeneratorAGPUseTest.java
index e03c6b3..167a184 100644
--- a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticGeneratorAGPUseTest.java
+++ b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticGeneratorAGPUseTest.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.internal.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.internal.BooleanUtils;
import java.nio.file.Path;
import java.util.List;
import org.junit.Test;
@@ -49,14 +49,14 @@
Path globals = temp.newFile("all.globals").toPath();
GlobalSyntheticsGenerator.run(
GlobalSyntheticsGeneratorCommand.builder()
- .addLibraryFiles(getAndroidJar(36))
+ .addLibraryFiles(getAndroidJar(36, 0))
.setGlobalSyntheticsOutput(globals)
.build());
Path globalsDex = temp.newFile("globals.zip").toPath();
D8.run(
D8Command.builder()
- .addLibraryFiles(getAndroidJar(36))
+ .addLibraryFiles(getAndroidJar(36, 0))
.setMinApiLevel(21)
.addGlobalSyntheticsFiles(globals)
.setOutput(globalsDex, OutputMode.DexIndexed)
diff --git a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
index 83f4f3d..930c7b1 100644
--- a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
+++ b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
@@ -17,7 +17,7 @@
private void checkExpectedAndroidJar(Path androidJarPath, AndroidApiLevel apiLevel) {
assertEquals("android.jar", androidJarPath.getFileName().toString());
assertEquals(
- "lib-v" + apiLevel.getMajor(),
+ "lib-v" + apiLevel.getNumericString(),
androidJarPath.getName(androidJarPath.getNameCount() - 2).toString());
}
diff --git a/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentAnnotationsTest.java b/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentAnnotationsTest.java
index 2b72fed..99fabec 100644
--- a/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentAnnotationsTest.java
+++ b/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentAnnotationsTest.java
@@ -308,7 +308,7 @@
parameters.assumeR8TestParameters();
testForR8(parameters)
.addInnerClassesAndStrippedOuter(getClass())
- .addLibraryFiles(ToolHelper.getAndroidJar(35))
+ .addLibraryFiles(ToolHelper.getAndroidJar(35, 0))
.addKeepMainRule(RecordWithAnnotations.class)
.addKeepClassAndMembersRulesWithAllowObfuscation(
RecordComponentAnnotationsTest.Person.class)
diff --git a/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentSignatureTest.java b/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentSignatureTest.java
index fc3a59f..c88fb2a 100644
--- a/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentSignatureTest.java
+++ b/src/test/java17/com/android/tools/r8/jdk17/records/RecordComponentSignatureTest.java
@@ -136,7 +136,7 @@
parameters.assumeR8TestParameters();
testForR8(parameters)
.addInnerClassesAndStrippedOuter(getClass())
- .addLibraryFiles(ToolHelper.getAndroidJar(35))
+ .addLibraryFiles(ToolHelper.getAndroidJar(35, 0))
.addKeepMainRule(RecordWithSignature.class)
.applyIf(keepSignatures, TestShrinkerBuilder::addKeepAttributeSignature)
.compile()
diff --git a/src/test/java17/com/android/tools/r8/jdk17/string/StringBuilderWithAppendOutOfBoundsTest.java b/src/test/java17/com/android/tools/r8/jdk17/string/StringBuilderWithAppendOutOfBoundsTest.java
index bfcf3e4..f414b2f 100644
--- a/src/test/java17/com/android/tools/r8/jdk17/string/StringBuilderWithAppendOutOfBoundsTest.java
+++ b/src/test/java17/com/android/tools/r8/jdk17/string/StringBuilderWithAppendOutOfBoundsTest.java
@@ -42,7 +42,7 @@
testForR8(parameters.getBackend())
.addInnerClassesAndStrippedOuter(getClass())
.addKeepMainRule(Main.class)
- .addLibraryFiles(ToolHelper.getAndroidJar(35))
+ .addLibraryFiles(ToolHelper.getAndroidJar(35, 0))
.setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java b/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
index 9cc27ec..ce99425 100644
--- a/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
+++ b/src/test/java21/com/android/tools/r8/jdk21/twr/LookUpCloseResourceTest.java
@@ -183,7 +183,7 @@
}
private AppView<?> getAppInfo(InternalOptions options, int api) throws IOException {
- AndroidApp app = AndroidApp.builder().addProgramFile(ToolHelper.getAndroidJar(api)).build();
+ AndroidApp app = AndroidApp.builder().addProgramFile(ToolHelper.getAndroidJar(api, 0)).build();
DirectMappedDexApplication libHolder =
new ApplicationReader(app, options, Timing.empty()).readDirectSingleThreaded();
AppInfo initialAppInfo =
diff --git a/src/test/java8/apimodel/com/android/tools/r8/androidapi/GenerateAvailableApiExceptions.java b/src/test/java8/apimodel/com/android/tools/r8/androidapi/GenerateAvailableApiExceptions.java
index ce5aeaf..2884bba 100644
--- a/src/test/java8/apimodel/com/android/tools/r8/androidapi/GenerateAvailableApiExceptions.java
+++ b/src/test/java8/apimodel/com/android/tools/r8/androidapi/GenerateAvailableApiExceptions.java
@@ -27,7 +27,7 @@
public class GenerateAvailableApiExceptions {
- private static final int fixedApiLevel = AndroidApiLevel.L.getMajor();
+ private static final AndroidApiLevel fixedApiLevel = AndroidApiLevel.L;
private static String generateBuildMapCode(Path apiVersionsXml) throws Exception {
CodeInspector inspector = new CodeInspector(ToolHelper.getAndroidJar(fixedApiLevel));
@@ -47,7 +47,7 @@
continue;
}
int since = Integer.parseInt(sinceAttr.getNodeValue());
- if (since >= fixedApiLevel) {
+ if (since >= fixedApiLevel.getMajor()) {
continue;
}
String name = node.getAttributes().getNamedItem("name").getNodeValue();
@@ -64,7 +64,7 @@
builder.append("public class DoNotCommit {");
builder.append("public static Set<DexType> build(DexItemFactory factory, int minApiLevel) {");
builder.append(" Set<DexType> types = SetUtils.newIdentityHashSet(" + totalCount + ");");
- for (int api = 1; api < fixedApiLevel; api++) {
+ for (int api = 1; api < fixedApiLevel.getMajor(); api++) {
Set<String> names = exceptionsMap.get(api);
if (names == null || names.isEmpty()) {
continue;
diff --git a/src/test/java8/desugar/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java8/desugar/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index 473eb0d..a9fbfdf 100644
--- a/src/test/java8/desugar/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java8/desugar/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -111,7 +111,8 @@
public void noWarningForPlatformBuild() throws Exception {
testForD8()
.addProgramClassFileData(transformTestMathMultiplyExactLongInt())
- .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT)
+ // TODO(b/356841164): Use full version.
+ .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT.getMajor())
.setOutputMode(OutputMode.DexFilePerClassFile)
.compile()
.assertNoMessages()
diff --git a/src/test/java8/desugar/com/android/tools/r8/desugar/desugaredlibrary/DesugaredMethodListCommandTest.java b/src/test/java8/desugar/com/android/tools/r8/desugar/desugaredlibrary/DesugaredMethodListCommandTest.java
index 9487344..8190c25 100644
--- a/src/test/java8/desugar/com/android/tools/r8/desugar/desugaredlibrary/DesugaredMethodListCommandTest.java
+++ b/src/test/java8/desugar/com/android/tools/r8/desugar/desugaredlibrary/DesugaredMethodListCommandTest.java
@@ -58,7 +58,7 @@
"--desugared-lib-jar",
libraryDesugaringSpecification.getDesugarJdkLibs().iterator().next().toString(),
"--lib",
- ToolHelper.getAndroidJar(34).toString()
+ ToolHelper.getAndroidJar(34, 0).toString()
},
new Reporter(diagnosticMessages));
diagnosticMessages.assertErrorMessageThatMatches(
@@ -117,7 +117,7 @@
commandList.add(desugarJdkLib.toString());
}
commandList.add("--lib");
- commandList.add(ToolHelper.getAndroidJar(34).toString());
+ commandList.add(ToolHelper.getAndroidJar(34, 0).toString());
String[] commandArray = commandList.stream().toArray(String[]::new);
DesugaredMethodsListCommand command = DesugaredMethodsListCommand.parse(commandArray);
assertFalse(command.getDesugarLibraryImplementation().isEmpty());
diff --git a/src/test/java8/shaking/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java b/src/test/java8/shaking/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
index 701eb75..42b1006 100644
--- a/src/test/java8/shaking/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
+++ b/src/test/java8/shaking/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
@@ -362,7 +362,8 @@
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class)
.addKeepMainRule(TestClass.class)
- .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT)
+ // TODO(b/356841164): Use full version.
+ .setMinApi(AndroidApiLevel.ANDROID_PLATFORM_CONSTANT.getMajor())
.compile()
.getSyntheticProguardRules();
for (ProguardConfigurationRule rule : rules) {
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBase.java b/src/test/testbase/java/com/android/tools/r8/TestBase.java
index 4a4c9c3..0bdebe4 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBase.java
@@ -734,7 +734,7 @@
for (byte[] clazz : classes) {
builder.addClassProgramData(clazz, Origin.unknown());
}
- builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N.getMajor()));
+ builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N));
return builder.build();
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
index bd78146..650407c 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -361,7 +361,7 @@
assert builder.isMinApiLevelSet();
return Collections.singletonList(
ToolHelper.getFirstSupportedAndroidJar(
- AndroidApiLevel.getAndroidApiLevel(builder.getMinApiLevel())));
+ AndroidApiLevel.getAndroidApiLevel(builder.getUncheckedMinApiLevel())));
} else {
assert backend == Backend.CF;
return Collections.singletonList(ToolHelper.getJava8RuntimeJar());
@@ -393,7 +393,10 @@
&& backend.isDex()
&& (isD8TestBuilder() || isR8TestBuilder() || isR8PartialTestBuilder())
&& !isBenchmarkRunner) {
- int minApiLevel = builder.getMinApiLevel();
+ // TODO(b/356841164): Support minor version.
+ assert builder.getUncheckedMinApiLevel().getMinor() == 0
+ : "Minor API version not yet supported: " + builder.getUncheckedMinApiLevel();
+ int minApiLevel = builder.getUncheckedMinApiLevel().getMajor();
Consumer<InternalOptions> previousConsumer = optionsConsumer;
optionsConsumer =
options -> {
@@ -464,9 +467,16 @@
internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build), benchmark)
.addRunClasspathFiles(additionalRunClassPath);
if (isAndroidBuildVersionAdded != null) {
- cr.setSystemProperty(
- AndroidBuildVersion.PROPERTY,
- "" + isAndroidBuildVersionAdded.orElse(builder.getMinApiLevel()));
+ int version;
+ if (isAndroidBuildVersionAdded.isPresent()) {
+ version = isAndroidBuildVersionAdded.get();
+ } else {
+ // TODO(b/356841164): Use full version.
+ assert builder.getUncheckedMinApiLevel().getMinor() == 0
+ : "Minor API version not yet supported: " + builder.getUncheckedMinApiLevel();
+ version = builder.getUncheckedMinApiLevel().getMajor();
+ }
+ cr.setSystemProperty(AndroidBuildVersion.PROPERTY, "" + version);
}
return cr;
} finally {
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
index e008a13..9393aba 100644
--- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -42,6 +42,7 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.UncheckedApiLevel;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.internal.FileUtils;
import com.android.tools.r8.utils.internal.ListUtils;
@@ -1244,18 +1245,22 @@
public static Path getFirstSupportedAndroidJar(AndroidApiLevel apiLevel) {
// Fast path.
if (hasAndroidJar(apiLevel)) {
- return getAndroidJar(apiLevel.getMajor());
+ return getAndroidJar(apiLevel);
}
// Search for an android jar.
for (AndroidApiLevel level : AndroidApiLevel.getAndroidApiLevelsSorted()) {
- if (level.getMajor() >= apiLevel.getMajor() && hasAndroidJar(level)) {
- return getAndroidJar(level.getMajor());
+ if (level.isGreaterThanOrEqualTo(apiLevel) && hasAndroidJar(level)) {
+ return getAndroidJar(level);
}
}
return getAndroidJar(AndroidApiLevel.LATEST);
}
- public static Path getAndroidJar(int apiLevel) {
+ public static Path getAndroidJar(int apiLevelMajor, int apiLevelMinor) {
+ return getAndroidJar(new UncheckedApiLevel(apiLevelMajor, apiLevelMinor));
+ }
+
+ public static Path getAndroidJar(UncheckedApiLevel apiLevel) {
return getAndroidJar(AndroidApiLevel.getAndroidApiLevel(apiLevel));
}
@@ -1940,7 +1945,8 @@
// Add the android library matching the minsdk. We filter out junit and testing classes
// from the android jar to avoid duplicate classes in art tests.
AndroidApp.Builder builder = AndroidApp.builder(app);
- addFilteredAndroidJar(builder, AndroidApiLevel.getAndroidApiLevel(command.getMinApiLevel()));
+ addFilteredAndroidJar(
+ builder, AndroidApiLevel.getAndroidApiLevel(command.getUncheckedMinApiLevel()));
app = builder.build();
}
InternalOptions options = command.getInternalOptions();
@@ -2987,4 +2993,15 @@
R8Command.Builder builder, boolean enabled) {
builder.setReadEmbeddedRulesFromClasspathAndLibrary(enabled);
}
+
+ // Bridge to avoid public methods in @KeepForApi classes.
+ public static UncheckedApiLevel getUncheckedMinApiLevel(
+ BaseCompilerCommand.Builder<?, ?> builder) {
+ return builder.getUncheckedMinApiLevel();
+ }
+
+ // Bridge to avoid public methods in @KeepForApi classes.
+ public static void setMinApiLevel(D8Command.Builder builder, UncheckedApiLevel minApiLevel) {
+ builder.setMinApiLevel(minApiLevel);
+ }
}