Sistem build platform Android (Soong) menjalankan compiler R8 pada
target yang mengompilasi bytecode DEX, termasuk aplikasi Android (android_app), pengujian
(android_test), dan library Java yang dapat diinstal dengan compile_dex: true (seperti
services.jar), untuk mengecilkan, mengoptimalkan, dan menghapus kode dan resource yang tidak digunakan. Pada
library statis (android_library dan java_library statis), Soong tidak
menjalankan R8 secara langsung, tetapi menggunakan blok properti optimize untuk melampirkan dan menyebarkan
aturan keep konsumen (export_proguard_flags_files: true) ke target DEX hilir
yang menautkannya secara statis.
Untuk engineer platform yang membuat image sistem atau paket vendor, menghilangkan aturan penyimpanan yang terlalu luas memberikan manfaat kesehatan sistem langsung:
- Jejak partisi sistem yang lebih kecil: R8 menghapus class, metode,
dan resource yang tidak digunakan sebelum mengemas APK dan JAR ke
/system,/system_ext,/product, dan/vendor. - Artefak yang dikompilasi lebih kecil: Metode DEX yang lebih sedikit berarti file
.odexdan.vdexyang dihasilkan olehdex2oatselama kompilasi waktu build atau di perangkat lebih kecil. - Tekanan memori runtime yang lebih rendah: Karena Android memetakan
.odex,.vdex, dan tabel resource APK ke memori proses menggunakan panggilanmmapyang dipaginasi sesuai permintaan, biner yang lebih kecil mengurangi kesalahan halaman utama selama startup aplikasi dan menurunkan memori kode dan resource residen di seluruh proses. Untuk mengetahui informasi selengkapnya tentang pengaruh kode aplikasi yang dikompilasi terhadap memori perangkat, lihat Kode aplikasi adalah memori. - Pengoptimalan seluruh program yang lebih efektif: Batasan keep yang sempit memungkinkan R8 menyisipkan metode, melakukan devirtualisasi antarmuka dan panggilan virtual, memangkas kolom yang tidak digunakan, dan menyebarkan konstanta di seluruh class.
Mengonfigurasi pengoptimalan R8 di Soong
Dalam file Android.bp, konfigurasi pengoptimalan R8 menggunakan blok properti optimize
pada android_app dan target java_library yang dapat diinstal (atau pada
android_library dan modul java_library statis untuk mengekspor aturan keep konsumen):
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
Tabel berikut merangkum properti optimize yang paling umum di Soong
(ditentukan dalam build/soong/java/dex.go):
| Properti | Deskripsi |
|---|---|
enabled |
Mengontrol apakah R8 berjalan di target. Nilai defaultnya adalah true
untuk semua target android_app.
|
shrink |
Mengontrol tree shaking untuk menghapus class, kolom, dan
metode yang tidak dapat dijangkau. Nilai defaultnya adalah true untuk target android_app (false untuk java_library mandiri dan
modul pengujian, yang meneruskan -dontshrink kecuali jika
ditetapkan secara eksplisit).
|
optimize |
Mengontrol pengoptimalan bytecode seperti penyisipan metode, penggabungan class,
propagasi konstanta, dan penghapusan cabang tidak terpakai. Nilai defaultnya adalah
true untuk target android_app (dikontrol oleh
flag build rilis RELEASE_R8_OPTIMIZE_BY_DEFAULT).
|
obfuscate |
Mengontrol pengecilan dan penggantian nama ID. Secara default, nilainya adalah
false untuk kompatibilitas historis, tetapi tetapkan ke
true jika memungkinkan untuk mengurangi ukuran DEX dan mengaktifkan
pengoptimalan yang lebih mendalam (lihat
Aktifkan obfuscation jika memungkinkan).
|
shrink_resources |
Menghapus resource yang tidak digunakan (entri res/) dari APK yang dipaketkan setelah penyingkatan kode. Nilai defaultnya adalah false.
|
optimized_shrink_resources |
Menjalankan pipeline penyingkat kode dan resource R8 terintegrasi sehingga R8 melacak
referensi kode dan resource secara bersamaan dalam satu proses. Jika
shrink_resources: true ditetapkan, defaultnya adalah
RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT
(true dalam build platform standar).
|
proguard_flags_files |
Mencantumkan file .flags atau .pro khusus modul
yang berisi aturan penyimpanan kustom. Hindari menambahkan file kustom jika anotasi atau default standar sudah cukup.
|
export_proguard_flags_files |
Menyebarkan proguard_flags_files library ini ke
modul downstream yang bergantung padanya secara statis.
|
trace_references_from |
Mencantumkan target pendamping library Java yang bytecode-nya merujuk ke target ini yang secara otomatis dilacak dan dipertahankan oleh R8. |
Aktifkan pengaburan jika memungkinkan
Di Soong, obfuscate secara default adalah false untuk kompatibilitas historis, tetapi Anda
harus menetapkan obfuscate: true secara eksplisit pada android_app dan target DEX mandiri
jika memungkinkan:
- Jejak DEX dan
.vdexyang lebih kecil: Mengganti nama paket, class, kolom, dan metode menjadi ID pendek (a,b) akan mengecilkan kumpulan string DEX (string_idsdanstring_data_item) serta deskriptor jenis. Karena Android memetakan file.vdexdan.odexke dalam memori proses, tabel simbol yang lebih kecil secara langsung mengurangi ukuran partisi sistem dan jejak memori runtime. - Pengoptimalan seluruh program yang lebih mendalam: Dengan mengizinkan R8 mengganti nama ID, penggabungan class, perataan paket, dan penghapusan duplikat class sintetis dapat dilakukan di seluruh paket yang seharusnya dilewati R8 untuk menghindari konflik nama.
- Simbolisasi stack trace lengkap: Mengaktifkan pengaburan di Soong tidak mengurangi kemampuan proses debug. Untuk setiap target yang dikompilasi R8, Soong akan memancarkan file pemetaan
proguard_dictionarydi direktori perantara modul, menggabungkan semua kamus modul ke dalam artefakproguard-dict.zipbuild, menyematkan hash pemetaan (--map-id-template) ke dalam header DEX, dan menulis ulang atribut classSourceFile(--source-file-template) sehinggaretracedapat menyimbolkan stack trace secara otomatis.
Pertahankan obfuscate: false (atau pertahankan nama API publik secara eksplisit) hanya untuk:
- Library bersama di bootclasspath atau classpath
system_server: Modul (java_libraryataujava_sdk_library) yang mengekspos API eksternal yang ditautkan secara dinamis oleh modul lain saat runtime (seperti targetframework.jar,services.jar, atau<uses-library>) harus mempertahankanobfuscate: falseatau secara eksplisit mempertahankan permukaan API-nya menggunakan aturan@KeepForApiatau-keep(bersama denganprotect_api_surface: trueuntuk target bootclasspath) sehingga pemanggil yang dikompilasi terhadap stub-nya dapat menyelesaikan nama class dan anggota saat runtime.
Sebelum mengaktifkan obfuscate: true di aplikasi, verifikasi prasyarat migrasi berikut:
- Dependensi APK pengujian eksternal: Jika APK
android_testeksternal menetapkaninstrumentation_for: "MyApp"dan memanggil secara langsung class atau metode internalMyApp, mengganti nama simbol tersebut akan menyebabkanNoSuchMethodErroratauNoClassDefFoundErrorsaat runtime pengujian. Sebaiknya susun pengujian sebagai APK yang menginstrumentasikan sendiri yang menautkanMyApp.implsecara statis, anotasi hook pengujian dengan@VisibleForTesting, atau konfigurasitrace_references_from(lihat Langkah 2: Memigrasikan aturan penyimpanan berbasis pengujian) sehingga simbol internal yang diperlukan oleh pengujian dipertahankan sekaligus meng-obfuscate aplikasi lainnya. - Refleksi dan JNI berbasis string: Jika modul mencari class, metode, atau kolom berdasarkan nama string literal (
Class.forName,getDeclaredMethod, atau JNIFindClassdanGetMethodID) tanpa aturan atau anotasi keep, pengaburan akan mengganti nama target tersebut dan merusak pencarian runtime. (Perhatikan bahwa refleksi yang tidak diberi anotasi juga gagal dishrink: truedanoptimize: true.) Beri anotasi pada titik entri tersebut dengan Panduan untuk Mempertahankan Anotasi (@UsesReflection,@UsedByReflection, atau@UsedByNative) agar R8 mempertahankan namanya dan meng-obfuscate modul lainnya.
Mengikuti prinsip nol tanda kustom
Modul platform Android yang ideal tidak memiliki file proguard.flags atau keep.xml kustom. Dalam build platform Android, sebagian besar aturan penyimpanan kustom bersifat
redundan:
- Dasar platform dan AAPT2: Sebagian besar titik entri sudah dipertahankan secara otomatis oleh dasar platform global (seperti
@Keep, metode JNInative, dan@VisibleForTesting) atau dibuat oleh AAPT2 dariAndroidManifest.xmldan resource tata letak (lihat Memahami aturan keep platform default). - Alternatif yang ditargetkan: Jika titik entri harus dipertahankan, sebaiknya gunakan anotasi situs deklarasi (
keepanno,@VisibleForTesting), aturan library yang diekspor (export_proguard_flags_files: true), atau penautan pengujian statis daripada file.flagsyang terlepas (lihat Mengaudit dan memigrasikan aturan penyimpanan yang ada).
Sebelum menambahkan atau mempertahankan file proguard.flags atau keep.xml kustom, verifikasi apakah aturan sudah ditangani oleh dasar pengukuran default atau dapat dimigrasikan ke anotasi kode.
Memahami aturan penyimpanan platform default
Soong secara otomatis meneruskan aturan dasar global berikut ke setiap pemanggilan R8 pada target kompilasi DEX (android_app, android_test, dan modul java_library yang dapat diinstal), yang dikonfigurasi di build/soong/java/dex.go:
build/make/core/proguard.flags: Mempertahankan class dan anggota yang diberi anotasi dengan@com.android.internal.annotations.VisibleForTestingdi semua paket, dan dengan@VisibleForTesting(androidx.annotation.VisibleForTestingataucom.google.common.annotations.VisibleForTesting) dalam paketandroid.**,com.android.**, dancom.google.android.**. Juga mempertahankan@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallback, dan@dalvik.annotation.optimization.**.build/make/core/proguard_basic_keeps.flags: Mempertahankan atributSourceFileuntuk stack trace, anotasi visibilitas runtime (RuntimeVisible*Annotations), atributExceptionsdanAnnotationDefault, metodenative, anggotaSerializable, metode@JavascriptInterface, konstruktorThrowable(String), kolomParcelable$CREATOR, dan kolom protobufMessageLite.build/make/core/proguard/kotlin.flags: Membisukan peringatan tidak berbahaya untuk meta-anotasi Kotlin tertentu (kotlin.Metadatadankotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) serta menghapus anotasiDebugMetadataKotlin dalam build rilis.build/make/core/proguard/checknotnull.flags: Menggantikan panggilan helper pemeriksaan null umum (com.google.common.base.Preconditions.checkNotNulldandagger.internal.Preconditions.checkNotNull*) dengan pemeriksaan null bytecode yang ringkas. File ini sengaja menghilangkanObjects.requireNonNulluntuk mempertahankan pesan pengecualian eksplisit di seluruh batas API framework.build/make/core/proguard/enumvalues.flags: Mempertahankan metodevaluesdanvalueOfpada jenisenumkecuali jika dinonaktifkan oleh konfigurasi build.- Aturan yang dibuat otomatis oleh AAPT2: AAPT2 memeriksa file
AndroidManifest.xml, XML tata letak, dan XML preferensi yang digabungkan untuk membuat aturan keep yang tepat untuk setiapActivity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, subclassViewkustom, subclassPreference, dan metodeandroid:onClickXML yang terdaftar.
Mengaudit dan memigrasikan aturan penyimpanan yang ada
Saat mengaudit file proguard.flags atau keep.xml yang ada di repositori platform, evaluasi setiap aturan secara berurutan berdasarkan hierarki empat langkah berikut:
Langkah 1: Hapus aturan yang berlebihan atau sudah tidak berlaku
Hapus aturan yang sudah tercakup oleh dasar global, aturan tata letak dan manifes AAPT2, atau default R8, serta aturan yang mereferensikan class atau paket yang tidak ada lagi.
Jika semua aturan dalam file .flags bersifat redundan, hapus file dan hapus
proguard_flags_files dari Android.bp. Jika blok optimize yang tersisa hanya
menyatakan kembali setelan default, hapus blok yang berlebihan dan format file build
dengan bpfmt -w Android.bp. Saat membersihkan paket, periksa apakah modul pendamping di subdirektori (seperti varian target Kotlin) mereferensikan file tanda yang sama dan perbarui secara bersamaan.
Langkah 2: Migrasikan aturan penyimpanan berbasis pengujian
Pindahkan aturan penyimpanan berbasis pengujian dari file produksi kustom .flags menggunakan salah satu pola berikut:
Tautkan library penerapan ke dalam pengujian (
static_libs): Jikaandroid_testmenggunakan detail penerapan internal atau khusus paket aplikasi, arsitektur platform yang direkomendasikan adalah menempatkan file sumber aplikasi diandroid_library(MyApp.impl) dan menautkanMyApp.implsecara statis keMyAppdanMyAppTests: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"], }Pola 3 modul ini memungkinkan
MyAppTestsberjalan sebagai pengujian yang menginstrumentasikan diri sendiri dengan akses penuh ke class internal, memungkinkanMyAppmengaktifkanobfuscate: truesecara bebas tanpa merusak pengujian, menghindari pengiriman titik entri khusus pengujian dalam APK produksi, dan menghilangkan pembangunan ulangMyAppsaat kode pengujian berubah.Anotasi hook pengujian dengan
@VisibleForTesting: Jika APK pengujian eksternal memanggil sejumlah kecil metode atau konstruktor internal pada targetandroid_appdan penataan ulang ke dalam library.impltidak praktis, anotasi deklarasi tersebut dengan@VisibleForTesting. Dasar pengukuran globalbuild/make/core/proguard.flagsmempertahankan item@VisibleForTestingdalam paketandroid.**,com.android.**, dancom.google.android.**secara otomatis tanpa file.flagskustom. (Untuk modul vendor di luar namespace ini, gunakan@UsedByReflectionatau aturan library yang diekspor.)Menggunakan
trace_references_fromdi seluruh batas library platform: Jika pengujian tidak dapat menautkan implementasi target secara statis (misalnya, pengujian yang menggunakan layanan server sistem atau JAR platform sepertiframework-connectivity), konfigurasitrace_references_frompada target modul yang mengarah ke modul pendamping library Java yang berisi sumber pengujian. R8 melacak dan mempertahankan semua class dan anggota yang dirujuk oleh bytecode pendamping.
Langkah 3: Mengekspor aturan dari pustaka pemilik
Jika java_library atau android_library bersama memerlukan aturan penyimpanan untuk callback JNI atau refleksi internalnya sendiri, tentukan aturan pada target library dan tetapkan 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,
},
}
Semua target android_app dan library downstream yang menautkan my-shared-library secara statis akan mewarisi aturan tersebut secara otomatis, sehingga aplikasi downstream tidak perlu menduplikasinya. Jika beberapa modul di berbagai direktori harus
berbagi set aturan yang tidak terikat ke satu library kode, publikasikan file .flags
melalui filegroup eksplisit di Android.bp sehingga modul dapat mereferensikan
:my-shared-flags dengan bersih di seluruh batas paket. Untuk panduan umum tentang
menulis aturan penyimpanan konsumen library tanpa membatasi pengoptimalan aplikasi hilir, lihat Pengoptimalan untuk penulis library.
Langkah 4: Anotasi deklarasi dalam kode sumber
Jika class, metode, konstruktor, atau kolom diakses melalui refleksi atau
JNI dan tidak tercakup oleh AAPT2 atau tolok ukur global, ganti aturan -keep yang terlepas
dalam file .flags dengan anotasi sumber dari
Panduan untuk Mempertahankan Anotasi (lihat
referensi Javadoc keepanno):
@UsesReflection: Pilih anotasi ini jika Anda mengontrol kode yang melakukan refleksi. Tempatkan di situs panggilan refleksi untuk mendeklarasikan class, metode, atau kolom target mana yang diakses secara dinamis. Karena@UsesReflectionotomatis mengenkode prasyarat bahwa situs panggilan yang dianotasi itu sendiri dapat dijangkau, R8 akan memangkas pemanggil dan target reflektif jika situs panggilan tidak digunakan.@UsedByReflection: Tempatkan pada class, metode, kolom, atau konstruktor yang di-instansiasi atau dipanggil secara reflektif oleh kode atau library eksternal, seperti class yang dimuat denganClass.forNamedari kunciBundleatauSettings, atau class plugin yang dimuat di seluruh classloader dinamis. Tentukankind(sepertiKeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition), dan batasan parameter sehingga R8 hanya menyimpan kontrak reflektif yang tepat dan masih dapat mengoptimalkan atau memangkas anggota class yang tidak digunakan. Jangan menambahkan@UsedByReflectionke komponen yang terdaftar di manifes sepertiJobServiceatauBroadcastReceiver, karena AAPT2 sudah menyimpannya.@UsedByNative: Tempatkan pada metode atau kolom yang diakses dari kode JNI C atau C++ menggunakanGetMethodID,GetStaticMethodID, atauGetFieldID.@KeepForApi: Tempatkan pada class atau anggota API library yang harus tetap utuh saat library itu sendiri di-shrink sebelum didistribusikan.@Keep(androidx.annotation.Keep): Gunakan sebagai penggantian jikakeepannotidak berlaku. Menerapkan@Keepke suatu class akan mempertahankan class dan semua anggotanya tanpa syarat. Menerapkan@Keepke metode atau kolom bertindak sebagai titik entri tanpa syarat yang mempertahankan anggota dan class yang memuatnya meskipun class tidak pernah di-instance, sedangkankeepannomengekspresikan keterjangkauan bersyarat.
Untuk menggunakan anotasi keepanno R8 dalam modul Soong:
Tambahkan
"keepanno-annotations"kelibsdiAndroid.bp:libs: [ "keepanno-annotations", ],Impor
com.android.tools.r8.keepanno.annotations.*dan anotasi deklarasi atau situs panggilan dalam kode sumber Java atau 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 menerjemahkan anotasi
keepannolangsung ke dalam model aturan keep internalnya dan menghapus anotasi dari output DEX akhir, sehingga tidak menambahkan overhead bytecode runtime.
Menghindari kesalahan umum
Bagian berikut menjelaskan kesalahan umum proguard.flags dan keep.xml
dalam kode platform dan cara memperbaikinya.
Aturan penyimpanan komponen luas
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- Alasan aturan ini menurunkan performa: Aturan ini sepenuhnya berlebihan dengan AAPT2.
Karena menggunakan karakter pengganti tanpa memeriksa apakah komponen terdaftar di
AndroidManifest.xmlgabungan akhir, R8 dipaksa untuk mempertahankan setiap subclassActivity,Service, atauBroadcastReceiveryang ditemukan di mana pun di classpath, termasuk komponen library yang tidak digunakan dan aktivitas debug yang dinonaktifkan. - Perbaikan yang direkomendasikan: Hapus aturan. AAPT2 memeriksa manifes gabungan dan
membuat aturan
-keepyang tepat untuk komponen terdaftar.
Aturan penyimpanan handler klik XML luas
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- Alasan performa terpengaruh: Mempertahankan setiap metode
public void *(View)di setiap class dalam modul mencegah R8 menghapus atau menyisipkan metode apa pun yang menerima satu parameterView. - Perbaikan yang direkomendasikan: Hapus aturan. AAPT2 memindai file XML tata letak dan
membuat aturan keep yang ditargetkan untuk metode yang dirujuk oleh atribut
android:onClick.
Aturan penyimpanan getter dan setter Broad View
# 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*();
}
- Alasan performa terpengaruh: Aturan ini memaksa R8 untuk mempertahankan setiap getter dan
setter di setiap subclass
Viewdalam aplikasi dan semua library tertaut (termasuk library AndroidX dan Material), sehingga memblokir penghapusan metode tidak terpakai dan inlining di seluruh kode UI. - Perbaikan yang direkomendasikan: Hapus aturan. AAPT2 sudah mempertahankan konstruktor
untuk class
Viewkustom yang di-inflate dari file XML tata letak. Jika kode menganimasikan properti tampilan menggunakan nama string reflektif sepertiObjectAnimator.ofFloat(view, "translationZ", ...), ganti nama string dengan referensi properti yang diketik (View.TRANSLATION_Zatau implementasiFloatPropertyatauIntPropertykustom) untuk menghindari refleksi sepenuhnya. Jika akses properti reflektif tidak dapat dihindari, beri anotasi pada getter atau setter tertentu dengan@UsedByReflection.
Pengoptimalan atau pengaburan menyeluruh dinonaktifkan
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Alasan performa terpengaruh: Menempatkan
-dontoptimizeatau-dontshrinkdi dalam file.flagssecara diam-diam akan menggantikan setelanAndroid.bpmodul dan menonaktifkan pengoptimalan di seluruh target. Lebih buruk lagi, jika library mengekspor file.flagsyang berisi-dontoptimize, hal ini akan menonaktifkan pengoptimalan R8 untuk setiapandroid_apphilir yang menautkan library. - Perbaikan yang direkomendasikan: Hapus
-dontoptimize,-dontshrink, dan-dontobfuscatedari file.flags. Mengontrol perilaku pengoptimalan secara eksplisit diAndroid.bpmenggunakan blokoptimize(shrink,optimize,obfuscate) pada target daun.
Tanda diagnostik dalam aturan yang diterapkan
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- Alasan merusak build: Flag diagnostik membanjiri log build atau mencoba menulis file output ke jalur lokal selama build Soong yang di-sandbox.
- Perbaikan yang direkomendasikan: Hapus tanda ini dari file
.flagsyang di-commit. Soong secara otomatis menulis output penggunaan dan pemetaan R8, sepertiproguard_dictionarydanproguard_usage.zip, ke direktori perantara modul di bagianout/soong/.intermediates/.
Aturan penyimpanan produksi untuk kode pengujian
- Alasan penurunan performa: Menambahkan aturan
-keepkustom hanya untuk akses pengujian memaksa kode tersebut tetap tidak di-obfuscate dan dipertahankan dalam build produksi. Meskipun menganotasi metode dengan@VisibleForTestingatau mengonfigurasitrace_references_frommenghindari pemeliharaan aturan-keepmanual, simbol tersebut tetap dikirim dalam biner produksi. - Perbaikan yang direkomendasikan: Untuk menjaga agar titik entri khusus pengujian benar-benar tidak ada di APK produksi, susun aplikasi ke dalam library
.impldan tautkan ke APK pengujian yang melakukan instrumentasi sendiri menggunakanstatic_libs, seperti yang dijelaskan dalam Langkah 2: Memigrasikan aturan keep berbasis pengujian.
Karakter pengganti resource menyeluruh di keep.xml
<!-- Don't do this in res/raw/keep.xml: -->
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@raw/*,@drawable/*,@string/*" />
- Alasan performa terpengaruh: Kartu pengganti menyeluruh mempertahankan setiap resource dalam jenis yang cocok di seluruh modul dan dependensinya, sehingga mengalahkan pengecilan resource (
shrink_resources: true) dan memperbesar APK serta tabelresources.arscyang dipetakan. - Perbaikan yang direkomendasikan:
- Lebih memilih referensi resource statis daripada
keep.xml: Hindari penggunaan metodeResources.getIdentifieruntuk mencari kumpulan resource yang terikat secara dinamis, seperti string eksperimen bernomor atau drawable bertema. Sebagai gantinya, gunakan pernyataanswitchwaktu kompilasi atau petakan konstanta statisR.id,R.string, atauR.drawable. Referensi statis memungkinkan R8 dan AAPT2 melacak resource live yang tepat, menghilangkan overhead pencarian string runtime, dan menghilangkan kebutuhan akankeep.xmlsama sekali. - Mencantumkan nama resource tertentu: Jika diperlukan pencarian dinamis, seperti
oleh pembaca lisensi pihak ketiga, cantumkan ID resource yang tepat di
tools:keep(misalnya,tools:keep="@raw/third_party_licenses"). - Hapus file
keep.xmlyang berlebihan: Jika resource yang tercantum sudah direferensikan secara statis dalam kode (R.raw.foo) atau XML (@raw/foo), alat penyingkat akan otomatis mempertahankannya, sehingga Anda dapat menghapusres/raw/keep.xml.
- Lebih memilih referensi resource statis daripada
Memverifikasi dan mengaudit perubahan aturan
Setiap kali Anda menghapus atau mempersempit aturan penyimpanan di proguard.flags atau keep.xml,
verifikasi bahwa modul dibangun dengan bersih, lulus pengujian unit dan instrumentasi,
serta mempertahankan semua titik entri yang diperlukan.
Membangun dan menguji modul
Bangun modul dengan bersih untuk memverifikasi bahwa R8 dan AAPT2 selesai tanpa peringatan referensi yang hilang:
m <MODULE_NAME>Jalankan pengujian unit dan instrumentasi untuk modul menggunakan
atest:atest <TEST_MODULE_NAME>Untuk aplikasi sistem, layanan istimewa, atau modul yang bergantung pada hardware, jalankan pengujian instrumentasi dan UI pada perangkat fisik target atau di lab pengujian perangkat Anda untuk melatih jalur refleksi runtime, binding IPC, dan inflasi resource.
Memeriksa perbedaan DEX dan resource
Bandingkan APK atau JAR yang dikompilasi sebelum dan sesudah perubahan aturan untuk mengonfirmasi bahwa R8 menghapus kode dan resource yang tidak digunakan tanpa menghapus titik entri yang diharapkan:
Gunakan
apkanalyzerataudexdumpuntuk memeriksa class, metode, dan kolom yang dipertahankan dalam file APK atau DEX output:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkSaat mengubah
keep.xmlatau mengaktifkanshrink_resources, gunakanaapt2 dump resourcesuntuk memverifikasi bahwa build menghapus resource yang tidak digunakan dan mempertahankan resource yang diperlukan:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
Menganalisis radius keep dan subsumsi aturan dengan R8
Compiler R8 open source menyertakan penganalisis Keep Radius
(juga diekspos di Android Studio dan Gradle sebagai
R8 Configuration Analyzer) yang mengukur dampak
persis setiap aturan keep selama kompilasi. Soong mengintegrasikan penganalisis ini
langsung ke build platform Android (dikonfigurasi di
build/soong/java/dex.go).
Untuk menganalisis aturan penyimpanan untuk modul platform atau di seluruh build:
Jalankan build dengan variabel lingkungan
R8_DUMP_KEEP_RADIUS=true:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>Jika
R8_DUMP_KEEP_RADIUS=truedisetel, Soong akan menginstruksikan R8 untuk merekam metrik aturan keep dalam filer8keepradius.pbperantara untuk setiap modul yang dikompilasi diout/soong/.intermediates/. Untuk setiap aturan keep dan anotasikeepanno, R8 mencatat:- Radius penyimpanan langsung: Class, kolom, dan metode persis yang dipertahankan oleh aturan, beserta batasan spesifik yang diterapkan terhadap penyusutan, pengoptimalan, atau pengaburan.
- Pencakupan aturan: Aturan atau anotasi penyimpanan mana yang sudah mempertahankan item yang sama. Jika aturan kustom sepenuhnya tercakup oleh aturan AAPT2 atau aturan dasar global, Anda dapat menghapusnya dengan aman.
- Aturan di seluruh paket dan global: Aturan yang menggunakan karakter pengganti luas di seluruh paket atau menerapkan direktif konfigurasi global.
Konversi output
r8keepradius.pbmenjadi laporan HTML interaktif menggunakanKeepRadiusHtmlReportGenerator(digabungkan dalamprebuilts/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_reportsJika diberi direktori,
KeepRadiusHtmlReportGeneratorakan menelusuri semua file*keepradius*.pb, membuat laporan HTML untuk setiap modul, dan membuatout/keep_radius_reports/keepradius.htmlyang merangkum jumlah item aktif, jumlah item yang dipertahankan, dan aturan pertahankan dengan radius tertinggi di seluruh build. Untuk mengetahui informasi selengkapnya tentang cara menafsirkan skor penyusutan, pengoptimalan, dan peng-obfuscate dalam laporan yang dihasilkan, lihat Menggunakan R8 Configuration Analyzer.
Soong juga mendukung dua variabel lingkungan diagnostik R8 tambahan di
build/soong/java/dex.go:
R8_DUMP_INPUT=true: Menulisr8inputs.zipke direktori perantara modul yang berisi semua JAR input, JAR library, dan konfigurasi ProGuard yang digabungkan untuk reproduksi R8 mandiri.R8_DUMP_PERFETTO_TRACE=true: Menulisr8trace.ptraceke direktori perantara modul untuk memeriksa langkah kompilasi R8 di Perfetto.
Memvalidasi aturan konsumen library
Saat ekspor java_library atau android_library menyimpan aturan ke konsumen hilir (export_proguard_flags_files: true), aturan tersebut tidak boleh menyertakan flag global yang mengubah atau menonaktifkan pengoptimalan untuk aplikasi yang menggunakan.
R8 menyediakan penganalisis aturan keep open source
(ProcessKeepRules), yang diekspos dalam build platform Android
sebagai alat host process-keep-rules (ditetapkan dalam
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>
Alat process-keep-rules mengurai setiap file konfigurasi dan gagal dengan diagnostik file
dan baris jika menemukan direktif yang tidak diizinkan dalam aturan
penggunaan library. Petunjuk yang tidak diizinkan mencakup pengoptimalan global, pengecilan,
atau penonaktifan pengaburan (seperti -dontoptimize atau -dontshrink), pengemasan ulang
paket dan tanda modifikasi akses, tanda diagnostik atau pemetaan, dan
-keepattributes tingkat aplikasi.
Mengaudit pohon sumber dengan pgaudit.py
Untuk mengaudit direktori sumber yang tidak dibangun bersama dengan penganalisis waktu build R8, hierarki platform Android menyertakan skrip pgaudit.py di bagian build/make/core/proguard/tools/. Alat analisis statis ini memindai file Android.bp,
proguard.flags, dan keep.xml di seluruh repositori untuk menandai aturan yang sudah
dicakup oleh AAPT2 atau dasar platform global, karakter pengganti luas, penggantian -dontoptimize, dan aturan penyimpanan khusus pengujian:
# 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
Tim platform dan OEM dapat menggabungkan pgaudit.py untuk triase pohon sumber yang cepat,
process-keep-rules untuk memvalidasi aturan library yang diekspor, dan
R8_DUMP_KEEP_RADIUS=true dengan KeepRadiusHtmlReportGenerator untuk mengukur
radius retensi class, kolom, dan metode yang tepat dari setiap aturan dalam build.