Add outstanding compilation options to R8 build metadata

This adds tracking of:
* Startup layout optimization
* Startup profile guided optimizations

This also adds tracking of the following directives:
* -flattenpackagehierarchy
* -repackageclasses
* -shrinkunusedprotofields
* -obfuscationdictionary
* -classobfuscationdictionary
* -packageobfuscationdictionary

Finally, this changes the Gson serialization to always serializing nulls (as opposed to omitting null-valued properties).

Fixes: b/373399258
Fixes: b/373400575
Fixes: b/373402721
Change-Id: Ied795602eb458139e80ba5bc4bf94ec6a1a88fce
diff --git a/src/main/java/com/android/tools/r8/metadata/D8BuildMetadata.java b/src/main/java/com/android/tools/r8/metadata/D8BuildMetadata.java
index 4f9003b..5abf83b 100644
--- a/src/main/java/com/android/tools/r8/metadata/D8BuildMetadata.java
+++ b/src/main/java/com/android/tools/r8/metadata/D8BuildMetadata.java
@@ -22,6 +22,7 @@
             D8ApiModelingMetadata.class, deserializeTo(D8ApiModelingMetadataImpl.class))
         .registerTypeAdapter(
             D8LibraryDesugaringMetadata.class, deserializeTo(D8LibraryDesugaringMetadataImpl.class))
+        .serializeNulls()
         .create()
         .fromJson(json, D8BuildMetadataImpl.class);
   }
diff --git a/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java b/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
index 153dd1e..0c81115 100644
--- a/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
+++ b/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
@@ -51,6 +51,7 @@
         .registerTypeAdapter(
             R8StartupOptimizationMetadata.class,
             deserializeTo(R8StartupOptimizationMetadataImpl.class))
+        .serializeNulls()
         .create()
         .fromJson(json, R8BuildMetadataImpl.class);
   }
diff --git a/src/main/java/com/android/tools/r8/metadata/R8OptionsMetadata.java b/src/main/java/com/android/tools/r8/metadata/R8OptionsMetadata.java
index c9279c2..eb3e4d8 100644
--- a/src/main/java/com/android/tools/r8/metadata/R8OptionsMetadata.java
+++ b/src/main/java/com/android/tools/r8/metadata/R8OptionsMetadata.java
@@ -25,15 +25,27 @@
 
   int getMinApiLevel();
 
+  boolean hasObfuscationDictionary();
+
+  boolean hasClassObfuscationDictionary();
+
+  boolean hasPackageObfuscationDictionary();
+
   boolean isAccessModificationEnabled();
 
   boolean isDebugModeEnabled();
 
-  boolean isProGuardCompatibilityModeEnabled();
+  boolean isFlattenPackageHierarchyEnabled();
 
   boolean isObfuscationEnabled();
 
   boolean isOptimizationsEnabled();
 
+  boolean isProGuardCompatibilityModeEnabled();
+
+  boolean isProtoLiteOptimizationEnabled();
+
+  boolean isRepackageClassesEnabled();
+
   boolean isShrinkingEnabled();
 }
diff --git a/src/main/java/com/android/tools/r8/metadata/R8StartupOptimizationMetadata.java b/src/main/java/com/android/tools/r8/metadata/R8StartupOptimizationMetadata.java
index 3067ed3..3bbeb5d 100644
--- a/src/main/java/com/android/tools/r8/metadata/R8StartupOptimizationMetadata.java
+++ b/src/main/java/com/android/tools/r8/metadata/R8StartupOptimizationMetadata.java
@@ -6,4 +6,9 @@
 import com.android.tools.r8.keepanno.annotations.KeepForApi;
 
 @KeepForApi
-public interface R8StartupOptimizationMetadata {}
+public interface R8StartupOptimizationMetadata {
+
+  boolean isDexLayoutOptimizationEnabled();
+
+  boolean isProfileGuidedOptimizationEnabled();
+}
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/R8OptionsMetadataImpl.java b/src/main/java/com/android/tools/r8/metadata/impl/R8OptionsMetadataImpl.java
index 70cec6f..aa4322d 100644
--- a/src/main/java/com/android/tools/r8/metadata/impl/R8OptionsMetadataImpl.java
+++ b/src/main/java/com/android/tools/r8/metadata/impl/R8OptionsMetadataImpl.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.metadata.R8KeepAttributesMetadata;
 import com.android.tools.r8.metadata.R8LibraryDesugaringMetadata;
 import com.android.tools.r8.metadata.R8OptionsMetadata;
+import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
@@ -28,6 +29,18 @@
     implements R8OptionsMetadata {
 
   @Expose
+  @SerializedName("hasObfuscationDictionary")
+  private final boolean hasObfuscationDictionary;
+
+  @Expose
+  @SerializedName("hasClassObfuscationDictionary")
+  private final boolean hasClassObfuscationDictionary;
+
+  @Expose
+  @SerializedName("hasPackageObfuscationDictionary")
+  private final boolean hasPackageObfuscationDictionary;
+
+  @Expose
   @SerializedName("keepAttributes")
   private final R8KeepAttributesMetadata keepAttributesMetadata;
 
@@ -36,8 +49,8 @@
   private final boolean isAccessModificationEnabled;
 
   @Expose
-  @SerializedName("isProGuardCompatibilityModeEnabled")
-  private final boolean isProGuardCompatibilityModeEnabled;
+  @SerializedName("isFlattenPackageHierarchyEnabled")
+  private final boolean isFlattenPackageHierarchyEnabled;
 
   @Expose
   @SerializedName("isObfuscationEnabled")
@@ -48,6 +61,18 @@
   private final boolean isOptimizationsEnabled;
 
   @Expose
+  @SerializedName("isProGuardCompatibilityModeEnabled")
+  private final boolean isProGuardCompatibilityModeEnabled;
+
+  @Expose
+  @SerializedName("isProtoLiteOptimizationEnabled")
+  private final boolean isProtoLiteOptimizationEnabled;
+
+  @Expose
+  @SerializedName("isRepackageClassesEnabled")
+  private final boolean isRepackageClassesEnabled;
+
+  @Expose
   @SerializedName("isShrinkingEnabled")
   private final boolean isShrinkingEnabled;
 
@@ -56,15 +81,27 @@
         R8ApiModelingMetadataImpl.create(options),
         R8LibraryDesugaringMetadataImpl.create(options),
         options);
+    ProguardConfiguration configuration = options.getProguardConfiguration();
+    boolean hasConfiguration = configuration != null;
+    this.hasObfuscationDictionary =
+        hasConfiguration && !configuration.getObfuscationDictionary().isEmpty();
+    this.hasClassObfuscationDictionary =
+        hasConfiguration && !configuration.getClassObfuscationDictionary().isEmpty();
+    this.hasPackageObfuscationDictionary =
+        hasConfiguration && !configuration.getPackageObfuscationDictionary().isEmpty();
     this.keepAttributesMetadata =
-        options.hasProguardConfiguration()
-            ? new R8KeepAttributesMetadataImpl(
-                options.getProguardConfiguration().getKeepAttributes())
+        hasConfiguration
+            ? new R8KeepAttributesMetadataImpl(configuration.getKeepAttributes())
             : null;
     this.isAccessModificationEnabled = options.isAccessModificationEnabled();
-    this.isProGuardCompatibilityModeEnabled = options.forceProguardCompatibility;
+    this.isFlattenPackageHierarchyEnabled =
+        hasConfiguration && configuration.getPackageObfuscationMode().isFlattenPackageHierarchy();
     this.isObfuscationEnabled = options.isMinifying();
     this.isOptimizationsEnabled = options.isOptimizing();
+    this.isProGuardCompatibilityModeEnabled = options.forceProguardCompatibility;
+    this.isProtoLiteOptimizationEnabled = options.protoShrinking().isProtoShrinkingEnabled();
+    this.isRepackageClassesEnabled =
+        hasConfiguration && configuration.getPackageObfuscationMode().isRepackageClasses();
     this.isShrinkingEnabled = options.isShrinking();
   }
 
@@ -74,13 +111,28 @@
   }
 
   @Override
+  public boolean hasObfuscationDictionary() {
+    return hasObfuscationDictionary;
+  }
+
+  @Override
+  public boolean hasClassObfuscationDictionary() {
+    return hasClassObfuscationDictionary;
+  }
+
+  @Override
+  public boolean hasPackageObfuscationDictionary() {
+    return hasPackageObfuscationDictionary;
+  }
+
+  @Override
   public boolean isAccessModificationEnabled() {
     return isAccessModificationEnabled;
   }
 
   @Override
-  public boolean isProGuardCompatibilityModeEnabled() {
-    return isProGuardCompatibilityModeEnabled;
+  public boolean isFlattenPackageHierarchyEnabled() {
+    return isFlattenPackageHierarchyEnabled;
   }
 
   @Override
@@ -94,6 +146,21 @@
   }
 
   @Override
+  public boolean isProGuardCompatibilityModeEnabled() {
+    return isProGuardCompatibilityModeEnabled;
+  }
+
+  @Override
+  public boolean isProtoLiteOptimizationEnabled() {
+    return isProtoLiteOptimizationEnabled;
+  }
+
+  @Override
+  public boolean isRepackageClassesEnabled() {
+    return isRepackageClassesEnabled;
+  }
+
+  @Override
   public boolean isShrinkingEnabled() {
     return isShrinkingEnabled;
   }
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/R8StartupOptimizationMetadataImpl.java b/src/main/java/com/android/tools/r8/metadata/impl/R8StartupOptimizationMetadataImpl.java
index d61d083..9e513b4 100644
--- a/src/main/java/com/android/tools/r8/metadata/impl/R8StartupOptimizationMetadataImpl.java
+++ b/src/main/java/com/android/tools/r8/metadata/impl/R8StartupOptimizationMetadataImpl.java
@@ -9,7 +9,9 @@
 import com.android.tools.r8.keepanno.annotations.KeepItemKind;
 import com.android.tools.r8.keepanno.annotations.UsedByReflection;
 import com.android.tools.r8.metadata.R8StartupOptimizationMetadata;
+import com.android.tools.r8.profile.startup.StartupOptions;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
 
 @UsedByReflection(
@@ -21,12 +23,35 @@
     fieldAnnotatedByClassConstant = SerializedName.class)
 public class R8StartupOptimizationMetadataImpl implements R8StartupOptimizationMetadata {
 
-  private R8StartupOptimizationMetadataImpl() {}
+  @Expose
+  @SerializedName("isDexLayoutOptimizationEnabled")
+  private final boolean isDexLayoutOptimizationEnabled;
+
+  @Expose
+  @SerializedName("isProfileGuidedOptimizationEnabled")
+  private final boolean isProfileGuidedOptimizationEnabled;
+
+  private R8StartupOptimizationMetadataImpl(StartupOptions startupOptions) {
+    this.isDexLayoutOptimizationEnabled = startupOptions.isStartupLayoutOptimizationEnabled();
+    this.isProfileGuidedOptimizationEnabled =
+        !startupOptions.isStartupBoundaryOptimizationsEnabled();
+  }
 
   public static R8StartupOptimizationMetadataImpl create(InternalOptions options) {
-    if (options.getStartupOptions().getStartupProfileProviders().isEmpty()) {
+    StartupOptions startupOptions = options.getStartupOptions();
+    if (startupOptions.getStartupProfileProviders().isEmpty()) {
       return null;
     }
-    return new R8StartupOptimizationMetadataImpl();
+    return new R8StartupOptimizationMetadataImpl(startupOptions);
+  }
+
+  @Override
+  public boolean isDexLayoutOptimizationEnabled() {
+    return isDexLayoutOptimizationEnabled;
+  }
+
+  @Override
+  public boolean isProfileGuidedOptimizationEnabled() {
+    return isProfileGuidedOptimizationEnabled;
   }
 }