Add 11-char unique build ID to marker and Proguard map.
Also: don't use min_api in CF mode.
Bug: 70040153
Change-Id: Ieb8fa2db2ae0fc7047a18cf762b684d300b14068
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 466a26f..e920ad3 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -148,10 +148,12 @@
if (options.testing.dontCreateMarkerInD8) {
return null;
}
- Marker marker = new Marker(Tool.D8)
- .setVersion(Version.LABEL)
- .setCompilationMode(options.debug ? CompilationMode.DEBUG : CompilationMode.RELEASE)
- .setMinApi(options.minApiLevel);
+ Marker marker =
+ new Marker(Tool.D8)
+ .setVersion(Version.LABEL)
+ .setCompilationMode(options.debug ? CompilationMode.DEBUG : CompilationMode.RELEASE)
+ .setMinApi(options.minApiLevel)
+ .setBuildId(options.buildId);
if (Version.isDev()) {
marker.setSha1(VersionProperties.INSTANCE.getSha());
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 75b0c81..36d4cf7 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -169,10 +169,14 @@
if (options.hasMarker()) {
return options.getMarker();
}
- Marker marker = new Marker(Tool.R8)
- .setVersion(Version.LABEL)
- .setCompilationMode(options.debug ? CompilationMode.DEBUG : CompilationMode.RELEASE)
- .setMinApi(options.minApiLevel);
+ Marker marker =
+ new Marker(Tool.R8)
+ .setVersion(Version.LABEL)
+ .setCompilationMode(options.debug ? CompilationMode.DEBUG : CompilationMode.RELEASE)
+ .setBuildId(options.buildId);
+ if (!options.isGeneratingClassFiles()) {
+ marker.setMinApi(options.minApiLevel);
+ }
if (Version.isDev()) {
marker.setSha1(VersionProperties.INSTANCE.getSha());
}
@@ -629,8 +633,7 @@
namingLens,
options.lineNumberOptimization == LineNumberOptimization.OFF);
timing.end();
- proguardMapSupplier =
- ProguardMapSupplier.fromClassNameMapper(classNameMapper, options.minApiLevel);
+ proguardMapSupplier = ProguardMapSupplier.fromClassNameMapper(classNameMapper, options);
// If a method filter is present don't produce output since the application is likely partial.
if (options.hasMethodsFilter()) {
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 3d977f6..41270da 100644
--- a/src/main/java/com/android/tools/r8/dex/Marker.java
+++ b/src/main/java/com/android/tools/r8/dex/Marker.java
@@ -21,6 +21,7 @@
public static final String MIN_API = "min-api";
public static final String SHA1 = "sha-1";
public static final String COMPILATION_MODE = "compilation-mode";
+ public static final String BUILD_ID = "build-id";
public enum Tool {D8, R8}
@@ -93,6 +94,16 @@
return this;
}
+ public String getBuildId() {
+ return jsonObject.get(BUILD_ID).getAsString();
+ }
+
+ public Marker setBuildId(String uuid) {
+ assert !jsonObject.has(BUILD_ID);
+ jsonObject.addProperty(BUILD_ID, uuid);
+ return this;
+ }
+
@Override
public String toString() {
// In order to make printing of markers deterministic we sort the entries by key.
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 5ee5891..d905116 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.Version;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.VersionProperties;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -18,39 +19,38 @@
public static final String MARKER_KEY_COMPILER_VERSION = "compiler_version";
public static final String MARKER_KEY_COMPILER_HASH = "compiler_hash";
public static final String MARKER_KEY_MIN_API = "min_api";
+ public static final String MARKER_KEY_BUILD_ID = "build_id";
public static ProguardMapSupplier fromClassNameMapper(
- ClassNameMapper classNameMapper, int minApiLevel) {
- return new ProguardMapSupplier(classNameMapper, minApiLevel);
+ ClassNameMapper classNameMapper, InternalOptions options) {
+ return new ProguardMapSupplier(true, classNameMapper, null, null, options);
}
public static ProguardMapSupplier fromNamingLens(
- NamingLens namingLens, DexApplication dexApplication, int minApiLevel) {
- return new ProguardMapSupplier(namingLens, dexApplication, minApiLevel);
+ NamingLens namingLens, DexApplication dexApplication, InternalOptions options) {
+ return new ProguardMapSupplier(false, null, namingLens, dexApplication, options);
}
- private ProguardMapSupplier(ClassNameMapper classNameMapper, int minApiLevel) {
- this.useClassNameMapper = true;
+ public ProguardMapSupplier(
+ boolean useClassNameMapper,
+ ClassNameMapper classNameMapper,
+ NamingLens namingLens,
+ DexApplication application,
+ InternalOptions options) {
+ this.useClassNameMapper = useClassNameMapper;
this.classNameMapper = classNameMapper;
- this.namingLens = null;
- this.application = null;
- this.minApiLevel = minApiLevel;
- }
-
- private ProguardMapSupplier(
- NamingLens namingLens, DexApplication dexApplication, int minApiLevel) {
- this.useClassNameMapper = false;
- this.classNameMapper = null;
this.namingLens = namingLens;
- this.application = dexApplication;
- this.minApiLevel = minApiLevel;
+ this.application = application;
+ this.minApiLevel = options.isGeneratingClassFiles() ? null : options.minApiLevel;
+ this.buildId = options.buildId;
}
private final boolean useClassNameMapper;
private final ClassNameMapper classNameMapper;
private final NamingLens namingLens;
private final DexApplication application;
- private final int minApiLevel;
+ private final Integer minApiLevel;
+ private final String buildId;
public String get() {
String body = getBody();
@@ -61,23 +61,23 @@
if (Version.isDev()) {
shaLine = "# " + MARKER_KEY_COMPILER_HASH + ": " + VersionProperties.INSTANCE.getSha() + "\n";
}
- return "# "
- + MARKER_KEY_COMPILER
- + ": "
- + MARKER_VALUE_COMPILER
- + "\n"
- + "# "
- + MARKER_KEY_COMPILER_VERSION
- + ": "
- + Version.LABEL
- + "\n"
- + "# "
- + MARKER_KEY_MIN_API
- + ": "
- + minApiLevel
- + "\n"
- + shaLine
- + body;
+ StringBuilder builder = new StringBuilder();
+ builder.append(
+ "# "
+ + MARKER_KEY_COMPILER
+ + ": "
+ + MARKER_VALUE_COMPILER
+ + "\n"
+ + "# "
+ + MARKER_KEY_COMPILER_VERSION
+ + ": "
+ + Version.LABEL
+ + "\n");
+ if (minApiLevel != null) {
+ builder.append("# " + MARKER_KEY_MIN_API + ": " + minApiLevel + "\n");
+ }
+ builder.append(shaLine + "# " + MARKER_KEY_BUILD_ID + ": " + buildId + "\n" + body);
+ return builder.toString();
}
private String getBody() {
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 3997982..09f2ef7 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -28,13 +28,16 @@
import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import java.util.UUID;
import java.util.function.Consumer;
public class InternalOptions {
@@ -63,6 +66,19 @@
public final List<DataResourceProvider> dataResourceProviders = new ArrayList<>();
public DataResourceConsumer dataResourceConsumer;
+ // Generate 11-char unique random string using the UUID generator.
+ private static String generateBuildId() {
+ UUID uuid = UUID.randomUUID();
+ return Base64.getEncoder()
+ .withoutPadding()
+ .encodeToString(
+ ByteBuffer.allocate(8)
+ .putLong(uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits())
+ .array());
+ }
+
+ public final String buildId = generateBuildId();
+
// Constructor for testing and/or other utilities.
public InternalOptions() {
reporter = new Reporter();
diff --git a/src/test/java/com/android/tools/r8/ExtractMarkerTest.java b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
index 6a47607..48482f8 100644
--- a/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
@@ -4,24 +4,36 @@
package com.android.tools.r8;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.utils.InternalOptions;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Set;
import org.junit.Test;
public class ExtractMarkerTest {
+ private static final String CLASS_FILE =
+ ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+
+ private static void verifyMarker(Marker marker, Tool tool) {
+ assertEquals(tool, marker.getTool());
+ assertEquals(Version.LABEL, marker.getVersion());
+ assertEquals(CompilationMode.DEBUG.toString().toLowerCase(), marker.getCompilationMode());
+ String anotherBuildId = new InternalOptions().buildId;
+ assertNotEquals(anotherBuildId, marker.getBuildId());
+ }
@Test
public void extractMarkerTestDex() throws CompilationFailedException {
- String classFile = ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
boolean[] testExecuted = {false};
+
D8.run(
D8Command.builder()
- .addProgramFiles(Paths.get(classFile))
+ .addProgramFiles(Paths.get(CLASS_FILE))
.setProgramConsumer(
new DexIndexedConsumer.ForwardingConsumer(null) {
@Override
@@ -39,11 +51,7 @@
} catch (Exception e) {
throw new RuntimeException(e);
}
- assertEquals(Tool.D8, marker.getTool());
- assertEquals(Version.LABEL, marker.getVersion());
- assertEquals(
- CompilationMode.DEBUG.toString().toLowerCase(),
- marker.getCompilationMode());
+ verifyMarker(marker, Tool.D8);
testExecuted[0] = true;
}
})
@@ -53,11 +61,10 @@
@Test
public void extractMarkerTestCf() throws CompilationFailedException {
- String classFile = ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
boolean[] testExecuted = {false};
R8.run(
R8Command.builder()
- .addProgramFiles(Paths.get(classFile))
+ .addProgramFiles(Paths.get(CLASS_FILE))
.addLibraryFiles(ToolHelper.getJava8RuntimeJar())
.setMode(CompilationMode.DEBUG)
.setDisableTreeShaking(true)
@@ -75,11 +82,7 @@
} catch (Exception e) {
throw new RuntimeException(e);
}
- assertEquals(Tool.R8, marker.getTool());
- assertEquals(Version.LABEL, marker.getVersion());
- assertEquals(
- CompilationMode.DEBUG.toString().toLowerCase(),
- marker.getCompilationMode());
+ verifyMarker(marker, Tool.R8);
testExecuted[0] = true;
}
})
diff --git a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
index 6310054..a3dedd9 100644
--- a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
@@ -6,55 +6,125 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.VersionProperties;
import java.nio.file.Paths;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
public class ProguardMapMarkerTest {
+ private static final int EXPECTED_NUMBER_OF_KEYS_DEX = 5;
+ private static final int EXPECTED_NUMBER_OF_KEYS_CF = 4;
+ private static final String CLASS_FILE =
+ ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+
@Test
public void proguardMapMarkerTest24() throws CompilationFailedException {
- proguardMapMarkerTest(AndroidApiLevel.N);
+ proguardMapMarkerTestDex(AndroidApiLevel.N);
}
@Test
public void proguardMapMarkerTest26() throws CompilationFailedException {
- proguardMapMarkerTest(AndroidApiLevel.O);
+ proguardMapMarkerTestDex(AndroidApiLevel.O);
}
- private void proguardMapMarkerTest(AndroidApiLevel minApiLevel) throws CompilationFailedException {
- String classFile = ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+ private static class BuildIds {
+ String fromProgram = null;
+ String fromMap = null;
+ }
+
+ private void proguardMapMarkerTestDex(AndroidApiLevel minApiLevel)
+ throws CompilationFailedException {
+ BuildIds buildIds = new BuildIds();
R8.run(
R8Command.builder()
- .addProgramFiles(Paths.get(classFile))
+ .addProgramFiles(Paths.get(CLASS_FILE))
+ .setDisableTreeShaking(true)
.setProgramConsumer(
- new DexIndexedConsumer() {
+ new DexIndexedConsumer.ForwardingConsumer(null) {
@Override
public void accept(
int fileIndex,
ByteDataView data,
Set<String> descriptors,
- DiagnosticsHandler handler) {}
-
- @Override
- public void finished(DiagnosticsHandler handler) {}
+ DiagnosticsHandler handler) {
+ Marker marker;
+ try {
+ Collection<Marker> markers =
+ ExtractMarker.extractMarkerFromDexProgramData(data.copyByteData());
+ assertEquals(1, markers.size());
+ marker = markers.iterator().next();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ buildIds.fromProgram = marker.getBuildId();
+ }
})
.addLibraryFiles(ToolHelper.getAndroidJar(minApiLevel))
.setMinApiLevel(minApiLevel.getLevel())
.setProguardMapConsumer(
(proguardMap, handler) -> {
- verifyMarkers(proguardMap, minApiLevel.getLevel());
+ buildIds.fromMap =
+ verifyMarkersGetBuildId(
+ proguardMap, minApiLevel.getLevel(), EXPECTED_NUMBER_OF_KEYS_DEX);
})
.build());
+ verifyBuildIds(buildIds);
}
- private static void verifyMarkers(String proguardMap, int minApiLevel) {
+ private void verifyBuildIds(BuildIds buildIds) {
+ assertTrue(buildIds.fromProgram != null && buildIds.fromProgram.length() > 0);
+ assertTrue(buildIds.fromMap != null && buildIds.fromMap.length() > 0);
+ assertEquals(buildIds.fromMap, buildIds.fromProgram);
+ }
+
+ @Test
+ public void proguardMapMarkerTestCf() throws CompilationFailedException {
+ BuildIds buildIds = new BuildIds();
+ R8.run(
+ R8Command.builder()
+ .addProgramFiles(Paths.get(CLASS_FILE))
+ .setDisableTreeShaking(true)
+ .setProgramConsumer(
+ new ClassFileConsumer.ForwardingConsumer(null) {
+ @Override
+ public void accept(
+ ByteDataView data, String descriptor, DiagnosticsHandler handler) {
+ Marker marker;
+ try {
+ Collection<Marker> markers =
+ ExtractMarker.extractMarkerFromClassProgramData(data.copyByteData());
+ assertEquals(1, markers.size());
+ marker = markers.iterator().next();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ buildIds.fromProgram = marker.getBuildId();
+ }
+ })
+ .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .setProguardMapConsumer(
+ (proguardMap, handler) -> {
+ buildIds.fromMap =
+ verifyMarkersGetBuildId(proguardMap, null, EXPECTED_NUMBER_OF_KEYS_CF);
+ })
+ .build());
+ verifyBuildIds(buildIds);
+ }
+
+ private static String verifyMarkersGetBuildId(
+ String proguardMap, Integer minApiLevel, int expectedNumberOfKeys) {
String[] lines = proguardMap.split("\n");
Set<String> keysFound = new HashSet<>();
+ String buildId = null;
for (String line : lines) {
if (!line.startsWith("#")) {
continue;
@@ -71,14 +141,20 @@
} else if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER_VERSION)) {
assertEquals(Version.LABEL, value);
} else if (key.equals(ProguardMapSupplier.MARKER_KEY_MIN_API)) {
- assertEquals(minApiLevel, Integer.parseInt(value));
+ assertNotNull(minApiLevel);
+ assertEquals(minApiLevel.intValue(), Integer.parseInt(value));
} else if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER_HASH)) {
assertEquals(VersionProperties.INSTANCE.getSha(), value);
+ } else if (key.equals(ProguardMapSupplier.MARKER_KEY_BUILD_ID)) {
+ assertNull(buildId);
+ buildId = value;
} else {
continue;
}
assertFalse(keysFound.contains(key));
keysFound.add(key);
}
+ assertEquals(expectedNumberOfKeys, keysFound.size());
+ return buildId;
}
}