Trace keep xml as R8 root set when using optimized shrinking

Bug: b/326564914
Change-Id: Ieb844d34507603932d04ace6e4ad5fe3d525c2fd
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 682b2df..8102003 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3884,7 +3884,7 @@
   private void traceManifests(Timing timing) {
     if (options.isOptimizedResourceShrinking()) {
       timing.begin("Trace AndroidManifest.xml files");
-      appView.getResourceShrinkerState().traceManifests();
+      appView.getResourceShrinkerState().traceKeepXmlAndManifest();
       timing.end();
     }
   }
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 29a3399..e43c68e 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -93,12 +93,32 @@
     }
   }
 
-  public void traceManifests() {
+  public void traceKeepXmlAndManifest() {
+    // We start by building the root set of all keep/discard rules to find those pinned resources
+    // before marking additional resources in the trace.
+    // We then explicitly trace those resources to transitively get the full set of reachable
+    // resources and code.
+    try {
+      updateModelWithKeepXmlReferences();
+    } catch (IOException e) {
+      throw errorHandler.apply(e);
+    }
+    // TODO(b/329584653): Update processToolsAttributes in AGP to return the kept resources and
+    //  trace directly using this instead of iterating the full resource store below.
+    r8ResourceShrinkerModel.getResourceStore().processToolsAttributes();
+    traceLiveResources();
     for (Supplier<InputStream> manifestProvider : manifestProviders) {
       traceXml("AndroidManifest.xml", manifestProvider.get());
     }
   }
 
+  private void traceLiveResources() {
+    r8ResourceShrinkerModel.getResourceStore().getResources().stream()
+        .filter(Resource::isReachable)
+        .map(r -> r.value)
+        .forEach(this::trace);
+  }
+
   public void setEnqueuerCallback(ClassReferenceCallback enqueuerCallback) {
     assert this.enqueuerCallback == null;
     this.enqueuerCallback = enqueuerCallback;
diff --git a/src/test/java/com/android/tools/r8/androidresources/KeepXmlTransitiveCodeReachabilityTest.java b/src/test/java/com/android/tools/r8/androidresources/KeepXmlTransitiveCodeReachabilityTest.java
index ee97c1c..da9fa3c 100644
--- a/src/test/java/com/android/tools/r8/androidresources/KeepXmlTransitiveCodeReachabilityTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/KeepXmlTransitiveCodeReachabilityTest.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.androidresources;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
@@ -59,10 +59,10 @@
             })
         .inspect(
             codeInspector -> {
-              // TODO(b/326564914): Ensure that we handle code references from resources that are
-              //  kept with xml keep rules (i.e., Bar is present).
-              assertThat(codeInspector.clazz(Bar.class), isAbsent());
-            });
+              assertThat(codeInspector.clazz(Bar.class), isPresentAndNotRenamed());
+            })
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("init");
   }
 
   public static class TestClass {