Update usage of D8 API in DexFileMerger.
PiperOrigin-RevId: 553539967
Change-Id: I5509d3e6752819ebf7d8cbc8979cf315ec2673a6
diff --git a/src/tools/android/java/com/google/devtools/build/android/r8/DexFileMerger.java b/src/tools/android/java/com/google/devtools/build/android/r8/DexFileMerger.java
index 82f4ba2..4b9abbd 100644
--- a/src/tools/android/java/com/google/devtools/build/android/r8/DexFileMerger.java
+++ b/src/tools/android/java/com/google/devtools/build/android/r8/DexFileMerger.java
@@ -36,11 +36,11 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.reflect.Method;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -68,6 +68,8 @@
private static final boolean PRINT_ARGS = false;
+ private static final int NATIVE_MULTIDEX_API_LEVEL = 21;
+
/** Strategies for outputting multiple {@code .dex} files supported by {@link DexFileMerger}. */
public enum MultidexStrategy {
/** Create exactly one .dex file. The operation will fail if .dex limits are exceeded. */
@@ -296,6 +298,17 @@
return shard;
}
+ private static int getInputNumber(
+ Origin origin, Map<String, Integer> inputOrdering, DiagnosticsHandler handler) {
+ Integer number = inputOrdering.get(origin.parent().part());
+ if (number == null) {
+ String message = "Class parent path not found among input paths: " + origin;
+ handler.error(new StringDiagnostic(message, origin));
+ throw new IllegalStateException(message);
+ }
+ return number;
+ }
+
public static void run(String[] args) throws CompilationFailedException, IOException {
Options options = parseArguments(args);
@@ -318,13 +331,39 @@
D8Command.Builder builder = D8Command.builder();
+ // If multidex is enabled but no main-dex list given then the build must be targeting
+ // devices with native multidex support.
+ if (options.multidexMode.isMultidexAllowed() && options.mainDexListFile == null) {
+ builder.setMinApiLevel(NATIVE_MULTIDEX_API_LEVEL);
+ }
+
+ // The merge step assumes that no further desugaring is needed.
+ builder = builder.setDisableDesugaring(true);
+
+ // D8 does not allow duplicate classes. Resolve conflicts based on input order.
Map<String, Integer> inputOrdering =
Maps.newHashMapWithExpectedSize(options.inputArchives.size());
int sequenceNumber = 0;
for (Path s : options.inputArchives) {
- builder.addProgramFiles(s);
+ builder = builder.addProgramFiles(s);
inputOrdering.put(s.toString(), sequenceNumber++);
}
+ builder =
+ builder.setClassConflictResolver(
+ (reference, origins, handler) -> {
+ Iterator<Origin> it = origins.iterator();
+ Origin first = it.next();
+ int firstNumber = getInputNumber(first, inputOrdering, handler);
+ while (it.hasNext()) {
+ Origin next = it.next();
+ int nextNumber = getInputNumber(next, inputOrdering, handler);
+ if (firstNumber > nextNumber) {
+ first = next;
+ firstNumber = nextNumber;
+ }
+ }
+ return first;
+ });
// Determine enabling multidexing and file indexing.
Integer singleFixedFileIndex = null;
@@ -345,31 +384,15 @@
break;
}
- if (options.mainDexListFile != null) {
- builder.addMainDexListFiles(options.mainDexListFile);
+ if (builder.getMinApiLevel() < NATIVE_MULTIDEX_API_LEVEL && options.mainDexListFile != null) {
+ builder = builder.addMainDexListFiles(options.mainDexListFile);
}
ArchiveConsumer consumer =
new ArchiveConsumer(options.outputArchive, options.dexPrefix, singleFixedFileIndex);
- builder.setProgramConsumer(consumer);
+ builder = builder.setProgramConsumer(consumer);
- // Try to run through com.android.tools.r8.DexFileMergerHelper.run. If not found, which
- // can happen when bazel use a d8.jar from a Platform SDK, fall back to plain D8 execution.
- try {
- Class<?> dexFileMergerHelper = Class.forName("com.android.tools.r8.DexFileMergerHelper");
- try {
- Method run =
- dexFileMergerHelper.getDeclaredMethod("run", D8Command.class, Boolean.class, Map.class);
- // DexFileMergerHelper.run(builder.build(), false, inputOrdering);
- run.invoke(null, builder.build(), false, inputOrdering);
- } catch (NoSuchMethodException e) {
- D8.run(builder.build());
- } catch (ReflectiveOperationException e) {
- throw new AssertionError("Unable to invoke run in DexFileMergerHelper", e);
- }
- } catch (ClassNotFoundException e) {
- D8.run(builder.build());
- }
+ D8.run(builder.build());
// If input was empty we still need to write out an empty zip.
if (!consumer.hasWrittenSomething()) {