Desugared lib: keep rules in JSON file

Bug: 144013102
Change-Id: I6a21b86a011babe9baf2e93fce10de40c4c129ca
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 1c774d6..8fb3ac2 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -251,6 +251,8 @@
         for (Pair<List<String>, Origin> proguardConfig : proguardConfigStrings) {
           r8Builder.addProguardConfiguration(proguardConfig.getFirst(), proguardConfig.getSecond());
         }
+        r8Builder.addProguardConfiguration(
+            libraryConfiguration.getExtraKeepRules(), Origin.unknown());
         r8Builder.addProguardConfigurationFiles(proguardConfigFiles);
         r8Command = r8Builder.makeCommand();
       } else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index e1f2181..dda019e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -15,6 +15,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -31,11 +32,26 @@
   private final Map<DexType, DexType> backportCoreLibraryMember;
   private final Map<DexType, DexType> customConversions;
   private final List<Pair<DexType, DexString>> dontRewriteInvocation;
+  private final List<String> extraKeepRules;
 
   public static Builder builder(DexItemFactory dexItemFactory) {
     return new Builder(dexItemFactory);
   }
 
+  public static DesugaredLibraryConfiguration withOnlyRewritePrefixForTesting(
+      Map<String, String> prefix) {
+    return new DesugaredLibraryConfiguration(
+        AndroidApiLevel.B,
+        false,
+        prefix,
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableMap.of(),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static DesugaredLibraryConfiguration empty() {
     return new DesugaredLibraryConfiguration(
         AndroidApiLevel.B,
@@ -45,6 +61,7 @@
         ImmutableMap.of(),
         ImmutableMap.of(),
         ImmutableMap.of(),
+        ImmutableList.of(),
         ImmutableList.of());
   }
 
@@ -56,7 +73,8 @@
       Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
       Map<DexType, DexType> backportCoreLibraryMember,
       Map<DexType, DexType> customConversions,
-      List<Pair<DexType, DexString>> dontRewriteInvocation) {
+      List<Pair<DexType, DexString>> dontRewriteInvocation,
+      List<String> extraKeepRules) {
     this.requiredCompilationAPILevel = requiredCompilationAPILevel;
     this.libraryCompilation = libraryCompilation;
     this.rewritePrefix = rewritePrefix;
@@ -65,6 +83,7 @@
     this.backportCoreLibraryMember = backportCoreLibraryMember;
     this.customConversions = customConversions;
     this.dontRewriteInvocation = dontRewriteInvocation;
+    this.extraKeepRules = extraKeepRules;
   }
 
   public PrefixRewritingMapper createPrefixRewritingMapper(DexItemFactory factory) {
@@ -105,6 +124,10 @@
     return dontRewriteInvocation;
   }
 
+  public List<String> getExtraKeepRules() {
+    return extraKeepRules;
+  }
+
   public static class Builder {
 
     private final DexItemFactory factory;
@@ -117,6 +140,7 @@
     private Map<DexType, DexType> backportCoreLibraryMember = new HashMap<>();
     private Map<DexType, DexType> customConversions = new HashMap<>();
     private List<Pair<DexType, DexString>> dontRewriteInvocation = new ArrayList<>();
+    private List<String> extraKeepRules = Collections.emptyList();
 
     public Builder(DexItemFactory dexItemFactory) {
       this.factory = dexItemFactory;
@@ -137,6 +161,11 @@
       return this;
     }
 
+    public Builder setExtraKeepRules(List<String> rules) {
+      extraKeepRules = rules;
+      return this;
+    }
+
     public Builder putRewritePrefix(String prefix, String rewrittenPrefix) {
       rewritePrefix.put(prefix, rewrittenPrefix);
       return this;
@@ -207,7 +236,8 @@
           ImmutableMap.copyOf(retargetCoreLibMember),
           ImmutableMap.copyOf(backportCoreLibraryMember),
           ImmutableMap.copyOf(customConversions),
-          ImmutableList.copyOf(dontRewriteInvocation));
+          ImmutableList.copyOf(dontRewriteInvocation),
+          ImmutableList.copyOf(extraKeepRules));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
index fbf3d1f..4de1fe1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
@@ -13,11 +13,13 @@
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 public class DesugaredLibraryConfigurationParser {
 
-  private static final int MAX_SUPPORTED_VERSION = 1;
+  private static final int MAX_SUPPORTED_VERSION = 2;
 
   private final DesugaredLibraryConfiguration.Builder configurationBuilder;
   private final Reporter reporter;
@@ -58,6 +60,13 @@
               "Unsupported desugared library configuration version, please upgrade the D8/R8"
                   + " compiler."));
     }
+    if (version == 1) {
+      reporter.warning(
+          new StringDiagnostic(
+              "You are using an experimental version of the desugared library configuration, "
+                  + "distributed only in the early canary versions. Please update for "
+                  + "production releases and to fix this warning."));
+    }
     int required_compilation_api_level =
         jsonConfig.get("required_compilation_api_level").getAsInt();
     configurationBuilder.setRequiredCompilationAPILevel(
@@ -74,6 +83,14 @@
       }
       parseFlags(jsonFlagSet.getAsJsonObject());
     }
+    if (jsonConfig.has("shrinker_config")) {
+      JsonArray jsonKeepRules = jsonConfig.get("shrinker_config").getAsJsonArray();
+      List<String> extraKeepRules = new ArrayList<>(jsonKeepRules.size());
+      for (JsonElement keepRule : jsonKeepRules) {
+        extraKeepRules.add(keepRule.getAsString());
+      }
+      configurationBuilder.setExtraKeepRules(extraKeepRules);
+    }
     return configurationBuilder.build();
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index 643be86..90e675c 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -22,21 +22,13 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.List;
 
 public class CoreLibDesugarTestBase extends TestBase {
 
-  private List<String> getBaseKeepRules() throws IOException {
-    Path path = Paths
-        .get("src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_keep_rules.cfg");
-    return Files.readAllLines(path, StandardCharsets.UTF_8);
-  }
-
   protected boolean requiresEmulatedInterfaceCoreLibDesugaring(TestParameters parameters) {
     return parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel();
   }
@@ -81,9 +73,8 @@
               .setMinApiLevel(apiLevel.getLevel())
               .setOutput(desugaredLib, OutputMode.DexIndexed);
       if (shrink) {
-        List<String> allKeepRules = getBaseKeepRules();
-        allKeepRules.addAll(Arrays.asList(keepRules.split(System.lineSeparator())));
-        l8Builder.addProguardConfiguration(allKeepRules, Origin.unknown());
+        l8Builder.addProguardConfiguration(
+            Arrays.asList(keepRules.split(System.lineSeparator())), Origin.unknown());
       }
       ToolHelper.runL8(
           l8Builder.build(),
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
index 843551e..adbcb3d 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/InconsistentPrefixTest.java
@@ -11,9 +11,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
 import com.android.tools.r8.jasmin.JasminBuilder;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.Map;
@@ -39,15 +36,7 @@
           .addOptionsModification(
               options ->
                   options.desugaredLibraryConfiguration =
-                      new DesugaredLibraryConfiguration(
-                          AndroidApiLevel.B,
-                          false,
-                          x,
-                          ImmutableMap.of(),
-                          ImmutableMap.of(),
-                          ImmutableMap.of(),
-                          ImmutableMap.of(),
-                          ImmutableList.of()))
+                      DesugaredLibraryConfiguration.withOnlyRewritePrefixForTesting(x))
           .compile();
       fail("Should have raised the compilation error.");
     } catch (CompilationFailedException e) {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs.json b/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs.json
index 79bc84f..ab1a617 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs.json
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs.json
@@ -1,6 +1,6 @@
 {
-  "configuration_format_version": 1,
-  "version": "0.6.0",
+  "configuration_format_version": 2,
+  "version": "0.7.0",
   "required_compilation_api_level": 26,
   "library_flags": [
     {
@@ -137,5 +137,12 @@
         "java.util.OptionalLong": "j$.util.OptionalConversions"
       }
     }
+  ],
+  "shrinker_config": [
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
+    "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
+    "-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }",
+    "-keeppackagenames j$"
   ]
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_comments.md b/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_comments.md
index db105b8..f08da27 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_comments.md
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_comments.md
@@ -19,7 +19,7 @@
 
 ## Library and program flags
 
-The fourth and last fields are `library_flags` and `program_flags`. They include the set of flags
+The fourth and fifth fields are `library_flags` and `program_flags`. They include the set of flags
 required for respectively the library and the program using the desugared library compilation. The
 sets of flags are different depending on the min API level used. The flags are in a list, where
 each list entry specifies up to which min API level the set of flags should be applied. During
@@ -29,6 +29,12 @@
 If compiling the program for min API 24, R8/D8 will use both the set of flags for API 24 and 26
 (24 <= 24, 24 <= 26 but !(24 <= 20)).
 
+## Extra keep rules
+
+The last field is `extra_keep_rules`, it includes keep rules that are appended by L8 when shrinking
+the desugared library. It includes keep rules related to reflection inside the desugared library,
+related to enum to have EnumSet working and to keep the j$ prefix.
+
 ## Copyright
 
 Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_keep_rules.cfg b/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_keep_rules.cfg
deleted file mode 100644
index 5aa90c9..0000000
--- a/src/test/java/com/android/tools/r8/desugar/corelib/desugar_jdk_libs_keep_rules.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-# For reflective access in ConcurrentHashMap with CompilationMode.DEBUG and R8 compilation.
--keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin {
-   int lockState;
-}
--keepclassmembers class j$.util.concurrent.ConcurrentHashMap {
-   int sizeCtl;
-   int transferIndex;
-   long baseCount;
-   int cellsBusy;
-}
--keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell {
-   long value;
-}
-# For EnumSet usage.
--keepclassmembers enum * {
-    public static **[] values();
-    public static ** valueOf(java.lang.String);
-}
-# j$ prefix should not be changed.
--keeppackagenames j$
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index 3353fd2..c81a2d6 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -16,12 +16,10 @@
 import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
 import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
 import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -79,15 +77,8 @@
             .addOptionsModification(
                 options ->
                     options.desugaredLibraryConfiguration =
-                        new DesugaredLibraryConfiguration(
-                            AndroidApiLevel.B,
-                            false,
-                            ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
-                            ImmutableMap.of(),
-                            ImmutableMap.of(),
-                            ImmutableMap.of(),
-                            ImmutableMap.of(),
-                            ImmutableList.of()))
+                        DesugaredLibraryConfiguration.withOnlyRewritePrefixForTesting(
+                            ImmutableMap.of(packageName + ".runtime", packageName + ".library")))
             .compile();
 
     testForR8(parameters.getBackend())