Add simple logging of reachable resource entries
This enables simple logging for the reachable entries in the resource
table when using optimized shrinking.
Bug: b/360284664
Bug: b/287398085
Change-Id: I69a88568870caea86baaf4c6f93b2179d98898b3
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
index 5e52e33..660504d 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
@@ -65,7 +65,11 @@
&& definition.getStaticValue().isDexValueResourceNumber()) {
appView
.getResourceShrinkerState()
- .trace(definition.getStaticValue().asDexValueResourceNumber().getValue());
+ .trace(
+ definition.getStaticValue().asDexValueResourceNumber().getValue(),
+ // TODO(b/378625969): Consider wrapping this in a reachability structure
+ // to avoid decoding.
+ field.toString());
}
}
});
@@ -110,7 +114,7 @@
// these.
if (integers != null) {
for (Integer integer : integers) {
- resourceShrinkerState.trace(integer);
+ resourceShrinkerState.trace(integer, field.toString());
}
}
}
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 df58f3d..cb5e723 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1129,7 +1129,7 @@
}
public void traceResourceValue(int value) {
- appView.getResourceShrinkerState().trace(value);
+ appView.getResourceShrinkerState().trace(value, "from dex");
}
public void traceReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
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 fccc50d..34e581b 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -44,6 +44,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -58,11 +59,13 @@
private final List<Supplier<InputStream>> manifestProviders = new ArrayList<>();
private final Map<String, Supplier<InputStream>> resfileProviders = new HashMap<>();
private final Map<FeatureSplit, ResourceTable> resourceTables = new HashMap<>();
+ private final ShrinkerDebugReporter shrinkerDebugReporter;
private ClassReferenceCallback enqueuerCallback;
private Map<Integer, List<String>> resourceIdToXmlFiles;
private Set<String> packageNames;
private final Set<String> seenNoneClassValues = new HashSet<>();
private final Set<Integer> seenResourceIds = new HashSet<>();
+ private final Map<Resource, String> reachabilityMap = new ConcurrentHashMap<>();
private static final Set<String> SPECIAL_MANIFEST_ELEMENTS =
ImmutableSet.of(
@@ -86,10 +89,11 @@
Function<Exception, RuntimeException> errorHandler,
ShrinkerDebugReporter shrinkerDebugReporter) {
r8ResourceShrinkerModel = new R8ResourceShrinkerModel(shrinkerDebugReporter, true);
+ this.shrinkerDebugReporter = shrinkerDebugReporter;
this.errorHandler = errorHandler;
}
- public void trace(int id) {
+ public void trace(int id, String reachableFrom) {
if (!seenResourceIds.add(id)) {
return;
}
@@ -97,12 +101,17 @@
if (resource == null) {
return;
}
+ assert reachableFrom != null;
+
+ // For deterministic output, sort the strings lexicographically.
+ reachabilityMap.compute(
+ resource, (r, v) -> v == null || v.compareTo(reachableFrom) > 0 ? reachableFrom : v);
ResourceUsageModel.markReachable(resource);
traceXmlForResourceId(id);
if (resource.references != null) {
for (Resource reference : resource.references) {
if (!reference.isReachable()) {
- trace(reference.value);
+ trace(reference.value, reference.toString());
}
}
}
@@ -122,7 +131,7 @@
r8ResourceShrinkerModel
.getResourceStore()
.processToolsAttributes()
- .forEach(resource -> trace(resource.value));
+ .forEach(resource -> trace(resource.value, "keep xml file"));
for (Supplier<InputStream> manifestProvider : manifestProviders) {
traceXml("AndroidManifest.xml", manifestProvider.get());
}
@@ -212,6 +221,13 @@
featureSplit,
ResourceTableUtilKt.nullOutEntriesWithIds(resourceTable, resourceIdsToRemove, true));
});
+ for (Map.Entry<Resource, String> resourceStringEntry : reachabilityMap.entrySet()) {
+ shrinkerDebugReporter.debug(
+ () ->
+ resourceStringEntry.getKey().toString()
+ + " reachable from "
+ + resourceStringEntry.getValue());
+ }
return new ShrinkerResult(resEntriesToKeep, shrunkenTables);
}
@@ -243,7 +259,7 @@
// resources for the reachable marker.
ProtoAndroidManifestUsageRecorderKt.recordUsagesFromNode(xmlNode, r8ResourceShrinkerModel)
.iterator()
- .forEachRemaining(resource -> trace(resource.value));
+ .forEachRemaining(resource -> trace(resource.value, xmlFile));
} catch (IOException e) {
errorHandler.apply(e);
}
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
index 1028b38..67dbef6 100644
--- a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkerLoggingTest.java
@@ -118,9 +118,22 @@
ensureResourceReachabilityState(strings, "drawable", "foobar", true);
ensureRootResourceState(strings, "drawable", "foobar", true);
ensureUnusedState(strings, "drawable", "foobar", false);
+ } else {
+ assertTrue(finished.get());
+ List<String> strings = StringUtils.splitLines(log.toString());
+ ensureReachableOptimized(strings, "string", "bar", true);
+ ensureReachableOptimized(strings, "string", "foo", true);
+ ensureReachableOptimized(strings, "drawable", "foobar", true);
+ ensureReachableOptimized(strings, "drawable", "unused_drawable", false);
}
}
+ private void ensureReachableOptimized(
+ List<String> logStrings, String type, String name, boolean reachable) {
+ assertEquals(
+ logStrings.stream().anyMatch(s -> s.startsWith(type + ":" + name + ":")), reachable);
+ }
+
private void ensureDexReachableResourcesState(
List<String> logStrings, String type, String name, boolean reachable) {
// Example line: