Il sistema di compilazione della piattaforma Android (Soong) esegue il compilatore R8 su
target che compilano bytecode DEX, incluse app per Android (android_app), test
(android_test) e librerie Java installabili con compile_dex: true (ad esempio
services.jar), per ridurre, ottimizzare ed eliminare codice e risorse inutilizzati. Nelle
librerie statiche (android_library e static java_library), Soong non
esegue R8 direttamente, ma utilizza il blocco di proprietà optimize per collegare e propagare
le regole di conservazione dei consumer (export_proguard_flags_files: true) ai target DEX downstream
che li collegano staticamente.
Per gli ingegneri di piattaforma che creano immagini di sistema o pacchetti del fornitore, l'eliminazione di regole di conservazione eccessivamente ampie offre vantaggi diretti per l'integrità del sistema:
- Ingombro ridotto della partizione di sistema: R8 rimuove classi, metodi e risorse non utilizzati prima di comprimere APK e JAR in
/system,/system_ext,/producte/vendor. - Artefatti compilati più piccoli: meno metodi DEX significano file
.odexe.vdexgenerati dadex2oatdurante la compilazione in fase di build o sul dispositivo. - Minore pressione sulla memoria di runtime: poiché Android mappa
.odex,.vdexe le tabelle delle risorse APK nella memoria di processo utilizzando chiamatemmapcon paging su richiesta, i binari più piccoli riducono gli errori di pagina principali durante l'avvio dell'app e la memoria di codice e risorse residente nei processi. Per ulteriori informazioni su come il codice dell'app compilato influisce sulla memoria del dispositivo, vedi Il codice dell'app è memoria. - Ottimizzazione più efficace dell'intero programma: i vincoli di conservazione ristretti consentono a R8 di incorporare i metodi, devirtualizzare l'interfaccia e le chiamate virtuali, eliminare i campi inutilizzati e propagare le costanti tra le classi.
Configurare l'ottimizzazione R8 in Soong
Nei file Android.bp, configura l'ottimizzazione R8 utilizzando il blocco di proprietà optimize nei target android_app e java_library installabili (o nei moduli android_library e java_library statici per esportare le regole di conservazione dei consumatori):
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
La tabella seguente riepiloga le proprietà optimize più comuni in Soong
(definite in build/soong/java/dex.go):
| Proprietà | Descrizione |
|---|---|
enabled |
Controlla se R8 viene eseguito sulla destinazione. Il valore predefinito è true
per tutte le destinazioni android_app.
|
shrink |
Controlla il tree shaking per rimuovere classi, campi e
metodi non raggiungibili. Il valore predefinito è true per i target android_app (false per i moduli di test e java_library autonomi, che superano -dontshrink se non impostato esplicitamente).
|
optimize |
Controlla le ottimizzazioni del bytecode, come l'incorporamento dei metodi, l'unione delle classi, la propagazione delle costanti e la rimozione dei rami non raggiungibili. Il valore predefinito è
true per i target android_app (controllati dal
flag di build di release RELEASE_R8_OPTIMIZE_BY_DEFAULT).
|
obfuscate |
Controlla la minimizzazione e la ridenominazione degli identificatori. Il valore predefinito è
false per la compatibilità storica, ma impostalo su
true ove possibile per ridurre le dimensioni del file DEX e sbloccare
ottimizzazioni più approfondite (vedi
Attiva l'offuscamento ove possibile).
|
shrink_resources |
Rimuove le risorse inutilizzate (voci res/) dall'APK
pacchettizzato dopo la riduzione del codice. Il valore predefinito è false.
|
optimized_shrink_resources |
Esegue la pipeline integrata di riduzione del codice e delle risorse R8 in modo che R8 tracci
il codice e i riferimenti alle risorse congiuntamente in un unico passaggio. Quando
shrink_resources: true è impostato, il valore predefinito è
RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT
(true nelle build della piattaforma standard).
|
proguard_flags_files |
Elenca i file .flags o .pro specifici del modulo
contenenti regole di conservazione personalizzate. Evita di aggiungere file personalizzati quando sono sufficienti
annotazioni o valori predefiniti standard.
|
export_proguard_flags_files |
Propaga proguard_flags_files di questa libreria ai moduli downstream che dipendono staticamente da essa.
|
trace_references_from |
Elenca i target complementari della libreria Java i cui riferimenti bytecode in questo target R8 vengono tracciati e conservati automaticamente. |
Abilita l'offuscamento ove possibile
In Soong, obfuscate è impostato su false per compatibilità storica, ma
dovresti impostare esplicitamente obfuscate: true su android_app e sui target DEX autonomi
ove possibile:
- Impronta DEX e
.vdexpiù piccola: la ridenominazione di pacchetti, classi, campi e metodi in identificatori brevi (a,b) riduce il pool di stringhe DEX (string_idsestring_data_item) e i descrittori di tipo. Poiché Android mappa i file.vdexe.odexnella memoria del processo, tabelle dei simboli più piccole riducono direttamente sia le dimensioni della partizione di sistema sia il footprint della memoria di runtime. - Ottimizzazioni più approfondite dell'intero programma: consentire a R8 di rinominare gli identificatori sblocca l'unione delle classi, l'appiattimento dei pacchetti e la deduplicazione delle classi sintetiche nei pacchetti che R8 deve altrimenti ignorare per evitare conflitti di nomi.
- Simbolizzazione completa dell'analisi dello stack: l'attivazione dell'offuscamento in Soong non
riduce la possibilità di eseguire il debug. Per ogni target compilato con R8, Soong genera un file di mapping
proguard_dictionarynella directory intermedia del modulo, raggruppa tutti i dizionari dei moduli nell'artefattoproguard-dict.zipdella build, incorpora un hash di mapping (--map-id-template) nell'intestazione DEX e riscrive gli attributiSourceFiledella classe (--source-file-template) in modo cheretracepossa simbolizzare automaticamente le analisi dello stack.
Conserva obfuscate: false (o conserva esplicitamente i nomi delle API pubbliche) solo per:
- Librerie condivise nel bootclasspath o nel
system_serverclasspath: i moduli (java_libraryojava_sdk_library) che espongono un'API esterna vengono collegati dinamicamente da altri moduli in fase di runtime (ad esempio targetframework.jar,services.jaro<uses-library>) devono mantenereobfuscate: falseo conservare esplicitamente la propria superficie API utilizzando le regole@KeepForApio-keep(insieme aprotect_api_surface: trueper i target bootclasspath) in modo che i chiamanti compilati in base ai relativi stub possano risolvere i nomi di classi e membri in fase di runtime.
Prima di abilitare obfuscate: true su un'applicazione, verifica i seguenti prerequisiti per la migrazione:
- Dipendenze APK di test esterni: se un APK
android_testesterno impostainstrumentation_for: "MyApp"e richiama direttamente classi o metodi interni diMyApp, la ridenominazione di questi simboli causaNoSuchMethodErroroNoClassDefFoundErrordurante l'esecuzione del test. Preferisci strutturare il test come un APK con strumentazione automatica che collegaMyApp.implin modo statico, annota gli hook di test con@VisibleForTestingo configuratrace_references_from(vedi Passaggio 2: esegui la migrazione delle regole di conservazione basate sui test) in modo che i simboli interni necessari per i test vengano conservati durante l'offuscamento del resto dell'app. - Riflessione basata su stringhe e JNI: se un modulo cerca classi, metodi o campi in base a nomi di stringhe letterali (
Class.forName,getDeclaredMethodo JNIFindClasseGetMethodID) senza regole di conservazione o annotazioni, l'offuscamento rinomina queste destinazioni e interrompe le ricerche in fase di runtime. Tieni presente che anche la reflection non annotata non supera i test inshrink: trueeoptimize: true. Annota questi punti di ingresso con Guida per conservare le annotazioni (@UsesReflection,@UsedByReflectiono@UsedByNative) in modo che R8 conservi i loro nomi e offuschi il resto del modulo.
Segui il principio di zero flag personalizzati
Il modulo della piattaforma Android ideale non ha file proguard.flags o keep.xml personalizzati. Nella build della piattaforma Android, la maggior parte delle regole di conservazione personalizzate sono
ridondanti:
- Baseline della piattaforma e AAPT2: la maggior parte dei punti di ingresso viene già conservata
automaticamente dalle baseline della piattaforma globali (come
@Keep, metodi JNInativee@VisibleForTesting) o generata da AAPT2 daAndroidManifest.xmle risorse di layout (vedi Informazioni sulle regole di conservazione predefinite della piattaforma). - Alternative mirate: nei casi in cui i punti di ingresso devono essere conservati, preferisci le annotazioni del sito di dichiarazione (
keepanno,@VisibleForTesting), le regole della libreria esportate (export_proguard_flags_files: true) o il collegamento dei test statici ai file.flagsseparati (vedi Esegui l'audit e la migrazione delle regole di conservazione esistenti).
Prima di aggiungere o conservare un file proguard.flags o keep.xml personalizzato, verifica
se la regola è già gestita dalle baseline predefinite o può essere migrata alle
annotazioni del codice.
Informazioni sulle regole di conservazione predefinite della piattaforma
Soong trasmette automaticamente le seguenti regole di base globali a ogni chiamata R8
sui target di compilazione DEX (android_app, android_test e
moduli java_library installabili), configurati in build/soong/java/dex.go:
build/make/core/proguard.flags: conserva le classi e i membri annotati con@com.android.internal.annotations.VisibleForTestingin tutti i pacchetti e con@VisibleForTesting(androidx.annotation.VisibleForTestingocom.google.common.annotations.VisibleForTesting) all'interno dei pacchettiandroid.**,com.android.**ecom.google.android.**. Conserva anche@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallbacke@dalvik.annotation.optimization.**.build/make/core/proguard_basic_keeps.flags: conserva gli attributiSourceFileper stack trace, annotazioni di visibilità di runtime (RuntimeVisible*Annotations), attributiExceptionseAnnotationDefault, metodinative, membriSerializable, metodi@JavascriptInterface, costruttoriThrowable(String), campiParcelable$CREATORe campiMessageLiteprotobuf.build/make/core/proguard/kotlin.flags: disattiva gli avvisi innocui per meta-annotazioni Kotlin specifiche (kotlin.Metadataekotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) e rimuove le annotazioni KotlinDebugMetadatanelle build di rilascio.build/make/core/proguard/checknotnull.flags: sostituisce le chiamate di assistenza per il controllo dei valori null comuni (com.google.common.base.Preconditions.checkNotNulledagger.internal.Preconditions.checkNotNull*) con controlli dei valori null del bytecode concisi. Questo file omette intenzionalmenteObjects.requireNonNullper preservare messaggi di eccezione espliciti nei limiti dell'API del framework.build/make/core/proguard/enumvalues.flags: mantiene i metodivaluesevalueOfsui tipienum, a meno che non siano disattivati dalla configurazione della build.- Regole generate automaticamente da AAPT2: AAPT2 esamina i file XML
AndroidManifest.xml, di layout e delle preferenze uniti per generare regole di conservazione esatte per ogniActivity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, sottoclasseViewpersonalizzata, sottoclassePreferencee metodoandroid:onClickXML registrati.
Controllare ed eseguire la migrazione delle regole di conservazione esistenti
Quando esegui l'audit dei file proguard.flags o keep.xml esistenti in un repository della piattaforma, valuta ogni regola in ordine in base alla seguente gerarchia in quattro passaggi:
Passaggio 1: elimina le regole ridondanti o obsolete
Elimina le regole già coperte dalle baseline globali, dalle regole di layout e del manifest AAPT2 o dai valori predefiniti di R8, nonché le regole che fanno riferimento a classi o pacchetti che non esistono più.
Se tutte le regole in un file .flags sono ridondanti, elimina il file e rimuovi
proguard_flags_files da Android.bp. Se il blocco optimize rimanente
riporta solo le impostazioni predefinite, rimuovi il blocco ridondante e formatta il file di build
con bpfmt -w Android.bp. Quando pulisci un pacchetto, controlla se i moduli
complementari nelle sottodirectory (ad esempio le varianti di destinazione Kotlin) fanno riferimento allo stesso
file di flag e aggiornali insieme.
Passaggio 2: esegui la migrazione delle regole di conservazione basate sui test
Sposta le regole di conservazione basate sui test fuori dai file .flags di produzione personalizzati utilizzando uno dei seguenti pattern:
Collega la libreria di implementazione ai test (
static_libs): quando unandroid_testesercita dettagli di implementazione interni o privati del pacchetto di un'app, l'architettura della piattaforma consigliata prevede di inserire i file sorgente dell'app in unandroid_library(MyApp.impl) e di collegare staticamenteMyApp.implsia aMyAppche aMyAppTests: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"], }Questo pattern a tre moduli consente a
MyAppTestsdi essere eseguito come test di autostrumentazione con accesso completo alle classi interne, consente aMyAppdi attivareobfuscate: trueliberamente senza interrompere i test, evita la spedizione di punti di ingresso solo di test nell'APK di produzione ed elimina la ricompilazione diMyAppquando il codice di test cambia.Annota gli hook di test con
@VisibleForTesting: se un APK di test esterno chiama un numero ridotto di metodi o costruttori interni su una destinazioneandroid_appe la ristrutturazione in una libreria.implè impraticabile, annota queste dichiarazioni con@VisibleForTesting. La baselinebuild/make/core/proguard.flagsglobale conserva@VisibleForTestinggli elementi nei pacchettiandroid.**,com.android.**ecom.google.android.**automaticamente senza file.flagspersonalizzati. (Per i moduli del fornitore al di fuori di questi spazi dei nomi, utilizza@UsedByReflectiono le regole della libreria esportata.)Utilizza
trace_references_fromoltre i limiti della libreria della piattaforma: quando i test non possono collegare staticamente l'implementazione di destinazione (ad esempio, i test che utilizzano i servizi del server di sistema o i file JAR della piattaforma comeframework-connectivity), configuratrace_references_fromnel modulo di destinazione in modo che punti a un modulo complementare della libreria Java contenente le origini dei test. R8 traccia e conserva tutte le classi e tutti i membri a cui fa riferimento il bytecode complementare.
Passaggio 3: esporta le regole dalla libreria proprietaria
Se una java_library o android_library condivisa richiede regole di conservazione per la propria
riflessione interna o callback JNI, definisci le regole nel target della libreria e
imposta 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,
},
}
Tutti i target android_app e delle librerie downstream che collegano staticamente
my-shared-library ereditano automaticamente queste regole, quindi le app downstream non
devono duplicarle. Quando più moduli in directory diverse devono condividere un insieme di regole non associato a una singola libreria di codice, pubblica il file .flags tramite un filegroup esplicito in Android.bp in modo che i moduli possano fare riferimento a :my-shared-flags in modo pulito tra i limiti del pacchetto. Per indicazioni generali sulla
creazione di regole di conservazione per i consumatori di librerie senza limitare l'ottimizzazione delle app downstream, consulta Ottimizzazione per gli autori di librerie.
Passaggio 4: annota le dichiarazioni nel codice sorgente
Quando si accede a una classe, a un metodo, a un costruttore o a un campo tramite reflection o
JNI e non sono coperti da AAPT2 o dalle baseline globali, sostituisci le regole -keep
separate nei file .flags con le annotazioni di origine della
Guida alle annotazioni Keep (vedi il
riferimento Javadoc keepanno):
@UsesReflection: preferisci questa annotazione quando controlli il codice che esegue la reflection. Posizionalo nel sito di chiamata di reflection per dichiarare dinamicamente le classi, i metodi o i campi di destinazione a cui si accede. Poiché@UsesReflectioncodifica automaticamente una precondizione che il sito di chiamata annotato stesso sia raggiungibile, R8 elimina sia il chiamante sia la destinazione riflessiva se il sito di chiamata non viene utilizzato.@UsedByReflection: posiziona su classi, metodi, campi o costruttori di cui viene creata un'istanza o richiamati in modo riflessivo da codice o librerie esterni, ad esempio classi caricate conClass.forNameda chiaviBundleoSettingso classi di plug-in caricate in class loader dinamici. Specificakind(ad esempioKeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition) e i vincoli dei parametri in modo che R8 mantenga solo il contratto di reflection esatto e possa comunque ottimizzare o eliminare i membri inutilizzati della classe. Non aggiungere@UsedByReflectionai componenti registrati nel manifest comeJobServiceoBroadcastReceiver, perché AAPT2 li conserva già.@UsedByNative: posiziona i metodi o i campi a cui si accede dal codice JNI C o C++ utilizzandoGetMethodID,GetStaticMethodIDoGetFieldID.@KeepForApi: posiziona le classi o i membri dell'API della libreria che devono rimanere intatti quando una libreria viene ridotta prima della distribuzione.@Keep(androidx.annotation.Keep): utilizza questo valore come fallback quandokeepannonon è applicabile. L'applicazione di@Keepa una classe mantiene la classe e tutti i relativi membri senza condizioni. L'applicazione di@Keepa un metodo o a un campo funge da punto di ingresso incondizionato che mantiene il membro e la relativa classe contenitore anche se la classe non viene mai istanziata, mentrekeepannoesprime la raggiungibilità condizionale.
Per utilizzare le annotazioni keepanno di R8 in un modulo Soong:
Aggiungi
"keepanno-annotations"alibsinAndroid.bp:libs: [ "keepanno-annotations", ],Importa
com.android.tools.r8.keepanno.annotations.*e annota la dichiarazione o il sito di chiamata nel codice sorgente Java o Kotlin: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 traduce le annotazioni
keepannodirettamente nel suo modello interno di regole di conservazione e rimuove le annotazioni dall'output DEX finale, aggiungendo un sovraccarico di bytecode di runtime pari a zero.
Evitare gli errori comuni
Le sezioni seguenti descrivono le insidie più frequenti di proguard.flags e keep.xml
nel codice della piattaforma e come risolverle.
Regole di conservazione dei componenti generali
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- Perché influisce negativamente sul rendimento: questa regola è completamente ridondante con AAPT2.
Poiché utilizza un carattere jolly senza verificare se il componente è
registrato nel
AndroidManifest.xmlunito finale, R8 è costretto a conservare ogni sottoclasseActivity,ServiceoBroadcastReceivertrovata ovunque nel classpath, inclusi i componenti della libreria inutilizzati e le attività di debug disattivate. - Correzione consigliata: elimina la regola. AAPT2 esamina il manifest unito e
genera regole
-keepesatte per i componenti registrati.
Regole di conservazione del gestore di clic XML generico
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- Perché influisce sul rendimento: la conservazione di ogni metodo
public void *(View)in ogni classe del modulo impedisce a R8 di rimuovere o incorporare qualsiasi metodo che accetta un singolo parametroView. - Correzione consigliata: elimina la regola. AAPT2 analizza i file XML di layout e
genera regole di conservazione mirate per i metodi a cui fanno riferimento gli attributi
android:onClick.
Getter e setter di Broad View mantengono le regole
# 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*();
}
- Perché influisce sulle prestazioni: questa regola impone a R8 di conservare ogni getter e
setter in ogni sottoclasse
Viewdell'app e in tutte le librerie collegate (incluse le librerie AndroidX e Material), bloccando la rimozione dei metodi inutilizzati e l'incorporamento nel codice dell'interfaccia utente. - Correzione consigliata: elimina la regola. AAPT2 conserva già i costruttori
per le classi
Viewpersonalizzate inflate dai file XML di layout. Se il codice anima una proprietà di visualizzazione utilizzando nomi di stringhe riflessive comeObjectAnimator.ofFloat(view, "translationZ", ...), sostituisci il nome della stringa con un riferimento alla proprietà digitato (View.TRANSLATION_Zo un'implementazione personalizzataFloatPropertyoIntProperty) per evitare completamente la riflessione. Se non è possibile evitare l'accesso alle proprietà di riflessione, annota il getter o il setter specifico con@UsedByReflection.
L'ottimizzazione o l'offuscamento generico disattiva
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Perché influisce sul rendimento: l'inserimento di
-dontoptimizeo-dontshrinkall'interno di un file.flagsesegue l'override silenzioso delle impostazioniAndroid.bpdel modulo e disattiva i passaggi di ottimizzazione nell'intero target. Peggio ancora, se una libreria esporta un file.flagscontenente-dontoptimize, disattiva l'ottimizzazione R8 per ogniandroid_appdownstream che collega la libreria. - Correzione consigliata: rimuovi
-dontoptimize,-dontshrinke-dontobfuscatedai file.flags. Controlla il comportamento di ottimizzazione in modo esplicito inAndroid.bputilizzando il bloccooptimize(shrink,optimize,obfuscate) nel target foglia.
Flag di diagnostica nelle regole di commit
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- Perché danneggia la build: i flag di diagnostica inondano i log di build o tentano di scrivere file di output in percorsi locali durante le build Soong in sandbox.
- Correzione consigliata: elimina questi flag dai file
.flagsdi cui è stato eseguito il commit. Soong scrive automaticamente le mappature e gli output di utilizzo di R8, ad esempioproguard_dictionaryeproguard_usage.zip, nella directory intermedia del modulo inout/soong/.intermediates/.
Regole di conservazione della produzione per il codice di test
- Perché influisce negativamente sul rendimento: l'aggiunta di regole
-keeppersonalizzate esclusivamente per l'accesso ai test impone che il codice rimanga non offuscato e conservato nelle build di produzione. Sebbene l'annotazione dei metodi con@VisibleForTestingo la configurazione ditrace_references_fromeviti di gestire regole-keepmanuali, questi simboli vengono comunque inclusi nel binario di produzione. - Correzione consigliata: per escludere completamente i punti di ingresso solo di test dall'APK di produzione, struttura l'applicazione in una libreria
.imple collegala a un APK di test auto-strumentato utilizzandostatic_libs, come descritto nel passaggio 2: esegui la migrazione delle regole di conservazione basate sui test.
Caratteri jolly per le risorse onnicomprensivi 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/*" />
- Perché influisce negativamente sul rendimento: i caratteri jolly generici conservano ogni risorsa nel tipo corrispondente in tutto il modulo e le relative dipendenze, vanificando la riduzione delle risorse (
shrink_resources: true) e gonfiando la tabella APK eresources.arscmappata. - Correzione consigliata:
- Preferisci i riferimenti alle risorse statiche a
keep.xml: evita di utilizzare il metodoResources.getIdentifierper cercare dinamicamente un insieme limitato di risorse, ad esempio stringhe di esperimenti numerate o risorse disegnabili a tema. Utilizza invece un'istruzioneswitchin fase di compilazione o una mappatura su costanti staticheR.id,R.stringoR.drawable. I riferimenti statici consentono a R8 e AAPT2 di tracciare le risorse live esatte, eliminare l'overhead di ricerca delle stringhe in fase di runtime e rimuovere completamente la necessità dikeep.xml. - Elenca nomi di risorse specifici: se è necessaria la ricerca dinamica, ad esempio
da parte di un lettore di licenze di terze parti, elenca gli identificatori di risorse esatti in
tools:keep(ad esempio,tools:keep="@raw/third_party_licenses"). - Elimina i file
keep.xmlridondanti: se le risorse elencate sono già referenziate staticamente nel codice (R.raw.foo) o in XML (@raw/foo), lo strumento di riduzione le conserva automaticamente, quindi puoi eliminareres/raw/keep.xml.
- Preferisci i riferimenti alle risorse statiche a
Verificare e controllare le modifiche alle regole
Ogni volta che rimuovi o restringi le regole di conservazione in proguard.flags o keep.xml,
verifica che il modulo venga compilato correttamente, superi i test unitari e di strumentazione
e mantenga tutti i punti di ingresso richiesti.
Creare e testare i moduli
Crea il modulo in modo pulito per verificare che R8 e AAPT2 vengano completati senza avvisi di riferimenti mancanti:
m <MODULE_NAME>Esegui test delle unità e di strumentazione per il modulo utilizzando
atest:atest <TEST_MODULE_NAME>Per app di sistema, servizi privilegiati o moduli dipendenti dall'hardware, esegui test di strumentazione e UI su dispositivi fisici di destinazione o nel laboratorio di test dei dispositivi per esercitare percorsi di reflection di runtime, binding IPC e inflazione delle risorse.
Ispezionare le differenze tra DEX e risorse
Confronta l'APK o il JAR compilato prima e dopo le modifiche alle regole per verificare che R8 rimuova il codice e le risorse inutilizzati senza eliminare i punti di ingresso previsti:
Utilizza
apkanalyzerodexdumpper esaminare classi, metodi e campi conservati nei file APK o DEX di output:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkQuando modifichi
keep.xmlo attivishrink_resources, utilizzaaapt2 dump resourcesper verificare che la build rimuova le risorse inutilizzate e mantenga quelle necessarie:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
Analizzare il raggio di conservazione e l'inclusione delle regole con R8
Il compilatore R8 open source include un analizzatore Keep Radius
(esposto anche in Android Studio e Gradle come
R8 Configuration Analyzer) che misura l'impatto esatto
di ogni regola di conservazione durante la compilazione. Soong integra questo analizzatore
direttamente nella build della piattaforma Android (configurata in
build/soong/java/dex.go).
Per analizzare le regole di conservazione per un modulo della piattaforma o per l'intera build:
Esegui la build con la variabile di ambiente
R8_DUMP_KEEP_RADIUS=true:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>Quando
R8_DUMP_KEEP_RADIUS=trueè impostato, Soong indica a R8 di registrare le metriche delle regole di conservazione in un filer8keepradius.pbintermedio per ogni modulo compilato inout/soong/.intermediates/. Per ogni regola di conservazione e annotazionekeepanno, R8 registra:- Raggio di conservazione immediata: le classi, i campi e i metodi esatti conservati dalla regola, insieme ai vincoli specifici che impone contro la riduzione, l'ottimizzazione o l'offuscamento.
- Subsumption della regola: quali altre regole di conservazione o annotazioni conservano già gli stessi elementi. Se una regola personalizzata è completamente inclusa in una regola AAPT2 o in una regola di base globale, puoi eliminarla in sicurezza.
- Regole globali e a livello di pacchetto: regole che utilizzano caratteri jolly generici a livello di pacchetto o che applicano direttive di configurazione globali.
Converti l'output
r8keepradius.pbin un report HTML interattivo utilizzandoKeepRadiusHtmlReportGenerator(incluso 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_reportsSe viene fornita una directory,
KeepRadiusHtmlReportGeneratoresamina tutti i file*keepradius*.pb, genera un report HTML per ogni modulo e creaout/keep_radius_reports/keepradius.htmlche riepilogano i conteggi degli elementi live, gli elementi conservati e le regole di conservazione con il raggio più ampio nella build. Per saperne di più sull'interpretazione dei punteggi di riduzione, ottimizzazione e offuscamento nel report generato, consulta Utilizzare R8 Configuration Analyzer.
Soong supporta anche due variabili di ambiente di diagnostica R8 aggiuntive in
build/soong/java/dex.go:
R8_DUMP_INPUT=true: scriver8inputs.zipnella directory intermedia del modulo contenente tutti i file JAR di input, i file JAR della libreria e le configurazioni ProGuard unite per la riproduzione di R8 standalone.R8_DUMP_PERFETTO_TRACE=true: scriver8trace.ptracenella directory intermedia del modulo per ispezionare le pass di compilazione R8 in Perfetto.
Convalidare le regole di consumo della libreria
Quando le regole di conservazione vengono mantenute per i consumatori downstream (export_proguard_flags_files: true) in un'esportazione java_library o android_library, queste regole non devono includere flag globali che alterano o disattivano l'ottimizzazione per l'app di consumo.
R8 fornisce un analizzatore di regole di conservazione open source
(ProcessKeepRules), esposto nella build della piattaforma Android
come strumento host process-keep-rules (definito 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>
Lo strumento process-keep-rules analizza ogni file di configurazione e genera un errore con diagnostica di file e riga se rileva direttive non consentite nelle regole di consumo della libreria. Le direttive non consentite includono l'ottimizzazione globale, la riduzione
o la disattivazione dell'offuscamento (ad esempio -dontoptimize o -dontshrink), i flag di
riconfezionamento e modifica dell'accesso dei pacchetti, i flag di diagnostica o mappatura e
-keepattributes a livello di app.
Controllare gli alberi delle origini con pgaudit.py
Per controllare le directory di origine non compilate insieme agli analizzatori in fase di compilazione di R8, l'albero della piattaforma Android include lo script pgaudit.py in build/make/core/proguard/tools/. Questo strumento di analisi statica esegue la scansione dei file Android.bp,
proguard.flags e keep.xml in un repository per segnalare le regole già
coperte da AAPT2 o dalle baseline della piattaforma globale, dai caratteri jolly generici, -dontoptimize
dagli override e dalle regole di conservazione solo per i test:
# 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
I team della piattaforma e degli OEM possono combinare pgaudit.py per la classificazione rapida dell'albero delle origini,
process-keep-rules per convalidare le regole della libreria esportate e
R8_DUMP_KEEP_RADIUS=true con KeepRadiusHtmlReportGenerator per misurare il
raggio di conservazione esatto di classi, campi e metodi di ogni regola in una build.