Support dumping for specific builds

Bug: b/236449152
Change-Id: Iab6d3521d56c79b461df255a460d119a5ae12223
diff --git a/src/main/java/com/android/tools/r8/DumpOptions.java b/src/main/java/com/android/tools/r8/DumpOptions.java
index 14ae9c6..e0351b3 100644
--- a/src/main/java/com/android/tools/r8/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/DumpOptions.java
@@ -12,7 +12,10 @@
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
 import com.android.tools.r8.utils.ThreadUtils;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 
 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@@ -93,43 +96,53 @@
     this.dumpInputToFile = dumpInputToFile;
   }
 
-  public String dumpOptions() {
+  public String getBuildPropertiesFileContent() {
     StringBuilder builder = new StringBuilder();
-    addDumpEntry(builder, TOOL_KEY, tool.name());
+    getBuildProperties()
+        .forEach((key, value) -> builder.append(key).append("=").append(value).append("\n"));
+    return builder.toString();
+  }
+
+  public Map<String, String> getBuildProperties() {
+    Map<String, String> buildProperties = new LinkedHashMap<>();
+    addDumpEntry(buildProperties, TOOL_KEY, tool.name());
     // We keep the following values for backward compatibility.
     addDumpEntry(
-        builder,
+        buildProperties,
         MODE_KEY,
         compilationMode == CompilationMode.DEBUG ? DEBUG_MODE_VALUE : RELEASE_MODE_VALUE);
-    addDumpEntry(builder, MIN_API_KEY, minApi);
-    addDumpEntry(builder, OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY, optimizeMultidexForLinearAlloc);
+    addDumpEntry(buildProperties, MIN_API_KEY, minApi);
+    addDumpEntry(
+        buildProperties, OPTIMIZE_MULTIDEX_FOR_LINEAR_ALLOC_KEY, optimizeMultidexForLinearAlloc);
     if (threadCount != ThreadUtils.NOT_SPECIFIED) {
-      addDumpEntry(builder, THREAD_COUNT_KEY, threadCount);
+      addDumpEntry(buildProperties, THREAD_COUNT_KEY, threadCount);
     }
-    addDumpEntry(builder, DESUGAR_STATE_KEY, desugarState);
-    addOptionalDumpEntry(builder, INTERMEDIATE_KEY, intermediate);
-    addOptionalDumpEntry(builder, INCLUDE_DATA_RESOURCES_KEY, includeDataResources);
-    addOptionalDumpEntry(builder, TREE_SHAKING_KEY, treeShaking);
-    addOptionalDumpEntry(builder, MINIFICATION_KEY, minification);
-    addOptionalDumpEntry(builder, FORCE_PROGUARD_COMPATIBILITY_KEY, forceProguardCompatibility);
+    addDumpEntry(buildProperties, DESUGAR_STATE_KEY, desugarState);
+    addOptionalDumpEntry(buildProperties, INTERMEDIATE_KEY, intermediate);
+    addOptionalDumpEntry(buildProperties, INCLUDE_DATA_RESOURCES_KEY, includeDataResources);
+    addOptionalDumpEntry(buildProperties, TREE_SHAKING_KEY, treeShaking);
+    addOptionalDumpEntry(buildProperties, MINIFICATION_KEY, minification);
+    addOptionalDumpEntry(
+        buildProperties, FORCE_PROGUARD_COMPATIBILITY_KEY, forceProguardCompatibility);
     System.getProperties()
         .stringPropertyNames()
         .forEach(
             name -> {
               if (name.startsWith("com.android.tools.r8.")) {
                 String value = System.getProperty(name);
-                addDumpEntry(builder, SYSTEM_PROPERTY_PREFIX + name, value);
+                addDumpEntry(buildProperties, SYSTEM_PROPERTY_PREFIX + name, value);
               }
             });
-    return builder.toString();
+    return buildProperties;
   }
 
-  private void addOptionalDumpEntry(StringBuilder builder, String key, Optional<?> optionalValue) {
-    optionalValue.ifPresent(bool -> addDumpEntry(builder, key, bool));
+  private void addOptionalDumpEntry(
+      Map<String, String> buildProperties, String key, Optional<?> optionalValue) {
+    optionalValue.ifPresent(bool -> addDumpEntry(buildProperties, key, bool));
   }
 
-  private void addDumpEntry(StringBuilder builder, String key, Object value) {
-    builder.append(key).append("=").append(value).append("\n");
+  private void addDumpEntry(Map<String, String> buildProperties, String key, Object value) {
+    buildProperties.put(key, Objects.toString(value));
   }
 
   private boolean hasDesugaredLibraryConfiguration() {
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index f00f7fb..15e187d 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ClassFileResourceProvider;
 import com.android.tools.r8.DataResourceProvider;
 import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DumpOptions;
 import com.android.tools.r8.ProgramResource;
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.ProgramResourceProvider;
@@ -55,12 +56,15 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 public class ApplicationReader {
@@ -196,9 +200,10 @@
       cleanDump = true;
       dumpOutput = Paths.get("/tmp").resolve("dump" + System.nanoTime() + ".zip");
     }
-    if (dumpOutput != null) {
+    DumpOptions dumpOptions = options.dumpOptions;
+    if (dumpOutput != null && dumpOptions != null && shouldDump(dumpOptions)) {
       timing.begin("ApplicationReader.dump");
-      inputApp.dump(dumpOutput, options.dumpOptions, options.reporter, options.dexItemFactory());
+      inputApp.dump(dumpOutput, dumpOptions, options.reporter, options.dexItemFactory());
       if (cleanDump) {
         Files.delete(dumpOutput);
       }
@@ -212,6 +217,18 @@
     }
   }
 
+  private static boolean shouldDump(DumpOptions options) {
+    Map<String, String> buildProperties = options.getBuildProperties();
+    for (Entry<String, String> entry : buildProperties.entrySet()) {
+      String valueRegExp =
+          System.getProperty("com.android.tools.r8.dump.filter.buildproperty." + entry.getKey());
+      if (valueRegExp != null && !Pattern.matches(valueRegExp, entry.getValue())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   public MainDexInfo readMainDexClasses(DexApplication app) {
     return readMainDexClasses(app, flags.hasReadProgramClassFromCf());
   }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 959238e..df58d15 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -467,9 +467,6 @@
   }
 
   public void dump(Path output, DumpOptions options, Reporter reporter, DexItemFactory factory) {
-    if (options == null) {
-      return;
-    }
     int nextDexIndex = 0;
     OpenOption[] openOptions =
         new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
@@ -477,7 +474,10 @@
       writeToZipStream(
           out, dumpVersionFileName, Version.getVersionString().getBytes(), ZipEntry.DEFLATED);
       writeToZipStream(
-          out, dumpBuildPropertiesFileName, options.dumpOptions().getBytes(), ZipEntry.DEFLATED);
+          out,
+          dumpBuildPropertiesFileName,
+          options.getBuildPropertiesFileContent().getBytes(),
+          ZipEntry.DEFLATED);
       if (options.getDesugaredLibraryJsonSource() != null) {
         writeToZipStream(
             out,