Track styleable and attr accurately in optimized shrinking

Instantiate the resource model including styleables
Ignore the resource model returned unused resources and explicitly only keep those that are reachable

Bug: b/319802261
Change-Id: I08d995c8e7715bdf3281667253021eebd94d109b
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
index 2dbcf84..ab97ce2 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
@@ -131,12 +131,13 @@
     R8ResourceShrinkerModel model = new R8ResourceShrinkerModel(NoDebugReporter.INSTANCE, true);
     for (PathAndBytes pathAndBytes : resourceTables.keySet()) {
       ResourceTable loadedResourceTable = ResourceTable.parseFrom(pathAndBytes.bytes);
-      model.instantiateFromResourceTable(loadedResourceTable);
+      model.instantiateFromResourceTable(loadedResourceTable, false);
     }
-    return shrinkModel(model);
+    return shrinkModel(model, false);
   }
 
-  public ShrinkerResult shrinkModel(R8ResourceShrinkerModel model) throws IOException {
+  public ShrinkerResult shrinkModel(
+      R8ResourceShrinkerModel model, boolean exactMatchingOfStyleablesAndAttr) throws IOException {
     if (proguardMapStrings != null) {
       new ProguardMappingsRecorder(proguardMapStrings).recordObfuscationMappings(model);
       proguardMapStrings = null;
@@ -193,7 +194,7 @@
       }
     }
     List<Integer> resourceIdsToRemove =
-        unusedResources.stream().map(resource -> resource.value).collect(Collectors.toList());
+        getResourceIdsToRemove(unusedResources, model, exactMatchingOfStyleablesAndAttr);
     Map<FeatureSplit, ResourceTable> shrunkenTables = new HashMap<>();
     for (Entry<PathAndBytes, FeatureSplit> entry : resourceTables.entrySet()) {
       ResourceTable shrunkenResourceTable =
@@ -204,6 +205,19 @@
     return new ShrinkerResult(resEntriesToKeep.build(), shrunkenTables);
   }
 
+  private static List<Integer> getResourceIdsToRemove(
+      List<Resource> unusedResources,
+      R8ResourceShrinkerModel model,
+      boolean exactMatchingOfStyleablesAndAttr) {
+    if (!exactMatchingOfStyleablesAndAttr) {
+      return unusedResources.stream().map(resource -> resource.value).collect(Collectors.toList());
+    }
+    return model.getResourceStore().getResources().stream()
+        .filter(r -> !r.isReachable())
+        .map(r -> r.value)
+        .collect(Collectors.toList());
+  }
+
   // Lifted from com/android/utils/XmlUtils.java which we can't easily update internal dependency
   // for.
   /**
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
index e0cca4f..088547e 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -36,7 +36,7 @@
 
   public void setResourceTableInput(InputStream inputStream) {
     r8ResourceShrinkerModel = new R8ResourceShrinkerModel(NoDebugReporter.INSTANCE, true);
-    r8ResourceShrinkerModel.instantiateFromResourceTable(inputStream);
+    r8ResourceShrinkerModel.instantiateFromResourceTable(inputStream, true);
   }
 
   public R8ResourceShrinkerModel getR8ResourceShrinkerModel() {
@@ -56,16 +56,16 @@
     }
 
     // Similar to instantiation in ProtoResourceTableGatherer, but using an inputstream.
-    void instantiateFromResourceTable(InputStream inputStream) {
+    void instantiateFromResourceTable(InputStream inputStream, boolean includeStyleables) {
       try {
         ResourceTable resourceTable = ResourceTable.parseFrom(inputStream);
-        instantiateFromResourceTable(resourceTable);
+        instantiateFromResourceTable(resourceTable, includeStyleables);
       } catch (IOException ex) {
         throw new RuntimeException(ex);
       }
     }
 
-    void instantiateFromResourceTable(ResourceTable resourceTable) {
+    void instantiateFromResourceTable(ResourceTable resourceTable, boolean includeStyleables) {
       ResourceTableUtilKt.entriesSequence(resourceTable)
           .iterator()
           .forEachRemaining(
@@ -74,7 +74,7 @@
                 Entry entry = entryWrapper.getEntry();
                 int entryId = entryWrapper.getId();
                 recordSingleValueResources(resourceType, entry, entryId);
-                if (resourceType != ResourceType.STYLEABLE) {
+                if (resourceType != ResourceType.STYLEABLE || includeStyleables) {
                   this.addResource(
                       resourceType,
                       entryWrapper.getPackageName(),