The Android platform build system (Soong) runs the R8 compiler on
targets that compile DEX bytecode, including Android apps (android_app), tests
(android_test), and installable Java libraries with compile_dex: true (such
as services.jar), to shrink, optimize, and strip unused code and resources. On
static libraries (android_library and static java_library), Soong doesn't
run R8 directly, but uses the optimize property block to attach and propagate
consumer keep rules (export_proguard_flags_files: true) to downstream DEX
targets that statically link them.
For platform engineers building system images or vendor packages, eliminating overly broad keep rules offers direct system health benefits:
- Smaller system partition footprint: R8 removes dead classes, methods,
and resources before packaging APKs and JARs onto
/system,/system_ext,/product, and/vendor. - Smaller compiled artifacts: Fewer DEX methods mean smaller
.odexand.vdexfiles generated bydex2oatduring build-time or on-device compilation. - Lower runtime memory pressure: Because Android maps
.odex,.vdex, and APK resource tables into process memory using demand-pagedmmapcalls, smaller binaries reduce major page faults during app startup and lower resident code and resource memory across processes. For more information about how compiled app code affects device memory, see App code is memory. - More effective whole-program optimization: Narrow keep constraints let R8 inline methods, devirtualize interface and virtual calls, prune unused fields, and propagate constants across classes.
Configure R8 optimization in Soong
In Android.bp files, configure R8 optimization using the optimize property
block on android_app and installable java_library targets (or on
android_library and static java_library modules to export consumer keep
rules):
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
The following table summarizes the most common optimize properties in Soong
(defined in build/soong/java/dex.go):
| Property | Description |
|---|---|
enabled |
Controls whether R8 runs on the target. Defaults to true
for all android_app targets.
|
shrink |
Controls tree shaking to remove unreachable classes, fields, and
methods. Defaults to true for android_app
targets (false for standalone java_library and
test modules, which pass -dontshrink unless explicitly
set).
|
optimize |
Controls bytecode optimizations such as method inlining, class merging,
constant propagation, and dead branch removal. Defaults to
true for android_app targets (controlled by
the RELEASE_R8_OPTIMIZE_BY_DEFAULT release build flag).
|
obfuscate |
Controls identifier minification and renaming. Defaults to
false for historical compatibility, but set it to
true wherever possible to reduce DEX size and unlock
deeper optimizations (see
Enable obfuscation wherever possible).
|
shrink_resources |
Removes unused resources (res/ entries) from the packaged
APK after code shrinking. Defaults to false.
|
optimized_shrink_resources |
Runs the integrated R8 code and resource shrinker pipeline so R8 traces
code and resource references jointly in a single pass. When
shrink_resources: true is set, defaults to
RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT
(true in standard platform builds).
|
proguard_flags_files |
Lists module-specific .flags or .pro files
containing custom keep rules. Avoid adding custom files when standard
annotations or defaults suffice.
|
export_proguard_flags_files |
Propagates this library's proguard_flags_files to
downstream modules that depend on it statically.
|
trace_references_from |
Lists Java library companion targets whose bytecode references into this target R8 automatically traces and retains. |
Enable obfuscation wherever possible
In Soong, obfuscate defaults to false for historical compatibility, but you
should explicitly set obfuscate: true on android_app and standalone DEX
targets wherever possible:
- Smaller DEX and
.vdexfootprint: Renaming packages, classes, fields, and methods to short identifiers (a,b) shrinks the DEX string pool (string_idsandstring_data_item) and type descriptors. Because Android maps.vdexand.odexfiles into process memory, smaller symbol tables directly reduce both system partition size and runtime memory footprint. - Deeper whole-program optimizations: Letting R8 rename identifiers unlocks class merging, package flattening, and synthetic class deduplication across packages that R8 must otherwise skip to avoid name collisions.
- Full stack trace symbolication: Enabling obfuscation in Soong doesn't
reduce debuggability. For every R8-compiled target, Soong emits a
proguard_dictionarymapping file in the module's intermediate directory, bundles all module dictionaries into the build'sproguard-dict.zipartifact, embeds a mapping hash (--map-id-template) into the DEX header, and rewrites classSourceFileattributes (--source-file-template) soretracecan symbolicate stack traces automatically.
Keep obfuscate: false (or explicitly preserve public API names) only for:
- Shared libraries on the bootclasspath or
system_serverclasspath: Modules (java_libraryorjava_sdk_library) that expose an external API surface linked dynamically by other modules at runtime (such asframework.jar,services.jar, or<uses-library>targets) must either keepobfuscate: falseor explicitly preserve their API surface using@KeepForApior-keeprules (along withprotect_api_surface: truefor bootclasspath targets) so callers compiled against their stubs can resolve class and member names at runtime.
Before enabling obfuscate: true on an application, verify the following
migration prerequisites:
- External test APK dependencies: If an external
android_testAPK setsinstrumentation_for: "MyApp"and directly invokes internal classes or methods ofMyApp, renaming those symbols causesNoSuchMethodErrororNoClassDefFoundErrorat test runtime. Prefer structuring the test as a self-instrumenting APK linkingMyApp.implstatically, annotate test hooks with@VisibleForTesting, or configuretrace_references_from(see Step 2: Migrate test-driven keep rules) so internal symbols needed by tests are preserved while obfuscating the rest of the app. - String-based reflection and JNI: If a module looks up classes, methods,
or fields by literal string names (
Class.forName,getDeclaredMethod, or JNIFindClassandGetMethodID) without keep rules or annotations, obfuscation renames those targets and breaks runtime lookups. (Note that unannotated reflection also fails undershrink: trueandoptimize: true.) Annotate those entry points with Guide to Keep Annotations (@UsesReflection,@UsedByReflection, or@UsedByNative) so R8 preserves their names and obfuscates the rest of the module.
Follow the zero custom flags principle
The ideal Android platform module has no custom proguard.flags or keep.xml
files. In the Android platform build, the vast majority of custom keep rules are
redundant:
- Platform baselines and AAPT2: Most entry points are already retained
automatically by global platform baselines (such as
@Keep, JNInativemethods, and@VisibleForTesting) or generated by AAPT2 fromAndroidManifest.xmland layout resources (see Understand default platform keep rules). - Targeted alternatives: Where entry points must be preserved, prefer
declaration-site annotations (
keepanno,@VisibleForTesting), exported library rules (export_proguard_flags_files: true), or static test linking over detached.flagsfiles (see Audit and migrate existing keep rules).
Before adding or retaining a custom proguard.flags or keep.xml file, verify
whether the rule is already handled by default baselines or can be migrated to
code annotations.
Understand default platform keep rules
Soong automatically passes the following global baseline rules to every R8
invocation on DEX-compiling targets (android_app, android_test, and
installable java_library modules), configured in build/soong/java/dex.go:
build/make/core/proguard.flags: Preserves classes and members annotated with@com.android.internal.annotations.VisibleForTestingacross all packages, and with@VisibleForTesting(androidx.annotation.VisibleForTestingorcom.google.common.annotations.VisibleForTesting) withinandroid.**,com.android.**, andcom.google.android.**packages. Also preserves@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallback, and@dalvik.annotation.optimization.**.build/make/core/proguard_basic_keeps.flags: PreservesSourceFileattributes for stack traces, runtime visibility annotations (RuntimeVisible*Annotations),ExceptionsandAnnotationDefaultattributes,nativemethods,Serializablemembers,@JavascriptInterfacemethods,Throwable(String)constructors,Parcelable$CREATORfields, and protobufMessageLitefields.build/make/core/proguard/kotlin.flags: Silences harmless warnings for specific Kotlin meta-annotations (kotlin.Metadataandkotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) and strips KotlinDebugMetadataannotations in release builds.build/make/core/proguard/checknotnull.flags: Replaces common null check helper calls (com.google.common.base.Preconditions.checkNotNullanddagger.internal.Preconditions.checkNotNull*) with concise bytecode null checks. This file intentionally omitsObjects.requireNonNullto preserve explicit exception messages across framework API boundaries.build/make/core/proguard/enumvalues.flags: Retains thevaluesandvalueOfmethods onenumtypes unless disabled by the build configuration.- AAPT2 auto-generated rules: AAPT2 inspects merged
AndroidManifest.xml, layout XML, and preference XML files to generate exact keep rules for every registeredActivity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, customViewsubclass,Preferencesubclass, and XMLandroid:onClickmethod.
Audit and migrate existing keep rules
When auditing existing proguard.flags or keep.xml files in a platform
repository, evaluate each rule in order against the following four-step
hierarchy:
Step 1: Delete redundant or obsolete rules
Delete rules that are already covered by global baselines, AAPT2 manifest and layout rules, or R8 defaults, as well as rules referencing classes or packages that no longer exist.
If all rules in a .flags file are redundant, delete the file and remove
proguard_flags_files from Android.bp. If the remaining optimize block only
restates default settings, remove the redundant block and format the build file
with bpfmt -w Android.bp. When cleaning up a package, check whether companion
modules in subdirectories (such as Kotlin target variants) reference the same
flags file and update them together.
Step 2: Migrate test-driven keep rules
Move test-driven keep rules out of custom production .flags files using one of
the following patterns:
Link the implementation library into tests (
static_libs): When anandroid_testexercises package-private or internal implementation details of an app, the recommended platform architecture is to place the app source files in anandroid_library(MyApp.impl) and statically linkMyApp.implinto bothMyAppandMyAppTests:android_library { name: "MyApp.impl", srcs: ["src/**/*.java"], manifest: "AndroidManifest.xml", } android_app { name: "MyApp", static_libs: ["MyApp.impl"], optimize: { obfuscate: true, shrink_resources: true, }, } android_test { name: "MyAppTests", srcs: ["tests/**/*.java"], static_libs: ["MyApp.impl"], }This 3-module pattern lets
MyAppTestsrun as a self-instrumenting test with full access to internal classes, letsMyAppenableobfuscate: truefreely without breaking tests, avoids shipping test-only entry points in the production APK, and eliminates rebuildingMyAppwhen test code changes.Annotate test hooks with
@VisibleForTesting: If an external test APK calls a small number of internal methods or constructors on anandroid_apptarget and restructuring into an.impllibrary is impractical, annotate those declarations with@VisibleForTesting. The globalbuild/make/core/proguard.flagsbaseline retains@VisibleForTestingitems inandroid.**,com.android.**, andcom.google.android.**packages automatically without custom.flagsfiles. (For vendor modules outside these namespaces, use@UsedByReflectionor exported library rules.)Use
trace_references_fromacross platform library boundaries: When tests can't statically link the target implementation (for example, tests exercising system server services or platform JARs likeframework-connectivity), configuretrace_references_fromon the target module pointing to a Java library companion module containing the test sources. R8 traces and retains all classes and members referenced by the companion bytecode.
Step 3: Export rules from the owning library
If a shared java_library or android_library requires keep rules for its own
internal reflection or JNI callbacks, define the rules on the library target and
set export_proguard_flags_files: true:
java_library {
name: "my-shared-library",
srcs: ["src/**/*.java"],
optimize: {
proguard_flags_files: ["proguard.flags"],
export_proguard_flags_files: true,
},
}
All downstream android_app and library targets that statically link
my-shared-library inherit those rules automatically, so downstream apps don't
need to duplicate them. When multiple modules across different directories must
share a rule set that isn't tied to a single code library, publish the .flags
file through an explicit filegroup in Android.bp so modules can reference
:my-shared-flags cleanly across package boundaries. For general guidance on
authoring library consumer keep rules without restricting downstream app
optimization, see Optimization for library authors.
Step 4: Annotate declarations in source code
When a class, method, constructor, or field is accessed through reflection or
JNI and isn't covered by AAPT2 or global baselines, replace detached -keep
rules in .flags files with source annotations from the
Guide to Keep Annotations (see the
keepanno Javadoc reference):
@UsesReflection: Prefer this annotation when you control the code performing the reflection. Place it at the reflection call site to declare which target classes, methods, or fields are accessed dynamically. Because@UsesReflectionautomatically encodes a precondition that the annotated call site itself is reachable, R8 prunes both the caller and the reflective target if the call site is unused.@UsedByReflection: Place on classes, methods, fields, or constructors that are instantiated or invoked reflectively by external code or libraries, such as classes loaded withClass.forNamefromBundleorSettingskeys, or plugin classes loaded across dynamic classloaders. Specifykind(such asKeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition), and parameter constraints so R8 keeps only the exact reflective contract and can still optimize or prune unused members of the class. Don't add@UsedByReflectionto manifest-registered components likeJobServiceorBroadcastReceiver, because AAPT2 already keeps them.@UsedByNative: Place on methods or fields accessed from C or C++ JNI code usingGetMethodID,GetStaticMethodID, orGetFieldID.@KeepForApi: Place on library API classes or members that must remain intact when a library itself is shrunk before distribution.@Keep(androidx.annotation.Keep): Use as a fallback whenkeepannoisn't applicable. Applying@Keepto a class retains the class and all its members unconditionally. Applying@Keepto a method or field acts as an unconditional entry point that retains the member and its containing class even if the class is never instantiated, whereaskeepannoexpresses conditional reachability.
To use R8 keepanno annotations in a Soong module:
Add
"keepanno-annotations"tolibsinAndroid.bp:libs: [ "keepanno-annotations", ],Import
com.android.tools.r8.keepanno.annotations.*and annotate the declaration or call site in Java or Kotlin source code:import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByReflection; public final class CustomPluginController { @UsedByReflection( description = "Instantiated via Class.forName from plugin config", kind = KeepItemKind.CLASS_AND_METHODS) public CustomPluginController(Context context) { // ... } }R8 translates
keepannoannotations directly into its internal keep rule model and strips the annotations from the final DEX output, adding zero runtime bytecode overhead.
Avoid common pitfalls
The following sections describe frequent proguard.flags and keep.xml
pitfalls in platform code and how to fix them.
Broad component keep rules
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- Why it hurts performance: This rule is completely redundant with AAPT2.
Because it uses a wildcard without checking whether the component is
registered in the final merged
AndroidManifest.xml, it forces R8 to retain everyActivity,Service, orBroadcastReceiversubclass found anywhere on the classpath, including unused library components and disabled debug activities. - Recommended fix: Delete the rule. AAPT2 inspects the merged manifest and
generates exact
-keeprules for registered components.
Broad XML click handler keep rules
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- Why it hurts performance: Retaining every
public void *(View)method across every class in the module prevents R8 from stripping or inlining any method that happens to accept a singleViewparameter. - Recommended fix: Delete the rule. AAPT2 scans layout XML files and
generates targeted keep rules for methods referenced by
android:onClickattributes.
Broad View getter and setter keep rules
# Don't do this:
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
public *** get*();
}
- Why it hurts performance: This rule forces R8 to retain every getter and
setter across every
Viewsubclass in the app and all linked libraries (including AndroidX and Material libraries), blocking dead method removal and inlining across UI code. - Recommended fix: Delete the rule. AAPT2 already preserves constructors
for custom
Viewclasses inflated from layout XML files. If code animates a view property using reflective string names such asObjectAnimator.ofFloat(view, "translationZ", ...), replace the string name with a typed property reference (View.TRANSLATION_Zor a customFloatPropertyorIntPropertyimplementation) to avoid reflection entirely. If reflective property access can't be avoided, annotate the specific getter or setter with@UsedByReflection.
Blanket optimization or obfuscation disables
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Why it hurts performance: Placing
-dontoptimizeor-dontshrinkinside a.flagsfile silently overrides the module'sAndroid.bpsettings and disables optimization passes across the entire target. Worse, if a library exports a.flagsfile containing-dontoptimize, it disables R8 optimization for every downstreamandroid_appthat links the library. - Recommended fix: Remove
-dontoptimize,-dontshrink, and-dontobfuscatefrom.flagsfiles. Control optimization behavior explicitly inAndroid.bpusing theoptimizeblock (shrink,optimize,obfuscate) on the leaf target.
Diagnostic flags in committed rules
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- Why it hurts the build: Diagnostic flags flood build logs or attempt to write output files to local paths during sandboxed Soong builds.
- Recommended fix: Delete these flags from committed
.flagsfiles. Soong automatically writes R8 mapping and usage outputs, such asproguard_dictionaryandproguard_usage.zip, to the module's intermediate directory underout/soong/.intermediates/.
Production keep rules for test code
- Why it hurts performance: Adding custom
-keeprules solely for test access forces that code to remain un-obfuscated and retained in production builds. While annotating methods with@VisibleForTestingor configuringtrace_references_fromavoids maintaining manual-keeprules, those symbols still ship in the production binary. - Recommended fix: To keep test-only entry points completely out of the
production APK, structure the application into a
.impllibrary and link it into a self-instrumenting test APK usingstatic_libs, as described in Step 2: Migrate test-driven keep rules.
Blanket resource wildcards in keep.xml
<!-- Don't do this in res/raw/keep.xml: -->
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@raw/*,@drawable/*,@string/*" />
- Why it hurts performance: Blanket wildcards retain every resource in the
matching type across the module and its dependencies, defeating resource
shrinking (
shrink_resources: true) and inflating the APK and mappedresources.arsctable. - Recommended fix:
- Prefer static resource references over
keep.xml: Avoid using theResources.getIdentifiermethod to look up a bounded set of resources dynamically, such as numbered experiment strings or themed drawables. Instead, use a compile-timeswitchstatement or map over staticR.id,R.string, orR.drawableconstants. Static references let R8 and AAPT2 trace the exact live resources, eliminate runtime string lookup overhead, and remove the need forkeep.xmlaltogether. - List specific resource names: If dynamic lookup is required, such as
by a third-party license reader, list the exact resource identifiers in
tools:keep(for example,tools:keep="@raw/third_party_licenses"). - Delete redundant
keep.xmlfiles: If the listed resources are already referenced statically in code (R.raw.foo) or XML (@raw/foo), the shrinker retains them automatically, so you can deleteres/raw/keep.xml.
- Prefer static resource references over
Verify and audit rule changes
Whenever you remove or narrow keep rules in proguard.flags or keep.xml,
verify that the module builds cleanly, passes unit and instrumentation tests,
and retains all required entry points.
Build and test modules
Build the module cleanly to verify that R8 and AAPT2 complete without missing reference warnings:
m <MODULE_NAME>Run unit and instrumentation tests for the module using
atest:atest <TEST_MODULE_NAME>For system apps, privileged services, or hardware-dependent modules, run instrumentation and UI tests on target physical devices or in your device test lab to exercise runtime reflection paths, IPC bindings, and resource inflation.
Inspect DEX and resource diffs
Compare the compiled APK or JAR before and after rule changes to confirm that R8 removes dead code and resources without stripping expected entry points:
Use
apkanalyzerordexdumpto inspect retained classes, methods, and fields in the output APK or DEX files:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkWhen modifying
keep.xmlor enablingshrink_resources, useaapt2 dump resourcesto verify that the build strips unused resources and retains required ones:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
Analyze keep radius and rule subsumption with R8
The open-source R8 compiler includes a Keep Radius analyzer
(also exposed in Android Studio and Gradle as the
R8 Configuration Analyzer) that measures the exact
impact of every keep rule during compilation. Soong integrates this analyzer
directly into the Android platform build (configured in
build/soong/java/dex.go).
To analyze keep rules for a platform module or across an entire build:
Run the build with the
R8_DUMP_KEEP_RADIUS=trueenvironment variable:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>When
R8_DUMP_KEEP_RADIUS=trueis set, Soong instructs R8 to record keep rule metrics in an intermediater8keepradius.pbfile for each compiled module underout/soong/.intermediates/. For each keep rule andkeepannoannotation, R8 records:- Immediate keep radius: The exact classes, fields, and methods retained by the rule, along with the specific constraints it enforces against shrinking, optimization, or obfuscation.
- Rule subsumption: Which other keep rules or annotations already retain the same items. If a custom rule is completely subsumed by an AAPT2 rule or a global baseline rule, you can safely delete it.
- Package-wide and global rules: Rules that use broad package-wide wildcards or apply global configuration directives.
Convert the
r8keepradius.pboutput into an interactive HTML report usingKeepRadiusHtmlReportGenerator(bundled inprebuilts/r8/r8.jar):# Generate an HTML report for a single module INTERMEDIATES=out/soong/.intermediates/packages/apps/<APP_NAME>/<APP_NAME> java -cp prebuilts/r8/r8.jar \ com.android.tools.r8.keepradius.KeepRadiusHtmlReportGenerator \ $INTERMEDIATES/android_common/r8keepradius.pb \ keep_radius_report.html # Scan all built modules under out/soong/.intermediates and generate # per-module HTML reports plus an aggregate keepradius.html summary java -cp prebuilts/r8/r8.jar \ com.android.tools.r8.keepradius.KeepRadiusHtmlReportGenerator \ out/soong/.intermediates \ out/keep_radius_reportsWhen given a directory,
KeepRadiusHtmlReportGeneratorwalks all*keepradius*.pbfiles, generates an HTML report for each module, and createsout/keep_radius_reports/keepradius.htmlsummarizing live item counts, kept item counts, and the highest-radius keep rules across the build. For more information about interpreting shrinking, optimization, and obfuscation scores in the generated report, see Use R8 Configuration Analyzer.
Soong also supports two additional R8 diagnostic environment variables in
build/soong/java/dex.go:
R8_DUMP_INPUT=true: Writesr8inputs.zipto the module's intermediate directory containing all input JARs, library JARs, and merged ProGuard configurations for standalone R8 reproduction.R8_DUMP_PERFETTO_TRACE=true: Writesr8trace.ptraceto the module's intermediate directory for inspecting R8 compilation passes in Perfetto.
Validate library consumer rules
When a java_library or android_library exports keep rules to downstream
consumers (export_proguard_flags_files: true), those rules mustn't include
global flags that alter or disable optimization for the consuming app.
R8 provides an open-source keep rule analyzer
(ProcessKeepRules), exposed in the Android platform
build as the process-keep-rules host tool (defined in
prebuilts/r8/Android.bp):
# Build the R8 keep rules validator host binary
m process-keep-rules
# Validate one or more ProGuard configuration files
out/host/linux-x86/bin/process-keep-rules <PROGUARD_FLAGS_PATH>
The process-keep-rules tool parses each configuration file and fails with file
and line diagnostics if it encounters directives that are disallowed in library
consumer rules. Disallowed directives include global optimization, shrinking,
or obfuscation disables (such as -dontoptimize or -dontshrink), package
repackaging and access modification flags, diagnostic or mapping flags, and
app-level -keepattributes.
Audit source trees with pgaudit.py
To audit unbuilt source directories alongside R8's build-time analyzers, the
Android platform tree includes the pgaudit.py script under
build/make/core/proguard/tools/. This static analysis tool scans Android.bp,
proguard.flags, and keep.xml files across a repository to flag rules already
covered by AAPT2 or global platform baselines, broad wildcards, -dontoptimize
overrides, and test-only keep rules:
# Audit a single package directory
./build/make/core/proguard/tools/pgaudit.py packages/apps/Provision/
# Scan a subsystem tree and write a structured JSON report
./build/make/core/proguard/tools/pgaudit.py packages/ --json=audit_report.json
Platform and OEM teams can combine pgaudit.py for fast source-tree triage,
process-keep-rules to validate exported library rules, and
R8_DUMP_KEEP_RADIUS=true with KeepRadiusHtmlReportGenerator to measure the
exact class, field, and method retention radius of every rule in a build.