Das Build-System der Android-Plattform (Soong) führt den R8-Compiler für Ziele aus, die DEX-Bytecode kompilieren, einschließlich Android-Apps (android_app), Tests (android_test) und installierbarer Java-Bibliotheken mit compile_dex: true (z. B. services.jar), um ungenutzten Code und ungenutzte Ressourcen zu verkleinern, zu optimieren und zu entfernen. Bei statischen Bibliotheken (android_library und statische java_library) wird R8 von Soong nicht direkt ausgeführt, sondern der optimize-Eigenschaftsblock verwendet, um Consumer-Keep-Regeln (export_proguard_flags_files: true) an nachgelagerte DEX-Ziele anzuhängen und weiterzugeben, die sie statisch verknüpfen.
Für Plattformentwickler, die System-Images oder Anbieterpakete erstellen, bietet das Entfernen von zu weit gefassten Keep-Regeln direkte Vorteile für die Systemintegrität:
- Kleinerer Speicherbedarf der Systempartition: Mit R8 werden inaktive Klassen, Methoden und Ressourcen entfernt, bevor APKs und JARs auf
/system,/system_ext,/productund/vendorgepackt werden. - Kleinere kompilierte Artefakte: Weniger DEX-Methoden bedeuten kleinere
.odex- und.vdex-Dateien, die vondex2oatwährend der Kompilierung zur Build-Zeit oder auf dem Gerät generiert werden. - Geringere Speicherauslastung zur Laufzeit: Da Android
.odex,.vdexund APK-Ressourcentabellen mithilfe von Demand-Paging-Aufrufen (mmap) in den Prozessspeicher einbindet, werden durch kleinere Binärdateien schwerwiegende Seitenfehler beim App-Start reduziert und der residente Code- und Ressourcenspeicher pro Prozess verringert. Weitere Informationen dazu, wie sich kompilierter App-Code auf den Gerätespeicher auswirkt, finden Sie unter App-Code ist Speicher. - Effektivere Programmoptimierung: Mit eingeschränkten Keep-Regeln kann R8 Methoden inline einfügen, Schnittstellen- und virtuelle Aufrufe devirtualisieren, nicht verwendete Felder entfernen und Konstanten klassenübergreifend weitergeben.
R8-Optimierung in Soong konfigurieren
Konfigurieren Sie in Android.bp-Dateien die R8-Optimierung mit dem Attributblock optimize für android_app- und installierbare java_library-Ziele (oder für android_library- und statische java_library-Module, um Regeln für die Beibehaltung von Verbrauchern zu exportieren):
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
In der folgenden Tabelle sind die häufigsten optimize-Attribute in Soong zusammengefasst (definiert in build/soong/java/dex.go):
| Attribut | Beschreibung |
|---|---|
enabled |
Steuert, ob R8 für das Ziel ausgeführt wird. Standardmäßig wird true für alle android_app-Ziele verwendet.
|
shrink |
Steuert das Tree Shaking, um nicht erreichbare Klassen, Felder und Methoden zu entfernen. Der Standardwert ist true für android_app-Ziele (false für eigenständige java_library- und Testmodule, die -dontshrink übergeben, sofern nicht explizit festgelegt).
|
optimize |
Steuert Bytecode-Optimierungen wie das Inline-Setzen von Methoden, das Zusammenführen von Klassen, die Weitergabe von Konstanten und das Entfernen von nicht erreichbarem Code. Der Standardwert ist true für android_app-Ziele (gesteuert durch das Release-Build-Flag RELEASE_R8_OPTIMIZE_BY_DEFAULT).
|
obfuscate |
Steuert die Minimierung und Umbenennung von Kennungen. Der Standardwert ist false aus Gründen der Abwärtskompatibilität. Setzen Sie ihn jedoch nach Möglichkeit auf true, um die DEX-Größe zu reduzieren und umfassendere Optimierungen zu ermöglichen (siehe Verschleierung nach Möglichkeit aktivieren).
|
shrink_resources |
Entfernt nicht verwendete Ressourcen (res/-Einträge) aus dem gepackten APK nach der Codekomprimierung. Die Standardeinstellung ist false.
|
optimized_shrink_resources |
Führt die integrierte R8-Pipeline zum Verkleinern von Code und Ressourcen aus, sodass R8 Code- und Ressourcenreferenzen gemeinsam in einem einzigen Durchlauf verfolgt. Wenn shrink_resources: true festgelegt ist, wird standardmäßig RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT verwendet (true in Standard-Plattform-Builds).
|
proguard_flags_files |
Listet modulspezifische .flags- oder .pro-Dateien mit benutzerdefinierten Keep-Regeln auf. Fügen Sie keine benutzerdefinierten Dateien hinzu, wenn Standardanmerkungen oder Standardwerte ausreichen.
|
export_proguard_flags_files |
Gibt die proguard_flags_files dieser Bibliothek an nachgelagerte Module weiter, die statisch davon abhängen.
|
trace_references_from |
Listet Java-Bibliotheksbegleitziele auf, deren Bytecode-Verweise in dieses Ziel automatisch von R8 verfolgt und beibehalten werden. |
Verschleierung aktivieren, wo immer möglich
In Soong ist obfuscate aus Gründen der Abwärtskompatibilität standardmäßig auf false festgelegt. Sie sollten obfuscate: true jedoch nach Möglichkeit explizit für android_app- und eigenständige DEX-Ziele festlegen:
- Kleinerer DEX- und
.vdex-Speicherbedarf: Durch das Umbenennen von Paketen, Klassen, Feldern und Methoden in kurze Kennungen (a,b) wird der DEX-Stringpool (string_idsundstring_data_item) und die Typdeskriptoren verkleinert. Da Android.vdex- und.odex-Dateien in den Prozessspeicher einbindet, werden durch kleinere Symboltabellen sowohl die Größe der Systempartition als auch der Laufzeitspeicherbedarf direkt reduziert. - Umfassendere Optimierungen des gesamten Programms: Wenn R8 Bezeichner umbenennen darf, können Klassen zusammengeführt, Pakete vereinfacht und synthetische Klassen in Paketen dedupliziert werden, die R8 andernfalls überspringen müsste, um Namenskonflikte zu vermeiden.
- Symbolisierung des vollständigen Stacktrace: Wenn Sie die Verschleierung in Soong aktivieren, wird die Debugging-Fähigkeit nicht eingeschränkt. Für jedes R8-kompilierte Ziel gibt Soong eine
proguard_dictionary-Zuordnungsdatei im Zwischenverzeichnis des Moduls aus, bündelt alle Modulverzeichnisse improguard-dict.zip-Artefakt des Builds, bettet einen Zuordnungshash (--map-id-template) in den DEX-Header ein und schreibt die Attribute der KlasseSourceFile(--source-file-template) so um, dassretraceStacktraces automatisch symbolisieren kann.
Behalten Sie obfuscate: false nur für Folgendes bei (oder behalten Sie öffentliche API-Namen explizit bei):
- Gemeinsam genutzte Bibliotheken im Bootclasspath oder
system_server-Klassenpfad: Module (java_libraryoderjava_sdk_library), die eine externe API bereitstellen, die zur Laufzeit dynamisch von anderen Modulen verknüpft wird (z. B.framework.jar-,services.jar- oder<uses-library>-Ziele), müssen entwederobfuscate: falsebeibehalten oder ihre API-Oberfläche explizit mit@KeepForApi- oder-keep-Regeln (zusammen mitprotect_api_surface: truefür Bootclasspath-Ziele) beibehalten, damit Aufrufer, die für ihre Stubs kompiliert wurden, Klassen- und Mitgliedsnamen zur Laufzeit auflösen können.
Prüfen Sie vor der Aktivierung von obfuscate: true für eine Anwendung die folgenden Migrationsvoraussetzungen:
- Externe Test-APK-Abhängigkeiten: Wenn ein externes
android_test-APK dieinstrumentation_for: "MyApp"festlegt und interne Klassen oder Methoden vonMyAppdirekt aufruft, führt das Umbenennen dieser Symbole zur Laufzeit des Tests zuNoSuchMethodErroroderNoClassDefFoundError. Strukturieren Sie den Test vorzugsweise als selbstinstrumentierendes APK, dasMyApp.implstatisch verknüpft, annotieren Sie Testhooks mit@VisibleForTestingoder konfigurieren Sietrace_references_from(siehe Schritt 2: Testgesteuerte Keep-Regeln migrieren), damit interne Symbole, die für Tests erforderlich sind, beibehalten werden, während der Rest der App verschleiert wird. - Stringbasierte Reflexion und JNI: Wenn in einem Modul Klassen, Methoden oder Felder anhand von Literalstringnamen (
Class.forName,getDeclaredMethododer JNIFindClassundGetMethodID) ohne Keep-Regeln oder Annotationen gesucht wird, werden diese Ziele durch die Verschleierung umbenannt und Laufzeitsuchen funktionieren nicht mehr. Hinweis: Nicht annotierte Reflexionen schlagen auch untershrink: trueundoptimize: truefehl. Annotieren Sie diese Einstiegspunkte mit Guide to Keep Annotations (@UsesReflection,@UsedByReflectionoder@UsedByNative), damit R8 ihre Namen beibehält und den Rest des Moduls verschleiert.
Prinzip „Keine benutzerdefinierten Flags“ beachten
Das ideale Android-Plattformmodul enthält keine benutzerdefinierten proguard.flags- oder keep.xml-Dateien. In der Android-Plattform sind die meisten benutzerdefinierten Keep-Regeln redundant:
- Plattform-Baselines und AAPT2: Die meisten Einstiegspunkte werden bereits automatisch durch globale Plattform-Baselines (z. B.
@Keep, JNI-Methodennativeund@VisibleForTesting) beibehalten oder von AAPT2 ausAndroidManifest.xml- und Layoutressourcen generiert (siehe Standardregeln für das Beibehalten von Plattformen). - Gezielte Alternativen: Wenn Einstiegspunkte beibehalten werden müssen, sollten Sie Anmerkungen am Deklarationsort (
keepanno,@VisibleForTesting), exportierte Bibliotheksregeln (export_proguard_flags_files: true) oder statische Testverknüpfungen gegenüber separaten.flags-Dateien bevorzugen (siehe Vorhandene Keep-Regeln prüfen und migrieren).
Bevor Sie eine benutzerdefinierte proguard.flags- oder keep.xml-Datei hinzufügen oder beibehalten, prüfen Sie, ob die Regel bereits von Standardbaselines abgedeckt wird oder zu Codeanmerkungen migriert werden kann.
Standardmäßige Aufbewahrungsregeln für die Plattform
Soong übergibt automatisch die folgenden globalen Basisregeln an jeden R8-Aufruf für DEX-Kompilierungsziele (android_app, android_test und installierbare java_library-Module), die in build/soong/java/dex.go konfiguriert sind:
build/make/core/proguard.flags: Behält Klassen und Elemente bei, die mit@com.android.internal.annotations.VisibleForTestingin allen Paketen und mit@VisibleForTesting(androidx.annotation.VisibleForTestingodercom.google.common.annotations.VisibleForTesting) in den Paketenandroid.**,com.android.**undcom.google.android.**annotiert sind. Außerdem werden@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallbackund@dalvik.annotation.optimization.**beibehalten.build/make/core/proguard_basic_keeps.flags: BehältSourceFile-Attribute für Stacktraces, Laufzeit-Sichtbarkeitsanmerkungen (RuntimeVisible*Annotations),Exceptions- undAnnotationDefault-Attribute,native-Methoden,Serializable-Elemente,@JavascriptInterface-Methoden,Throwable(String)-Konstruktoren,Parcelable$CREATOR-Felder und Protobuf-MessageLite-Felder bei.build/make/core/proguard/kotlin.flags: Unterdrückt harmlose Warnungen für bestimmte Kotlin-Meta-Annotationen (kotlin.Metadataundkotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) und entfernt Kotlin-DebugMetadata-Annotationen in Release-Builds.build/make/core/proguard/checknotnull.flags: Ersetzt allgemeine Hilfsaufrufe für die Nullprüfung (com.google.common.base.Preconditions.checkNotNullunddagger.internal.Preconditions.checkNotNull*) durch prägnante Bytecode-Nullprüfungen. In dieser Datei wirdObjects.requireNonNullabsichtlich ausgelassen, um explizite Fehlermeldungen über Framework-API-Grenzen hinweg beizubehalten.build/make/core/proguard/enumvalues.flags: Behält die MethodenvaluesundvalueOffürenum-Typen bei, sofern sie nicht durch die Build-Konfiguration deaktiviert werden.- Automatisch generierte AAPT2-Regeln: AAPT2 prüft zusammengeführte
AndroidManifest.xml-, Layout-XML- und Preference-XML-Dateien, um genaue Keep-Regeln für jede registrierteActivity-,Service-,BroadcastReceiver-,ContentProvider-,BackupAgent-,Application-, benutzerdefinierteView-Unterklasse,Preference-Unterklasse und XML-android:onClick-Methode zu generieren.
Vorhandene Aufbewahrungsregeln prüfen und migrieren
Wenn Sie vorhandene proguard.flags- oder keep.xml-Dateien in einem Plattformrepository prüfen, bewerten Sie jede Regel in der Reihenfolge anhand der folgenden vierstufigen Hierarchie:
Schritt 1: Redundante oder veraltete Regeln löschen
Löschen Sie Regeln, die bereits von globalen Baselines, AAPT2-Manifest- und Layoutregeln oder R8-Standardeinstellungen abgedeckt werden, sowie Regeln, die auf nicht mehr vorhandene Klassen oder Pakete verweisen.
Wenn alle Regeln in einer .flags-Datei redundant sind, löschen Sie die Datei und entfernen Sie proguard_flags_files aus Android.bp. Wenn im verbleibenden optimize-Block nur Standardeinstellungen wiederholt werden, entfernen Sie den redundanten Block und formatieren Sie die Build-Datei mit bpfmt -w Android.bp. Prüfen Sie beim Bereinigen eines Pakets, ob Companion-Module in Unterverzeichnissen (z. B. Kotlin-Zielvarianten) auf dieselbe Flags-Datei verweisen, und aktualisieren Sie sie gemeinsam.
Schritt 2: Testbasierte Aufbewahrungsregeln migrieren
Verschieben Sie testgesteuerte Keep-Regeln aus benutzerdefinierten .flags-Dateien für die Produktion mit einem der folgenden Muster:
Implementierungsbibliothek in Tests einbinden (
static_libs): Wenn einandroid_testpaketprivate oder interne Implementierungsdetails einer App verwendet, wird empfohlen, die App-Quelldateien in einemandroid_library(MyApp.impl) zu platzieren undMyApp.implstatisch inMyAppundMyAppTestseinzubinden: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"], }Dieses Muster mit drei Modulen ermöglicht es,
MyAppTestsals selbstinstrumentierenden Test mit vollem Zugriff auf interne Klassen auszuführen,MyAppkannobfuscate: truefrei aktivieren, ohne Tests zu unterbrechen, es werden keine reinen Test-Einstiegspunkte im Produktions-APK ausgeliefert undMyAppmuss nicht neu erstellt werden, wenn sich der Testcode ändert.Testhooks mit
@VisibleForTestingannotieren: Wenn ein externes Test-APK eine kleine Anzahl interner Methoden oder Konstruktoren für einandroid_app-Ziel aufruft und eine Umstrukturierung in eine.impl-Bibliothek nicht praktikabel ist, annotieren Sie diese Deklarationen mit@VisibleForTesting. In der globalenbuild/make/core/proguard.flags-Baseline werden@VisibleForTesting-Elemente in den Paketenandroid.**,com.android.**undcom.google.android.**automatisch beibehalten, ohne dass benutzerdefinierte.flags-Dateien erforderlich sind. Bei Anbietermodulen außerhalb dieser Namespaces verwenden Sie@UsedByReflectionoder exportierte Bibliotheksregeln.trace_references_fromüber Plattformbibliotheksgrenzen hinweg verwenden: Wenn Tests die Zielimplementierung nicht statisch verknüpfen können (z. B. Tests für Systemserverdienste oder Plattform-JARs wieframework-connectivity), konfigurieren Sietrace_references_fromfür das Zielmodul, das auf ein Java-Bibliotheksbegleitmodul mit den Testquellen verweist. R8 verfolgt und behält alle Klassen und Elemente bei, auf die im Companion-Bytecode verwiesen wird.
Schritt 3: Regeln aus der Inhaberbibliothek exportieren
Wenn für ein gemeinsam genutztes java_library oder android_library Keep-Regeln für die eigene interne Reflektion oder JNI-Rückrufe erforderlich sind, definieren Sie die Regeln für das Bibliotheksziel und legen Sie export_proguard_flags_files: true fest:
java_library {
name: "my-shared-library",
srcs: ["src/**/*.java"],
optimize: {
proguard_flags_files: ["proguard.flags"],
export_proguard_flags_files: true,
},
}
Alle nachgelagerten android_app- und Bibliotheksziele, die statisch verknüpft werden, my-shared-library übernehmen diese Regeln automatisch. Nachgelagerte Apps müssen sie also nicht duplizieren. Wenn mehrere Module in verschiedenen Verzeichnissen einen Regelsatz verwenden müssen, der nicht an eine einzelne Codebibliothek gebunden ist, veröffentlichen Sie die Datei .flags über ein explizites filegroup in Android.bp, damit Module sauber über Paketgrenzen hinweg auf :my-shared-flags verweisen können. Allgemeine Informationen zum Erstellen von Keep-Regeln für Bibliotheksnutzer, ohne die Optimierung von Downstream-Apps einzuschränken, finden Sie unter Optimierung für Bibliotheksautoren.
Schritt 4: Deklarationen im Quellcode mit Anmerkungen versehen
Wenn auf eine Klasse, Methode, einen Konstruktor oder ein Feld über Reflection oder JNI zugegriffen wird und diese nicht von AAPT2 oder globalen Baselines abgedeckt werden, ersetzen Sie die getrennten -keep-Regeln in .flags-Dateien durch Quellannotationen aus dem Leitfaden zu Keep-Annotationen (siehe keepanno-Javadoc-Referenz):
@UsesReflection: Verwenden Sie diese Annotation, wenn Sie den Code steuern, der die Reflektion ausführt. Platzieren Sie sie an der Stelle des Reflexionsaufrufs, um zu deklarieren, auf welche Zielklassen, Methoden oder Felder dynamisch zugegriffen wird. Da@UsesReflectionautomatisch eine Vorbedingung dafür codiert, dass die annotierte Aufrufstelle selbst erreichbar ist, entfernt R8 sowohl den Aufrufer als auch das reflektive Ziel, wenn die Aufrufstelle nicht verwendet wird.@UsedByReflection: Wird für Klassen, Methoden, Felder oder Konstruktoren verwendet, die durch externen Code oder Bibliotheken reflektierend instanziiert oder aufgerufen werden, z. B. Klassen, die mitClass.forNameausBundle- oderSettings-Schlüsseln geladen werden, oder Plugin-Klassen, die über dynamische Classloader geladen werden. Geben Siekind(z. B.KeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition) und Parameterbeschränkungen an, damit R8 nur den genauen reflektierenden Vertrag beibehält und weiterhin ungenutzte Elemente der Klasse optimieren oder entfernen kann. Fügen Sie@UsedByReflectionnicht zu im Manifest registrierten Komponenten wieJobServiceoderBroadcastReceiverhinzu, da AAPT2 sie bereits beibehält.@UsedByNative: Wird für Methoden oder Felder verwendet, auf die über C- oder C++-JNI-Code mitGetMethodID,GetStaticMethodIDoderGetFieldIDzugegriffen wird.@KeepForApi: Platzieren Sie diese Option für API-Klassen oder ‑Elemente der Bibliothek, die intakt bleiben müssen, wenn eine Bibliothek vor der Verteilung verkleinert wird.@Keep(androidx.annotation.Keep): Als Fallback verwenden, wennkeepannonicht zutrifft. Wenn Sie@Keepauf eine Klasse anwenden, bleiben die Klasse und alle ihre Mitglieder bedingungslos erhalten. Wenn Sie@Keepauf eine Methode oder ein Feld anwenden, fungiert dies als bedingungsloser Einstiegspunkt, der das Element und die zugehörige Klasse beibehält, auch wenn die Klasse nie instanziiert wird.keepannodrückt dagegen die bedingte Erreichbarkeit aus.
So verwenden Sie R8-keepanno-Annotationen in einem Soong-Modul:
So fügen Sie
"keepanno-annotations"zulibsinAndroid.bphinzu:libs: [ "keepanno-annotations", ],Importieren Sie
com.android.tools.r8.keepanno.annotations.*und fügen Sie der Deklaration oder dem Aufruf in Java- oder Kotlin-Quellcode eine Annotation hinzu: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 übersetzt
keepanno-Annotationen direkt in sein internes Modell für Keep-Regeln und entfernt die Annotationen aus der endgültigen DEX-Ausgabe. Dadurch entsteht kein zusätzlicher Bytecode-Overhead zur Laufzeit.
Häufige Fehler vermeiden
In den folgenden Abschnitten werden häufige proguard.flags- und keep.xml-Fehler im Plattformcode und ihre Behebung beschrieben.
Allgemeine Regeln zum Beibehalten von Komponenten
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- Warum die Leistung beeinträchtigt wird: Diese Regel ist in AAPT2 vollständig redundant.
Da ein Platzhalter verwendet wird, ohne zu prüfen, ob die Komponente in der endgültigen zusammengeführten
AndroidManifest.xmlregistriert ist, zwingt dies R8, jedeActivity-,Service- oderBroadcastReceiver-Unterklasse beizubehalten, die sich irgendwo im Klassenpfad befindet, einschließlich ungenutzter Bibliothekskomponenten und deaktivierter Debugging-Aktivitäten. - Empfohlene Fehlerbehebung: Löschen Sie die Regel. AAPT2 prüft das zusammengeführte Manifest und generiert genaue
-keep-Regeln für registrierte Komponenten.
Allgemeine Regeln für XML-Klickhandler beibehalten
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- Warum die Leistung beeinträchtigt wird: Wenn jede
public void *(View)-Methode in jeder Klasse im Modul beibehalten wird, kann R8 keine Methode entfernen oder inline einfügen, die einen einzelnenView-Parameter akzeptiert. - Empfohlene Fehlerbehebung: Löschen Sie die Regel. AAPT2 scannt Layout-XML-Dateien und generiert gezielte Keep-Regeln für Methoden, auf die von
android:onClick-Attributen verwiesen wird.
Regeln für Getter und Setter für die breite Ansicht
# 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*();
}
- Warum die Leistung beeinträchtigt wird: Diese Regel zwingt R8, alle Getter und Setter in jeder
View-Unterklasse in der App und allen verknüpften Bibliotheken (einschließlich AndroidX- und Material-Bibliotheken) beizubehalten. Dadurch wird das Entfernen von nicht verwendeten Methoden und das Inlining im gesamten UI-Code verhindert. - Empfohlene Fehlerbehebung: Löschen Sie die Regel. AAPT2 behält bereits Konstruktoren für benutzerdefinierte
View-Klassen bei, die aus Layout-XML-Dateien instanziiert werden. Wenn in Code eine Ansichtseigenschaft mit reflektierenden String-Namen wieObjectAnimator.ofFloat(view, "translationZ", ...)animiert wird, ersetzen Sie den String-Namen durch eine typisierte Eigenschaftsreferenz (View.TRANSLATION_Zoder eine benutzerdefinierteFloatProperty- oderIntProperty-Implementierung), um die Reflektion vollständig zu vermeiden. Wenn der Zugriff auf reflektierende Eigenschaften nicht vermieden werden kann, annotieren Sie den jeweiligen Getter oder Setter mit@UsedByReflection.
Globale Optimierung oder Verschleierung deaktiviert
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Warum die Leistung beeinträchtigt wird: Wenn Sie
-dontoptimizeoder-dontshrinkin eine.flags-Datei einfügen, werden dieAndroid.bp-Einstellungen des Moduls im Hintergrund überschrieben und Optimierungsdurchläufe für das gesamte Ziel deaktiviert. Noch schlimmer: Wenn eine Bibliothek eine.flags-Datei mit-dontoptimizeexportiert, wird die R8-Optimierung für alle nachgelagertenandroid_appdeaktiviert, die die Bibliothek verknüpfen. - Empfohlene Lösung: Entfernen Sie
-dontoptimize,-dontshrinkund-dontobfuscateaus den.flags-Dateien. Das Optimierungsverhalten kann inAndroid.bpmithilfe desoptimize-Blocks (shrink,optimize,obfuscate) für das untergeordnete Zielvorhaben explizit gesteuert werden.
Diagnose-Flags in zugesicherten Regeln
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- Warum es den Build beeinträchtigt: Diagnose-Flags überfluten Build-Logs oder versuchen, Ausgabedateien während der Soong-Builds in der Sandbox in lokale Pfade zu schreiben.
- Empfohlene Korrektur: Löschen Sie diese Flags aus den übertragenen
.flags-Dateien. Soong schreibt automatisch R8-Mapping- und Nutzungsausgaben wieproguard_dictionaryundproguard_usage.zipin das Zwischenverzeichnis des Moduls unterout/soong/.intermediates/.
Regeln zum Beibehalten von Testcode in der Produktionsumgebung
- Warum die Leistung beeinträchtigt wird: Wenn Sie benutzerdefinierte
-keep-Regeln nur für den Testzugriff hinzufügen, muss der Code in Produktions-Builds unverschleiert und beibehalten werden. Wenn Sie Methoden mit@VisibleForTestingannotieren odertrace_references_fromkonfigurieren, müssen Sie keine manuellen-keep-Regeln mehr verwalten. Die entsprechenden Symbole sind jedoch weiterhin in der Produktions-Binärdatei enthalten. - Empfohlene Lösung: Damit Test-only-Einstiegspunkte vollständig aus dem Produktions-APK entfernt werden, strukturieren Sie die Anwendung in eine
.impl-Bibliothek und verknüpfen Sie sie mit einem selbstinstrumentierenden Test-APK überstatic_libs, wie in Schritt 2: Testgesteuerte Keep-Regeln migrieren beschrieben.
Alles einschließende Platzhalter für Ressourcen 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/*" />
- Warum sich das negativ auf die Leistung auswirkt: Durch Platzhalter werden alle Ressourcen des entsprechenden Typs im Modul und seinen Abhängigkeiten beibehalten. Dadurch wird die Ressourcenverkleinerung (
shrink_resources: true) verhindert und die APK-Datei und die zugeordneteresources.arsc-Tabelle werden aufgebläht. - Empfohlene Korrektur:
- Statische Ressourcenreferenzen gegenüber
keep.xmlbevorzugen: Vermeiden Sie die Verwendung der MethodeResources.getIdentifier, um eine begrenzte Menge von Ressourcen dynamisch zu suchen, z. B. nummerierte Test-Strings oder thematische Drawables. Verwenden Sie stattdessen eineswitch-Anweisung zur Kompilierzeit oder ordnen Sie statischeR.id-,R.string- oderR.drawable-Konstanten zu. Statische Verweise ermöglichen es R8 und AAPT2, die genauen Live-Ressourcen zu verfolgen, den Overhead für die Laufzeit-Stringsuche zu eliminieren und die Notwendigkeit vonkeep.xmlzu beseitigen. - Bestimmte Ressourcennamen auflisten: Wenn eine dynamische Suche erforderlich ist, z. B. durch einen Lizenzleser eines Drittanbieters, listen Sie die genauen Ressourcen-IDs in
tools:keepauf (z. B.tools:keep="@raw/third_party_licenses"). - Redundante
keep.xml-Dateien löschen: Wenn auf die aufgeführten Ressourcen bereits statisch im Code (R.raw.foo) oder in XML (@raw/foo) verwiesen wird, werden sie vom Shrinker automatisch beibehalten. Sie können alsores/raw/keep.xmllöschen.
- Statische Ressourcenreferenzen gegenüber
Regeländerungen überprüfen und prüfen
Wenn Sie Keep-Regeln in proguard.flags oder keep.xml entfernen oder einschränken, prüfen Sie, ob das Modul fehlerfrei erstellt wird, Unit- und Instrumentationstests bestanden werden und alle erforderlichen Einstiegspunkte beibehalten werden.
Module erstellen und testen
Erstellen Sie das Modul ohne Fehler, um zu prüfen, ob R8 und AAPT2 ohne Warnungen zu fehlenden Referenzen abgeschlossen werden:
m <MODULE_NAME>Führen Sie mit
atestUnit- und Instrumentierungstests für das Modul aus:atest <TEST_MODULE_NAME>Führen Sie für System-Apps, privilegierte Dienste oder hardwareabhängige Module Instrumentierungs- und UI-Tests auf physischen Zielgeräten oder in Ihrem Gerätetestlabor aus, um Laufzeit-Reflexionspfade, IPC-Bindungen und die Ressourceninflation zu testen.
DEX- und Ressourcendifferenzen prüfen
Vergleichen Sie das kompilierte APK oder JAR vor und nach den Regeländerungen, um zu bestätigen, dass R8 nicht verwendeten Code und Ressourcen entfernt, ohne erwartete Einstiegspunkte zu entfernen:
Verwenden Sie
apkanalyzeroderdexdump, um beibehaltene Klassen, Methoden und Felder in den Ausgabedateien (APK oder DEX) zu prüfen:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkWenn Sie
keep.xmländern odershrink_resourcesaktivieren, verwenden Sieaapt2 dump resources, um zu prüfen, ob beim Build nicht verwendete Ressourcen entfernt und erforderliche Ressourcen beibehalten werden:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
Keep-Radius und Regelunterordnung mit R8 analysieren
Der Open-Source-R8-Compiler enthält einen Keep-Radius-Analyzer (auch in Android Studio und Gradle als R8 Configuration Analyzer verfügbar), der die genauen Auswirkungen jeder Keep-Regel während der Kompilierung misst. Soong integriert diesen Analyzer direkt in den Android-Plattform-Build (konfiguriert in build/soong/java/dex.go).
So analysieren Sie Keep-Regeln für ein Plattformmodul oder für den gesamten Build:
Führen Sie den Build mit der Umgebungsvariable
R8_DUMP_KEEP_RADIUS=trueaus:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>Wenn
R8_DUMP_KEEP_RADIUS=truefestgelegt ist, weist Soong R8 an, Messwerte für Keep-Regeln in einer temporärenr8keepradius.pb-Datei für jedes kompilierte Modul unterout/soong/.intermediates/aufzuzeichnen. Für jede Keep-Regel undkeepanno-Annotation zeichnet R8 Folgendes auf:- Unmittelbarer Beibehaltungsradius: Die genauen Klassen, Felder und Methoden, die durch die Regel beibehalten werden, sowie die spezifischen Einschränkungen, die sie in Bezug auf das Verkleinern, Optimieren oder Verschleiern erzwingt.
- Regelunterordnung: Welche anderen Aufbewahrungsregeln oder Annotationen dieselben Elemente bereits beibehalten. Wenn eine benutzerdefinierte Regel vollständig von einer AAPT2-Regel oder einer globalen Baseline-Regel abgedeckt wird, können Sie sie gefahrlos löschen.
- Paketweite und globale Regeln: Regeln, die breite paketweite Platzhalter verwenden oder globale Konfigurationsanweisungen anwenden.
Konvertieren Sie die
r8keepradius.pb-Ausgabe mitKeepRadiusHtmlReportGenerator(inprebuilts/r8/r8.jarenthalten) in einen interaktiven HTML-Bericht:# 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_reportsWenn ein Verzeichnis angegeben wird, durchläuft
KeepRadiusHtmlReportGeneratoralle*keepradius*.pb-Dateien, generiert für jedes Modul einen HTML-Bericht und erstelltout/keep_radius_reports/keepradius.htmlmit einer Zusammenfassung der Anzahl der Live-Elemente, der Anzahl der beibehaltenen Elemente und der Keep-Regeln mit dem größten Radius im gesamten Build. Weitere Informationen zum Interpretieren von Werten für das Verkleinern, Optimieren und Verschleiern im generierten Bericht finden Sie unter R8 Configuration Analyzer verwenden.
Soong unterstützt auch zwei zusätzliche R8-Diagnoseumgebungsvariablen in build/soong/java/dex.go:
R8_DUMP_INPUT=true: Schreibtr8inputs.zipin das Zwischenverzeichnis des Moduls, das alle Eingabe-JARs, Bibliotheks-JARs und zusammengeführten ProGuard-Konfigurationen für die eigenständige R8-Reproduktion enthält.R8_DUMP_PERFETTO_TRACE=true: Schreibtr8trace.ptracein das Zwischendateiverzeichnis des Moduls, um R8-Kompilierungsdurchläufe in Perfetto zu prüfen.
Regeln für Bibliotheksnutzer validieren
Wenn bei java_library- oder android_library-Exporten Regeln an nachgelagerte Nutzer (export_proguard_flags_files: true) weitergegeben werden, dürfen diese Regeln keine globalen Flags enthalten, die die Optimierung für die Nutzer-App ändern oder deaktivieren.
R8 bietet einen Open-Source-Analyzer für Keep-Regeln (ProcessKeepRules), der im Android-Plattform-Build als process-keep-rules-Host-Tool (definiert in prebuilts/r8/Android.bp) verfügbar ist:
# 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>
Das Tool process-keep-rules parst jede Konfigurationsdatei und gibt Datei- und Zeilendiagnosen aus, wenn es auf Anweisungen stößt, die in Regeln für Bibliotheksnutzer nicht zulässig sind. Nicht zulässige Direktiven sind unter anderem globale Optimierungs-, Verkleinerungs- oder Verschleierungs-Deaktivierungen (z. B. -dontoptimize oder -dontshrink), Flags für das Neuverpacken von Paketen und die Zugriffsänderung, Diagnose- oder Mapping-Flags sowie -keepattributes auf App-Ebene.
Quellbäume mit pgaudit.py prüfen
Wenn Sie ungebaute Quellverzeichnisse zusammen mit den Build-Time-Analysetools von R8 prüfen möchten, enthält der Android-Plattformbaum das pgaudit.py-Script unter build/make/core/proguard/tools/. Dieses Tool für die statische Analyse scannt Android.bp-, proguard.flags- und keep.xml-Dateien in einem Repository, um Regeln zu kennzeichnen, die bereits von AAPT2 oder globalen Plattform-Baselines, breiten Platzhaltern, -dontoptimize-Überschreibungen und Keep-Regeln nur für Tests abgedeckt werden:
# 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
Plattform- und OEM-Teams können pgaudit.py für die schnelle Triage des Quellbaums, process-keep-rules zum Validieren exportierter Bibliotheksregeln und R8_DUMP_KEEP_RADIUS=true mit KeepRadiusHtmlReportGenerator kombinieren, um den genauen Beibehaltungsradius von Klassen, Feldern und Methoden für jede Regel in einem Build zu messen.