Change internal consumer of proguardmap to ProguardMapConsumer
We would use StringConsumer before but that is not compatible with partitioned output.
Change-Id: Id78ed07b0e06b4ff74d0fbac7f2e0cef60c445f8
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index d1495c2..1abfbd2 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileForRewriting;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
@@ -665,7 +666,13 @@
internal.setSyntheticInfoConsumer(syntheticInfoConsumer);
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
- internal.proguardMapConsumer = proguardMapConsumer;
+ internal.proguardMapConsumer =
+ proguardMapConsumer == null
+ ? null
+ : ProguardMapStringConsumer.builder()
+ .setStringConsumer(proguardMapConsumer)
+ .setDiagnosticsHandler(getReporter())
+ .build();
internal.lineNumberOptimization =
!internal.debug && proguardMapConsumer != null
? LineNumberOptimization.ON
diff --git a/src/main/java/com/android/tools/r8/Finishable.java b/src/main/java/com/android/tools/r8/Finishable.java
new file mode 100644
index 0000000..2e114ef
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/Finishable.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2023, 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;
+
+public interface Finishable {
+
+ /**
+ * Callback when no further content will be provided for the resource.
+ *
+ * <p>The consumer is expected not to throw, but instead report any errors via the diagnostics
+ * {@param handler}. If an error is reported via {@param handler} and no exceptions are thrown,
+ * then the compiler guaranties to exit with an error.
+ *
+ * @param handler Diagnostics handler for reporting.
+ */
+ default void finished(DiagnosticsHandler handler) {}
+}
diff --git a/src/main/java/com/android/tools/r8/ProguardMapConsumer.java b/src/main/java/com/android/tools/r8/ProguardMapConsumer.java
new file mode 100644
index 0000000..f00b428
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ProguardMapConsumer.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2023, 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;
+
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.ProguardMapMarkerInfo;
+
+public abstract class ProguardMapConsumer implements Finishable {
+
+ public abstract void accept(ProguardMapMarkerInfo makerInfo, ClassNameMapper classNameMapper);
+}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 6118b88..5fc02c3 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor;
+import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.naming.SourceFileRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
@@ -1065,11 +1066,18 @@
}
// Amend the proguard-map consumer with options from the proguard configuration.
- internal.proguardMapConsumer =
+ StringConsumer stringConsumer =
wrapStringConsumer(
proguardMapConsumer,
proguardConfiguration.isPrintMapping(),
proguardConfiguration.getPrintMappingFile());
+ internal.proguardMapConsumer =
+ stringConsumer == null
+ ? null
+ : ProguardMapStringConsumer.builder()
+ .setStringConsumer(stringConsumer)
+ .setDiagnosticsHandler(getReporter())
+ .build();
// Amend the usage information consumer with options from the proguard configuration.
internal.usageInformationConsumer =
diff --git a/src/main/java/com/android/tools/r8/StringConsumer.java b/src/main/java/com/android/tools/r8/StringConsumer.java
index d0e05cc..2583572 100644
--- a/src/main/java/com/android/tools/r8/StringConsumer.java
+++ b/src/main/java/com/android/tools/r8/StringConsumer.java
@@ -15,7 +15,7 @@
/** Interface for receiving String resource. */
@KeepForSubclassing
-public interface StringConsumer {
+public interface StringConsumer extends Finishable {
/**
* Callback to receive part of a string resource.
@@ -32,17 +32,6 @@
*/
void accept(String string, DiagnosticsHandler handler);
- /**
- * Callback when no further content will be provided for the string resource.
- *
- * <p>The consumer is expected not to throw, but instead report any errors via the diagnostics
- * {@param handler}. If an error is reported via {@param handler} and no exceptions are thrown,
- * then the compiler guaranties to exit with an error.
- *
- * @param handler Diagnostics handler for reporting.
- */
- default void finished(DiagnosticsHandler handler) {}
-
static EmptyConsumer emptyConsumer() {
return EmptyConsumer.EMPTY_CONSUMER;
}
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 8a196d9..caa1c27 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.ProgramConsumer;
-import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.ProguardMapConsumer;
import com.android.tools.r8.bisect.BisectOptions.Result;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
@@ -182,9 +182,9 @@
private static void writeApp(DexApplication app, Path output, ExecutorService executor)
throws IOException, ExecutionException {
InternalOptions options = app.options;
- // Save the original consumers so they can be unwrapped after write.
+ // Save the original consumers, so they can be unwrapped after write.
ProgramConsumer programConsumer = options.programConsumer;
- StringConsumer proguardMapConsumer = options.proguardMapConsumer;
+ ProguardMapConsumer proguardMapConsumer = options.proguardMapConsumer;
AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
ApplicationWriter writer =
ApplicationWriter.create(
diff --git a/src/main/java/com/android/tools/r8/naming/MultiProguardMapConsumer.java b/src/main/java/com/android/tools/r8/naming/MultiProguardMapConsumer.java
new file mode 100644
index 0000000..5901fd3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/MultiProguardMapConsumer.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2023, 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.naming;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.ProguardMapConsumer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultiProguardMapConsumer extends ProguardMapConsumer {
+
+ private final List<ProguardMapConsumer> proguardMapConsumers;
+
+ public MultiProguardMapConsumer(List<ProguardMapConsumer> proguardMapConsumers) {
+ this.proguardMapConsumers = proguardMapConsumers;
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ proguardMapConsumers.forEach(consumer -> consumer.finished(handler));
+ }
+
+ @Override
+ public void accept(ProguardMapMarkerInfo markerInfo, ClassNameMapper classNameMapper) {
+ proguardMapConsumers.forEach(consumer -> consumer.accept(markerInfo, classNameMapper));
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private final List<ProguardMapConsumer> proguardMapConsumers = new ArrayList<>();
+
+ public Builder addProguardMapConsumer(ProguardMapConsumer consumer) {
+ proguardMapConsumers.add(consumer);
+ return this;
+ }
+
+ public MultiProguardMapConsumer build() {
+ return new MultiProguardMapConsumer(proguardMapConsumers);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapChecker.java b/src/main/java/com/android/tools/r8/naming/ProguardMapChecker.java
new file mode 100644
index 0000000..be80509
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapChecker.java
@@ -0,0 +1,129 @@
+// Copyright (c) 2023, 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.naming;
+
+import static com.android.tools.r8.naming.ProguardMapMarkerInfo.MARKER_KEY_PG_MAP_HASH;
+import static com.android.tools.r8.naming.ProguardMapMarkerInfo.SHA_256_KEY;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+public class ProguardMapChecker implements StringConsumer {
+
+ private final StringConsumer inner;
+ private final StringBuilder contents = new StringBuilder();
+
+ ProguardMapChecker(StringConsumer inner) {
+ if (!InternalOptions.assertionsEnabled()) {
+ // Make sure we never get here without assertions enabled.
+ throw new Unreachable();
+ }
+ this.inner = inner;
+ }
+
+ @Override
+ public void accept(String string, DiagnosticsHandler handler) {
+ inner.accept(string, handler);
+ contents.append(string);
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ inner.finished(handler);
+ String stringContent = contents.toString();
+ assert validateProguardMapParses(stringContent);
+ assert validateProguardMapHash(stringContent).isOk();
+ }
+
+ private static boolean validateProguardMapParses(String content) {
+ try {
+ ClassNameMapper.mapperFromString(content);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public static class VerifyMappingFileHashResult {
+
+ private final boolean error;
+ private final String message;
+
+ public static VerifyMappingFileHashResult createOk() {
+ return new VerifyMappingFileHashResult(false, null);
+ }
+
+ public static VerifyMappingFileHashResult createInfo(String message) {
+ return new VerifyMappingFileHashResult(false, message);
+ }
+
+ public static VerifyMappingFileHashResult createError(String message) {
+ return new VerifyMappingFileHashResult(true, message);
+ }
+
+ private VerifyMappingFileHashResult(boolean error, String message) {
+ this.error = error;
+ this.message = message;
+ }
+
+ public boolean isOk() {
+ return !error && message == null;
+ }
+
+ public boolean isError() {
+ return error;
+ }
+
+ public String getMessage() {
+ assert message != null;
+ return message;
+ }
+ }
+
+ public static VerifyMappingFileHashResult validateProguardMapHash(String content) {
+ int lineEnd = -1;
+ while (true) {
+ int lineStart = lineEnd + 1;
+ lineEnd = content.indexOf('\n', lineStart);
+ if (lineEnd < 0) {
+ return VerifyMappingFileHashResult.createInfo("Failure to find map hash");
+ }
+ String line = content.substring(lineStart, lineEnd).trim();
+ if (line.isEmpty()) {
+ // Ignore empty lines in the header.
+ continue;
+ }
+ if (line.charAt(0) != '#') {
+ // At the first non-empty non-comment line we assume that the file has no hash marker.
+ return VerifyMappingFileHashResult.createInfo("Failure to find map hash in header");
+ }
+ String headerLine = line.substring(1).trim();
+ if (headerLine.startsWith(MARKER_KEY_PG_MAP_HASH)) {
+ int shaIndex = headerLine.indexOf(SHA_256_KEY + " ", MARKER_KEY_PG_MAP_HASH.length());
+ if (shaIndex < 0) {
+ return VerifyMappingFileHashResult.createError(
+ "Unknown map hash function: '" + headerLine + "'");
+ }
+ String headerHash = headerLine.substring(shaIndex + SHA_256_KEY.length()).trim();
+ // We are on the hash line. Everything past this line is the hashed content.
+ Hasher hasher = Hashing.sha256().newHasher();
+ String hashedContent = content.substring(lineEnd + 1);
+ hasher.putString(hashedContent, StandardCharsets.UTF_8);
+ String computedHash = hasher.hash().toString();
+ return headerHash.equals(computedHash)
+ ? VerifyMappingFileHashResult.createOk()
+ : VerifyMappingFileHashResult.createError(
+ "Mismatching map hash: '" + headerHash + "' != '" + computedHash + "'");
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMarkerInfo.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMarkerInfo.java
new file mode 100644
index 0000000..8394ecf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMarkerInfo.java
@@ -0,0 +1,112 @@
+// Copyright (c) 2023, 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.naming;
+
+import com.android.tools.r8.Version;
+import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.VersionProperties;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ProguardMapMarkerInfo {
+
+ private static final String MARKER_KEY_COMPILER = "compiler";
+ private static final String MARKER_KEY_COMPILER_VERSION = "compiler_version";
+ private static final String MARKER_KEY_COMPILER_HASH = "compiler_hash";
+ private static final String MARKER_KEY_MIN_API = "min_api";
+ private static final String MARKER_KEY_PG_MAP_ID = "pg_map_id";
+ public static final String MARKER_KEY_PG_MAP_HASH = "pg_map_hash";
+ public static final String SHA_256_KEY = "SHA-256";
+
+ private final String compilerName;
+ private final boolean isGeneratingDex;
+ private final AndroidApiLevel apiLevel;
+ private final MapVersion mapVersion;
+ private final ProguardMapId proguardMapId;
+
+ private ProguardMapMarkerInfo(
+ String compilerName,
+ boolean isGeneratingDex,
+ AndroidApiLevel apiLevel,
+ MapVersion mapVersion,
+ ProguardMapId proguardMapId) {
+ this.compilerName = compilerName;
+ this.isGeneratingDex = isGeneratingDex;
+ this.apiLevel = apiLevel;
+ this.mapVersion = mapVersion;
+ this.proguardMapId = proguardMapId;
+ }
+
+ public List<String> toPreamble() {
+ List<String> preamble = new ArrayList<>();
+ preamble.add("# " + MARKER_KEY_COMPILER + ": " + compilerName);
+ preamble.add("# " + MARKER_KEY_COMPILER_VERSION + ": " + Version.LABEL);
+ if (isGeneratingDex) {
+ preamble.add("# " + MARKER_KEY_MIN_API + ": " + apiLevel.getLevel());
+ }
+ if (Version.isDevelopmentVersion()) {
+ preamble.add("# " + MARKER_KEY_COMPILER_HASH + ": " + VersionProperties.INSTANCE.getSha());
+ }
+ // Turn off linting of the mapping file in some build systems.
+ preamble.add("# common_typos_disable");
+ // Emit the R8 specific map-file version.
+ if (mapVersion.isGreaterThan(MapVersion.MAP_VERSION_NONE)) {
+ preamble.add("# " + mapVersion.toMapVersionMappingInformation().serialize());
+ }
+ preamble.add("# " + MARKER_KEY_PG_MAP_ID + ": " + proguardMapId.getId());
+ preamble.add(
+ "# " + MARKER_KEY_PG_MAP_HASH + ": " + SHA_256_KEY + " " + proguardMapId.getHash());
+ return preamble;
+ }
+
+ public String serializeToString() {
+ return StringUtils.unixLines(toPreamble());
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String compilerName;
+ private boolean isGeneratingDex;
+ private AndroidApiLevel apiLevel;
+ private MapVersion mapVersion;
+ private ProguardMapId proguardMapId;
+
+ public Builder setCompilerName(String compilerName) {
+ this.compilerName = compilerName;
+ return this;
+ }
+
+ public Builder setApiLevel(AndroidApiLevel apiLevel) {
+ this.apiLevel = apiLevel;
+ return this;
+ }
+
+ public Builder setGeneratingDex(boolean generatingDex) {
+ isGeneratingDex = generatingDex;
+ return this;
+ }
+
+ public Builder setMapVersion(MapVersion mapVersion) {
+ this.mapVersion = mapVersion;
+ return this;
+ }
+
+ public Builder setProguardMapId(ProguardMapId proguardMapId) {
+ this.proguardMapId = proguardMapId;
+ return this;
+ }
+
+ public ProguardMapMarkerInfo build() {
+ return new ProguardMapMarkerInfo(
+ compilerName, isGeneratingDex, apiLevel, mapVersion, proguardMapId);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java b/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java
new file mode 100644
index 0000000..95bbd38
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapStringConsumer.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2023, 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.naming;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.ProguardMapConsumer;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.utils.ChainableStringConsumer;
+
+/***
+ * Default implementation of a ProguardMapConsumer that wraps around a string consumer for streamed
+ * string output.
+ */
+public class ProguardMapStringConsumer extends ProguardMapConsumer
+ implements ChainableStringConsumer {
+
+ private final StringConsumer stringConsumer;
+ private final DiagnosticsHandler diagnosticsHandler;
+
+ private ProguardMapStringConsumer(
+ StringConsumer stringConsumer, DiagnosticsHandler diagnosticsHandler) {
+ assert stringConsumer != null;
+ assert diagnosticsHandler != null;
+ this.stringConsumer = stringConsumer;
+ this.diagnosticsHandler = diagnosticsHandler;
+ }
+
+ @Override
+ public void accept(ProguardMapMarkerInfo markerInfo, ClassNameMapper classNameMapper) {
+ accept(markerInfo.serializeToString());
+ classNameMapper.write(this);
+ }
+
+ @Override
+ public ChainableStringConsumer accept(String string) {
+ stringConsumer.accept(string, diagnosticsHandler);
+ return this;
+ }
+
+ public StringConsumer getStringConsumer() {
+ return stringConsumer;
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ stringConsumer.finished(handler);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private StringConsumer stringConsumer;
+ private DiagnosticsHandler diagnosticsHandler;
+
+ public Builder setStringConsumer(StringConsumer stringConsumer) {
+ this.stringConsumer = stringConsumer;
+ return this;
+ }
+
+ public Builder setDiagnosticsHandler(DiagnosticsHandler diagnosticsHandler) {
+ this.diagnosticsHandler = diagnosticsHandler;
+ return this;
+ }
+
+ public ProguardMapStringConsumer build() {
+ return new ProguardMapStringConsumer(stringConsumer, diagnosticsHandler);
+ }
+ }
+}
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 a7f62dd..c3fc071 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -3,33 +3,20 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.MapIdEnvironment;
import com.android.tools.r8.MapIdProvider;
-import com.android.tools.r8.StringConsumer;
-import com.android.tools.r8.Version;
+import com.android.tools.r8.ProguardMapConsumer;
import com.android.tools.r8.dex.Marker.Tool;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.ChainableStringConsumer;
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.VersionProperties;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class ProguardMapSupplier {
- public static final String MARKER_KEY_COMPILER = "compiler";
- 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_PG_MAP_ID = "pg_map_id";
- public static final String MARKER_KEY_PG_MAP_HASH = "pg_map_hash";
- public static final String SHA_256_KEY = "SHA-256";
-
public static int PG_MAP_ID_LENGTH = 7;
// Hash of the Proguard map (excluding the header up to and including the hash marker).
@@ -56,8 +43,8 @@
}
private final ClassNameMapper classNameMapper;
- private final StringConsumer consumer;
private final InternalOptions options;
+ private final ProguardMapConsumer consumer;
private final Reporter reporter;
private final Tool compiler;
@@ -79,11 +66,18 @@
}
public ProguardMapId writeProguardMap() {
- ProguardMapId id = computeProguardMapId();
- writeMarker(id);
- writeBody();
- ExceptionUtils.withFinishedResourceHandler(reporter, consumer);
- return id;
+ ProguardMapId proguardMapId = computeProguardMapId();
+ consumer.accept(
+ ProguardMapMarkerInfo.builder()
+ .setCompilerName(compiler.name())
+ .setProguardMapId(proguardMapId)
+ .setGeneratingDex(options.isGeneratingDex())
+ .setApiLevel(options.getMinApiLevel())
+ .setMapVersion(options.getMapFileVersion())
+ .build(),
+ classNameMapper);
+ ExceptionUtils.withConsumeResourceHandler(reporter, this.consumer::finished);
+ return proguardMapId;
}
private ProguardMapId computeProguardMapId() {
@@ -92,52 +86,6 @@
return builder.build(options.mapIdProvider);
}
- private void writeBody() {
- classNameMapper.write(new ProguardMapWriter());
- }
-
- private void writeMarker(ProguardMapId id) {
- StringBuilder builder = new StringBuilder();
- builder.append(
- "# "
- + MARKER_KEY_COMPILER
- + ": "
- + compiler.name()
- + "\n"
- + "# "
- + MARKER_KEY_COMPILER_VERSION
- + ": "
- + Version.LABEL
- + "\n");
- if (options.isGeneratingDex()) {
- builder.append("# " + MARKER_KEY_MIN_API + ": " + options.getMinApiLevel().getLevel() + "\n");
- }
- if (Version.isDevelopmentVersion()) {
- builder.append(
- "# " + MARKER_KEY_COMPILER_HASH + ": " + VersionProperties.INSTANCE.getSha() + "\n");
- }
- // Turn off linting of the mapping file in some build systems.
- builder.append("# common_typos_disable" + "\n");
- // Emit the R8 specific map-file version.
- MapVersion mapVersion = options.getMapFileVersion();
- if (mapVersion.isGreaterThan(MapVersion.MAP_VERSION_NONE)) {
- builder
- .append("# ")
- .append(mapVersion.toMapVersionMappingInformation().serialize())
- .append("\n");
- }
- builder.append("# " + MARKER_KEY_PG_MAP_ID + ": " + id.getId() + "\n");
- // Place the map hash as the last header item. Everything past this line is the hashed content.
- builder
- .append("# ")
- .append(MARKER_KEY_PG_MAP_HASH)
- .append(": ")
- .append(SHA_256_KEY)
- .append(" ")
- .append(id.getHash())
- .append("\n");
- consumer.accept(builder.toString(), reporter);
- }
static class ProguardMapIdBuilder implements ChainableStringConsumer {
@@ -171,123 +119,4 @@
}
}
- class ProguardMapWriter implements ChainableStringConsumer {
-
- @Override
- public ProguardMapWriter accept(String string) {
- consumer.accept(string, reporter);
- return this;
- }
- }
-
- public static class ProguardMapChecker implements StringConsumer {
-
- private final StringConsumer inner;
- private final StringBuilder contents = new StringBuilder();
-
- ProguardMapChecker(StringConsumer inner) {
- if (!InternalOptions.assertionsEnabled()) {
- // Make sure we never get here without assertions enabled.
- throw new Unreachable();
- }
- this.inner = inner;
- }
-
- @Override
- public void accept(String string, DiagnosticsHandler handler) {
- inner.accept(string, handler);
- contents.append(string);
- }
-
- @Override
- public void finished(DiagnosticsHandler handler) {
- inner.finished(handler);
- String stringContent = contents.toString();
- assert validateProguardMapParses(stringContent);
- assert validateProguardMapHash(stringContent).isOk();
- }
-
- private static boolean validateProguardMapParses(String content) {
- try {
- ClassNameMapper.mapperFromString(content);
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- public static class VerifyMappingFileHashResult {
- private final boolean error;
- private final String message;
-
- public static VerifyMappingFileHashResult createOk() {
- return new VerifyMappingFileHashResult(false, null);
- }
-
- public static VerifyMappingFileHashResult createInfo(String message) {
- return new VerifyMappingFileHashResult(false, message);
- }
-
- public static VerifyMappingFileHashResult createError(String message) {
- return new VerifyMappingFileHashResult(true, message);
- }
-
- private VerifyMappingFileHashResult(boolean error, String message) {
- this.error = error;
- this.message = message;
- }
-
- public boolean isOk() {
- return !error && message == null;
- }
-
- public boolean isError() {
- return error;
- }
-
- public String getMessage() {
- assert message != null;
- return message;
- }
- }
-
- public static VerifyMappingFileHashResult validateProguardMapHash(String content) {
- int lineEnd = -1;
- while (true) {
- int lineStart = lineEnd + 1;
- lineEnd = content.indexOf('\n', lineStart);
- if (lineEnd < 0) {
- return VerifyMappingFileHashResult.createInfo("Failure to find map hash");
- }
- String line = content.substring(lineStart, lineEnd).trim();
- if (line.isEmpty()) {
- // Ignore empty lines in the header.
- continue;
- }
- if (line.charAt(0) != '#') {
- // At the first non-empty non-comment line we assume that the file has no hash marker.
- return VerifyMappingFileHashResult.createInfo("Failure to find map hash in header");
- }
- String headerLine = line.substring(1).trim();
- if (headerLine.startsWith(MARKER_KEY_PG_MAP_HASH)) {
- int shaIndex = headerLine.indexOf(SHA_256_KEY + " ", MARKER_KEY_PG_MAP_HASH.length());
- if (shaIndex < 0) {
- return VerifyMappingFileHashResult.createError(
- "Unknown map hash function: '" + headerLine + "'");
- }
- String headerHash = headerLine.substring(shaIndex + SHA_256_KEY.length()).trim();
- // We are on the hash line. Everything past this line is the hashed content.
- Hasher hasher = Hashing.sha256().newHasher();
- String hashedContent = content.substring(lineEnd + 1);
- hasher.putString(hashedContent, StandardCharsets.UTF_8);
- String computedHash = hasher.hash().toString();
- return headerHash.equals(computedHash)
- ? VerifyMappingFileHashResult.createOk()
- : VerifyMappingFileHashResult.createError(
- "Mismatching map hash: '" + headerHash + "' != '" + computedHash + "'");
- }
- }
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
index ec9449a..8c8ee27 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/MappingPartitionMetadataInternal.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.naming.MapVersion;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.retrace.MappingPartitionMetadata;
-import com.android.tools.r8.retrace.RetracePartitionException;
import com.android.tools.r8.retrace.internal.MetadataPartitionCollection.LazyMetadataPartitionCollection;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.google.common.primitives.Ints;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
index 98ac266..0298816 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.retrace.ProguardMapPartitioner;
import com.android.tools.r8.retrace.ProguardMapPartitionerBuilder;
import com.android.tools.r8.retrace.ProguardMapProducer;
-import com.android.tools.r8.retrace.RetracePartitionException;
import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal.ObfuscatedTypeNameAsKeyMetadata;
import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal.ObfuscatedTypeNameAsKeyMetadataWithPartitionNames;
import com.android.tools.r8.retrace.internal.ProguardMapReaderWithFiltering.ProguardMapReaderWithFilteringInputBuffer;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
index 14f41ed..d791a5c 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMappingSupplierImpl.java
@@ -8,8 +8,8 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.LineReader;
import com.android.tools.r8.naming.MapVersion;
-import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker;
-import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker.VerifyMappingFileHashResult;
+import com.android.tools.r8.naming.ProguardMapChecker;
+import com.android.tools.r8.naming.ProguardMapChecker.VerifyMappingFileHashResult;
import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.retrace.InvalidMappingFileException;
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracePartitionException.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
similarity index 89%
rename from src/main/java/com/android/tools/r8/retrace/RetracePartitionException.java
rename to src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
index 7751302..dd183f2 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracePartitionException.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracePartitionException.java
@@ -2,7 +2,7 @@
// 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.retrace;
+package com.android.tools.r8.retrace.internal;
import com.android.tools.r8.Keep;
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
index 7a77e25..653e567 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
@@ -14,8 +14,11 @@
import com.android.tools.r8.DexIndexedConsumer.ForwardingConsumer;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.ProguardMapConsumer;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.naming.MultiProguardMapConsumer;
+import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.origin.Origin;
import com.google.common.io.ByteStreams;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
@@ -33,7 +36,7 @@
private boolean closed = false;
private ProgramConsumer programConsumer = null;
- private StringConsumer proguardMapConsumer = null;
+ private ProguardMapConsumer proguardMapConsumer = null;
public AndroidAppConsumers() {
// Nothing to do.
@@ -45,7 +48,8 @@
public AndroidAppConsumers(InternalOptions options) {
options.programConsumer = wrapProgramConsumer(options.programConsumer);
- options.proguardMapConsumer = wrapProguardMapConsumer(options.proguardMapConsumer);
+ options.proguardMapConsumer =
+ wrapProguardMapConsumer(options.proguardMapConsumer, options.reporter);
}
public ProgramConsumer wrapProgramConsumer(ProgramConsumer consumer) {
@@ -65,30 +69,37 @@
return programConsumer;
}
- public StringConsumer wrapProguardMapConsumer(StringConsumer consumer) {
+ public ProguardMapConsumer wrapProguardMapConsumer(
+ ProguardMapConsumer consumer, DiagnosticsHandler diagnosticsHandler) {
assert proguardMapConsumer == null;
if (consumer != null) {
proguardMapConsumer =
- new StringConsumer.ForwardingConsumer(consumer) {
- StringBuilder stringBuilder = null;
+ MultiProguardMapConsumer.builder()
+ .addProguardMapConsumer(consumer)
+ .addProguardMapConsumer(
+ ProguardMapStringConsumer.builder()
+ .setStringConsumer(
+ new StringConsumer() {
+ StringBuilder stringBuilder = null;
- @Override
- public void accept(String string, DiagnosticsHandler handler) {
- super.accept(string, handler);
- if (stringBuilder == null) {
- stringBuilder = new StringBuilder();
- }
- stringBuilder.append(string);
- }
+ @Override
+ public void accept(String string, DiagnosticsHandler handler) {
+ if (stringBuilder == null) {
+ stringBuilder = new StringBuilder();
+ }
+ stringBuilder.append(string);
+ }
- @Override
- public void finished(DiagnosticsHandler handler) {
- super.finished(handler);
- if (stringBuilder != null) {
- builder.setProguardMapOutputData(stringBuilder.toString());
- }
- }
- };
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ if (stringBuilder != null) {
+ builder.setProguardMapOutputData(stringBuilder.toString());
+ }
+ }
+ })
+ .setDiagnosticsHandler(diagnosticsHandler)
+ .build())
+ .build();
}
return proguardMapConsumer;
}
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 3a51f8b..6c09eb1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.GlobalSyntheticsConsumer;
import com.android.tools.r8.MapIdProvider;
import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.ProguardMapConsumer;
import com.android.tools.r8.SourceFileProvider;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.SyntheticInfoConsumer;
@@ -1025,7 +1026,7 @@
// If null, no proguard map needs to be computed.
// If non null it must be and passed to the consumer.
- public StringConsumer proguardMapConsumer = null;
+ public ProguardMapConsumer proguardMapConsumer = null;
// If null, no usage information needs to be computed.
// If non-null, it must be and is passed to the consumer.
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index a561718..9885ab6 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -248,7 +248,11 @@
}
public static String unixLines(String... lines) {
- return lines(Arrays.asList(lines), "\n");
+ return unixLines(Arrays.asList(lines));
+ }
+
+ public static String unixLines(List<String> lines) {
+ return lines(lines, "\n");
}
public static String withNativeLineSeparator(String s) {
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index e2d8b20..4b42d31 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.StringConsumer.FileConsumer;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.Reference;
@@ -186,8 +187,10 @@
assertNotNull(parsedCommand.getR8Command());
InternalOptions internalOptions = parsedCommand.getR8Command().getInternalOptions();
assertNotNull(internalOptions);
- assertTrue(internalOptions.proguardMapConsumer instanceof StringConsumer.FileConsumer);
- FileConsumer proguardMapConsumer = (FileConsumer) internalOptions.proguardMapConsumer;
+ assertTrue(internalOptions.proguardMapConsumer instanceof ProguardMapStringConsumer);
+ ProguardMapStringConsumer mapStringConsumer =
+ (ProguardMapStringConsumer) internalOptions.proguardMapConsumer;
+ FileConsumer proguardMapConsumer = (FileConsumer) mapStringConsumer.getStringConsumer();
assertEquals(pgMap, proguardMapConsumer.getOutputPath());
}
diff --git a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
index f827134..e38ecf7 100644
--- a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
@@ -25,6 +25,7 @@
@RunWith(Parameterized.class)
public class ProguardMapMarkerTest extends TestBase {
+
private static final int EXPECTED_NUMBER_OF_KEYS_DEX = 6;
private static final int EXPECTED_NUMBER_OF_KEYS_CF = 5;
private static final String CLASS_FILE =
@@ -85,11 +86,10 @@
.setMinApiLevel(minApiLevel.getLevel())
.setProguardMapConsumer(
ToolHelper.consumeString(
- proguardMap -> {
- proguardMapIds.fromMap =
- verifyMarkersGetPgMapId(
- proguardMap, minApiLevel.getLevel(), EXPECTED_NUMBER_OF_KEYS_DEX);
- }))
+ proguardMap ->
+ proguardMapIds.fromMap =
+ verifyMarkersGetPgMapId(
+ proguardMap, minApiLevel.getLevel(), EXPECTED_NUMBER_OF_KEYS_DEX)))
.build());
verifyProguardMapIds(proguardMapIds);
}
@@ -154,21 +154,28 @@
}
String key = comment.substring(0, colonIndex).trim();
String value = comment.substring(colonIndex + 1).trim();
- if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER)) {
- assertEquals("R8", value);
- } else if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER_VERSION)) {
- assertEquals(Version.LABEL, value);
- } else if (key.equals(ProguardMapSupplier.MARKER_KEY_MIN_API)) {
- 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_PG_MAP_ID)) {
- proguardMapId = value;
- } else if (key.equals(ProguardMapSupplier.MARKER_KEY_PG_MAP_HASH)) {
- proguardMapHash = value;
- } else {
- continue;
+ switch (key) {
+ case "compiler":
+ assertEquals("R8", value);
+ break;
+ case "compiler_version":
+ assertEquals(Version.LABEL, value);
+ break;
+ case "min_api":
+ assertNotNull(minApiLevel);
+ assertEquals(minApiLevel.intValue(), Integer.parseInt(value));
+ break;
+ case "compiler_hash":
+ assertEquals(VersionProperties.INSTANCE.getSha(), value);
+ break;
+ case "pg_map_id":
+ proguardMapId = value;
+ break;
+ case "pg_map_hash":
+ proguardMapHash = value;
+ break;
+ default:
+ continue;
}
assertFalse(keysFound.contains(key));
keysFound.add(key);
diff --git a/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java b/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java
index efc6cf7..1468bd8 100644
--- a/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MappingFileHashTest.java
@@ -8,8 +8,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker;
-import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapChecker.VerifyMappingFileHashResult;
+import com.android.tools.r8.naming.ProguardMapChecker.VerifyMappingFileHashResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
diff --git a/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataUnknownTest.java b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataUnknownTest.java
index 345566b..01159fa 100644
--- a/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/partition/RetracePartitionMetadataUnknownTest.java
@@ -12,8 +12,8 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.naming.MapVersion;
-import com.android.tools.r8.retrace.RetracePartitionException;
import com.android.tools.r8.retrace.internal.MappingPartitionMetadataInternal;
+import com.android.tools.r8.retrace.internal.RetracePartitionException;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import org.junit.Test;