Android platformu derleme sistemi (Soong), kullanılmayan kodları ve kaynakları küçültmek, optimize etmek ve kaldırmak için Android uygulamaları (android_app), testler (android_test) ve compile_dex: true içeren yüklenebilir Java kitaplıkları (services.jar gibi) dahil olmak üzere DEX bayt kodunu derleyen hedeflerde R8 derleyicisini çalıştırır. Soong, statik kitaplıklarda (android_library ve statik java_library) R8'i doğrudan çalıştırmaz. Bunun yerine, tüketici saklama kurallarını (export_proguard_flags_files: true) statik olarak bağlayan alt DEX hedeflerine eklemek ve yaymak için optimize özellik bloğunu kullanır.
Sistem görüntüleri veya tedarikçi firma paketleri oluşturan platform mühendisleri için aşırı geniş kapsamlı saklama kurallarını ortadan kaldırmak, sistem sağlığı açısından doğrudan fayda sağlar:
- Daha küçük sistem bölümü ayak izi: R8, APK'ları ve JAR'ları
/system,/system_ext,/productve/vendor'te paketlemeden önce kullanılmayan sınıfları, yöntemleri ve kaynakları kaldırır. - Daha küçük derlenmiş yapılar: Daha az DEX yöntemi, derleme sırasında veya cihazda derleme sırasında
dex2oattarafından oluşturulan daha küçük.odexve.vdexdosyaları anlamına gelir. - Çalışma zamanında daha az bellek baskısı: Android,
.odex,.vdexve APK kaynak tablolarını, isteğe bağlı sayfalama yapılanmmapçağrılarını kullanarak işlem belleğiyle eşlediğinden daha küçük ikili programlar, uygulama başlatma sırasında önemli sayfa hatalarını azaltır ve işlemler arasında yerleşik kod ve kaynak belleğini düşürür. Derlenmiş uygulama kodunun cihaz belleğini nasıl etkilediği hakkında daha fazla bilgi için Uygulama kodu bellektir başlıklı makaleyi inceleyin. - Daha etkili tüm program optimizasyonu: Dar tutma kısıtlamaları, R8'in satır içi yöntemleri kullanmasına, arayüz ve sanal çağrıları sanallaştırmasına, kullanılmayan alanları ayıklamasına ve sabitleri sınıflar arasında yaymasına olanak tanır.
Soong'da R8 optimizasyonunu yapılandırma
Android.bp dosyalarında, android_app ve yüklenebilir java_library hedeflerinde (veya tüketici saklama kurallarını dışa aktarmak için android_library ve statik java_library modüllerinde) optimize özellik bloğunu kullanarak R8 optimizasyonunu yapılandırın:
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
Aşağıdaki tabloda, Soong'daki en yaygın optimize özellikleri (build/soong/java/dex.go içinde tanımlanmıştır) özetlenmiştir:
| Özellik | Açıklama |
|---|---|
enabled |
R8'in hedefte çalışıp çalışmayacağını kontrol eder. Tüm android_app hedefleri için varsayılan olarak true değerine ayarlanır.
|
shrink |
Erişilemeyen sınıfları, alanları ve yöntemleri kaldırmak için ağaç sallamayı kontrol eder. android_app hedefleri için varsayılan olarak true değerine ayarlanır (bağımsız java_library ve test modülleri için false değerine ayarlanır. Bu modüller, açıkça ayarlanmadığı sürece -dontshrink değerini iletir).
|
optimize |
Yöntem satır içi ekleme, sınıf birleştirme, sabit yayma ve kullanılmayan dal kaldırma gibi bayt kodu optimizasyonlarını kontrol eder. android_app hedefleri için varsayılan olarak true değerine ayarlanır (RELEASE_R8_OPTIMIZE_BY_DEFAULT yayınlanan derleme işareti tarafından kontrol edilir).
|
obfuscate |
Tanımlayıcı sadeleştirmesini ve yeniden adlandırmasını kontrol eder. Geçmiş uyumluluk için varsayılan olarak false değerine ayarlanır ancak DEX boyutunu küçültmek ve daha kapsamlı optimizasyonları etkinleştirmek için mümkün olduğunda true değerine ayarlayın (Mümkün olduğunda kod karartmayı etkinleştirme bölümüne bakın).
|
shrink_resources |
Kod daraltma işleminden sonra paketlenmiş APK'dan kullanılmayan kaynakları (res/ giriş) kaldırır. Varsayılan değer: false.
|
optimized_shrink_resources |
Entegre R8 kodunu ve kaynak küçültücü ardışık düzenini çalıştırır. Böylece R8, kod ve kaynak referanslarını tek bir geçişte birlikte izler. shrink_resources: true ayarlandığında varsayılan olarak RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT (standart platform derlemelerinde true) değerine ayarlanır.
|
proguard_flags_files |
Özel saklama kuralları içeren modüle özgü .flags veya .pro dosyalarını listeler. Standart ek açıklamalar veya varsayılanlar yeterli olduğunda özel dosyalar eklemekten kaçının.
|
export_proguard_flags_files |
Bu kitaplığın proguard_flags_files öğesini, statik olarak bağlı olan alt modüllere yayar.
|
trace_references_from |
Bayt kodu bu hedefe referans veren doğrudan DEX derlemeye bağımlı hedefleri (instrumentation_for veya libs aracılığıyla bağlı) listeler. R8, bu hedefleri otomatik olarak izler ve saklar (ayrıca override_android_app ve override_android_test varyantları arasında yayılır ve bir .impl bölmesiyle eşlendiğinde bağımlı olmayan tamamlayıcı Java kitaplıkları için desteklenir).
|
allow_traced_references |
Doğrudan DEX derlemeye bağlı hedeflerin (instrumentation_for veya libs aracılığıyla bağlanan, trace_references_from içinde listelenemeyen çapraz depo ya da tedarikçi testleri gibi), trace_references: true ayarını yaparak bayt kodu referanslarını bu hedefte izlemeyi etkinleştirmesine olanak tanır.
|
trace_references |
allow_traced_references: true içeren bir hedefin doğrudan DEX derleme bağımlılığında true olarak ayarlandığında bu modülde R8 tracereferences çalıştırılır ve oluşturulan saklama kuralları hedef modüle iletilir.
|
protect_api_surface |
--protect-api-surface değerini R8'e iletir. java_sdk_library üzerinde ayarlandığında, etkinleştirilen tüm API kapsamlarında (herkese açık, sistem, modül kitaplığı, sistem sunucusu ve test) Metalava API saklama kurallarını otomatik olarak oluşturur ve uygulama kitaplığına ekler.
|
Statik kitaplıklar (android_library, java_library ve AAR içe aktarmaları), R8 küçültme ve bayt kodu optimizasyonunu etkinleştirmek için bunları statik olarak (doğrudan veya geçişli olarak) bağlayan tüm alt DEX derleme hedeflerini zorunlu kılmak üzere Android.bp içinde required_downstream_optimization: { enabled: true, optimize: true } değerini de ayarlayabilir. Soong, bunu androidx.compose.runtime_runtime üzerinde otomatik olarak etkinleştirir. Böylece Jetpack Compose'u bağlayan hedefler R8 ile optimize edilir.
Mümkün olan her yerde kod karartmayı etkinleştirme
Soong'da obfuscate, geçmiş uyumluluk için varsayılan olarak false değerine ayarlanır ancak mümkün olduğunda android_app ve bağımsız DEX hedeflerinde obfuscate: true değerini açıkça ayarlamanız gerekir:
- Daha küçük DEX ve
.vdexayak izi: Paketleri, sınıfları, alanları ve yöntemleri kısa tanımlayıcılar (a,b) olarak yeniden adlandırmak, DEX dize havuzunu (string_idsvestring_data_item) ve tür tanımlayıcılarını küçültür. Android,.vdexve.odexdosyalarını işlem belleğiyle eşlediğinden daha küçük sembol tabloları, hem sistem bölümü boyutunu hem de çalışma zamanı bellekte kaplanan yeri doğrudan azaltır. - Daha kapsamlı program optimizasyonları: R8'in tanımlayıcıları yeniden adlandırmasına izin vermek, ad çakışmalarını önlemek için R8'in atlaması gereken paketlerde sınıf birleştirme, paket düzleştirme ve sentetik sınıf tekilleştirme işlemlerini etkinleştirir.
- Tam yığın izleme simgeselleştirmesi: Soong'da kod karartmayı etkinleştirmek, hata ayıklama özelliğini azaltmaz. Soong, R8 ile derlenen her hedef için modülün ara dizininde bir
proguard_dictionaryeşleme dosyası oluşturur, tüm modül sözlüklerini derlemeninproguard-dict.zipyapısında birleştirir, DEX başlığına bir eşleme karması (--map-id-template) yerleştirir veretrace'in yığın izlemelerini otomatik olarak sembolize edebilmesi için sınıfSourceFileözelliklerini (--source-file-template) yeniden yazar.
obfuscate: false (veya herkese açık API adlarını açıkça koru) yalnızca şunlar için geçerli olsun:
- bootclasspath veya
system_serversınıf yolundaki paylaşılan kitaplıklar: Çalışma zamanında diğer modüller tarafından dinamik olarak bağlanan harici bir API yüzeyini (ör.framework.jar,services.jarveya<uses-library>hedefleri) gösteren modüller (java_libraryveyajava_sdk_library),obfuscate: falsedeğerini korumalı veyaprotect_api_surface: true,@KeepForApiya da-keepkurallarını kullanarak API yüzeylerini açıkça korumalıdır. Böylece, taslaklarına göre derlenen çağrıcılar çalışma zamanında sınıf ve üye adlarını çözümleyebilir.java_sdk_librarymodüllerindeprotect_api_surface: trueayarı, tüm etkin API kapsamlarında (herkese açık, sistem, modül kitaplığı, sistem sunucusu ve test) Metalava ProGuard saklama kurallarını otomatik olarak oluşturur ve uygulama kitaplığına ekler. Güncellenemeyen bootclasspath hedeflerinde (framework-minus-apex,extveframework-location) genelleştirilmiş R8 optimizasyonu etkinleştirildiğinde, etkinboot/hiddenapi/*.txtdosyalarında listelenen üyeleri korumak içinframework-hiddenapi-proguard-rules(hiddenapi_to_proguardtarafından oluşturulur) de dahil edilir (hiddenapi-max-target-o.txthariç tutulur).
Bir uygulamada obfuscate: true özelliğini etkinleştirmeden önce aşağıdaki taşıma ön koşullarını doğrulayın:
- Harici test APK bağımlılıkları: Harici bir
android_testAPK'sıinstrumentation_for: "MyApp"ayarlar veMyApp'nin dahili sınıflarını veya yöntemlerini doğrudan çağırırsa bu sembollerin yeniden adlandırılması, test çalıştırma zamanındaNoSuchMethodErrorveyaNoClassDefFoundErrorhatasına neden olur.trace_references_from(veyatrace_references: trueileallow_traced_references) yapılandırın, testi statik olarakMyApp.implbağlayan kendi kendini izleyen bir APK olarak yapılandırın veya test kancalarına@VisibleForTestingile ek açıklama ekleyin (2. Adım: Test odaklı saklama kurallarını taşıyın bölümüne bakın). Böylece, uygulamanın geri kalanı gizlenirken testler için gereken dahili semboller korunur. - Dize tabanlı yansıma ve JNI: Bir modül; sınıfları, yöntemleri veya alanları, saklama kuralları ya da ek açıklamalar olmadan dize adlarıyla (
Class.forName,getDeclaredMethodveya JNIFindClassveGetMethodID) ararsa kod karartma bu hedefleri yeniden adlandırır ve çalışma zamanı aramalarını bozar. (Ek açıklama eklenmemiş yansıtmanınshrink: trueveoptimize: truealtında da başarısız olduğunu unutmayın.) R8'in adlarını koruması ve modülün geri kalanını gizlemesi için bu giriş noktalarına Ek Açıklamaları Saklama Kılavuzu (@UsesReflection,@UsedByReflectionveya@UsedByNative) ile ek açıklama ekleyin.
Sıfır özel işaret ilkesine uyun
İdeal Android platform modülünde özel proguard.flags veya keep.xml dosyaları bulunmaz. Android platformu derlemesinde, özel saklama kurallarının büyük çoğunluğu gereksizdir:
- Platform temelleri ve AAPT2: Çoğu giriş noktası, global platform temelleri (ör.
@Keep, JNInativeyöntemleri ve@VisibleForTesting) tarafından otomatik olarak korunur veya AAPT2 tarafındanAndroidManifest.xmlve düzen kaynaklarından oluşturulur (Varsayılan platform saklama kurallarını anlama bölümüne bakın). - Hedeflenen alternatifler: Giriş noktalarının korunması gereken durumlarda, ayrılmış
.flagsdosyaları yerine bildirim sitesi ek açıklamalarını (keepanno,@VisibleForTesting), dışa aktarılan kitaplık kurallarını (export_proguard_flags_files: true) veya statik test bağlantısını tercih edin (Mevcut saklama kurallarını denetleme ve taşıma bölümüne bakın).
Özel bir proguard.flags veya keep.xml dosyası eklemeden ya da saklamadan önce, kuralın varsayılan referanslar tarafından zaten işlenip işlenmediğini veya kod ek açıklamalarına taşınıp taşınamayacağını doğrulayın.
Varsayılan platform saklama kurallarını anlama
Soong, aşağıdaki global temel kuralları build/soong/java/dex.go içinde yapılandırılmış DEX derleme hedeflerindeki (android_app, android_test ve yüklenebilir java_library modülleri) her R8 çağrısına otomatik olarak iletir:
build/make/core/proguard.flags: Tüm paketlerde@com.android.internal.annotations.VisibleForTestingile veandroid.**,com.android.**vecom.google.android.**paketlerinde@VisibleForTesting(androidx.annotation.VisibleForTestingveyacom.google.common.annotations.VisibleForTesting) ile ek açıklama eklenmiş sınıfları ve üyeleri korur. Ayrıca@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallbackve@dalvik.annotation.optimization.**dillerini de korur.build/make/core/proguard_basic_keeps.flags: Yığın izlemeleri (stack trace) içinSourceFileözelliklerini, çalışma zamanı görünürlük ek açıklamalarını (RuntimeVisible*Annotations),ExceptionsveAnnotationDefaultözelliklerini,nativeyöntemlerini,Serializableüyelerini,@JavascriptInterfaceyöntemlerini,Throwable(String)kurucularını,Parcelable$CREATORalanlarını ve protobufMessageLitealanlarını korur.build/make/core/proguard/kotlin.flags: Belirli Kotlin meta ek açıklamaları (kotlin.Metadatavekotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) için zararsız uyarıları sessize alır ve yayınlanan derlemelerdeki KotlinDebugMetadataek açıklamalarını kaldırır.build/make/core/proguard/checknotnull.flags: Yaygın null kontrolü yardımcı çağrılarını (com.google.common.base.Preconditions.checkNotNullvedagger.internal.Preconditions.checkNotNull*) kısa bayt kodu null kontrolleriyle değiştirir. Bu dosya, çerçeve API sınırları genelinde açık istisna mesajlarını korumak için kasıtlı olarakObjects.requireNonNullöğesini atlar.build/make/core/proguard/enumvalues.flags: Derleme yapılandırması tarafından devre dışı bırakılmadığı süreceenumtürlerindevaluesvevalueOfyöntemlerini korur.- AAPT2 tarafından otomatik olarak oluşturulan kurallar: AAPT2, kayıtlı her
Activity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, özelViewalt sınıfı,Preferencealt sınıfı ve XMLandroid:onClickyöntemi için tam saklama kuralları oluşturmak üzere birleştirilmişAndroidManifest.xml, düzen XML ve tercih XML dosyalarını inceler.
Mevcut saklama kurallarını denetleme ve taşıma
Bir platform deposundaki mevcut proguard.flags veya keep.xml dosyalarını denetlerken her kuralı aşağıdaki dört adımlı hiyerarşiye göre değerlendirin:
1. adım: Gereksiz veya eski kuralları silin
Genel temel çizgiler, AAPT2 manifest ve düzen kuralları veya R8 varsayılanları tarafından zaten kapsanan kuralları ve artık mevcut olmayan sınıflara veya paketlere referans veren kuralları silin.
Bir .flags dosyasındaki tüm kurallar gereksizse dosyayı silin ve Android.bp dosyasından proguard_flags_files satırını kaldırın. Kalan optimize bloğu yalnızca varsayılan ayarları yeniden belirtiyorsa gereksiz bloğu kaldırın ve derleme dosyasını bpfmt -w Android.bp ile biçimlendirin. Bir paketi temizlerken alt dizinlerdeki tamamlayıcı modüllerin (ör. Kotlin hedef varyantları) aynı işaret dosyasına referans verip vermediğini kontrol edin ve bunları birlikte güncelleyin.
2. adım: Test odaklı saklama kurallarını taşıyın
Test odaklı saklama kurallarını, aşağıdaki kalıplardan birini kullanarak özel üretim .flags dosyalarından çıkarın:
Test veya tamamlayıcı hedeflerden (
trace_references_fromveyaallow_traced_references) referansları izleme: Hem hedef hem de doğrudan bağımlı bir modül kendi DEX'lerini (android_app,android_testveya dexedjava_library) derlediğinde veinstrumentation_forya dalibsaracılığıyla bağlandığında Soong, bağımlı modülde R8tracereferencesçalıştırabilir ve oluşturulan saklama kurallarını, bağımlılık döngüsü oluşturmadan veya manuel.implkitaplık bölme işlemi gerektirmeden hedefin R8 derlemesine besleyebilir:Aynı depodaki testler (
trace_references_from): Hedef modüle doğrudaninstrumentation_forveyalibsbağımlı olanları listeleyin (Bu,override_android_appveoverride_android_testvaryantları arasında da otomatik olarak yayılır ve.implbölmesiyle eşlendiğinde bağımlı olmayan tamamlayıcı Java kitaplıklarını desteklemeye devam eder):android_app { name: "MyApp", srcs: ["src/**/*.java"], optimize: { obfuscate: true, shrink_resources: true, trace_references_from: ["MyAppTests"], }, } android_test { name: "MyAppTests", instrumentation_for: "MyApp", srcs: ["tests/**/*.java"], }Depolar arası veya tedarikçi testleri (
allow_traced_referencesvetrace_references): Hedef modül, bağımlı modülü doğrudantrace_references_fromiçinde listeleyemediğinde (başka bir depodaki veya tedarikçi ağacındaki testler gibi) hedef modüldeallow_traced_references: truedeğerini ayarlayın vetrace_references: trueile her bağımlı modülden etkinleştirin:android_app { name: "MyApp", srcs: ["src/**/*.java"], optimize: { allow_traced_references: true, }, } android_test { name: "MyAppVendorTests", instrumentation_for: "MyApp", srcs: ["tests/**/*.java"], optimize: { trace_references: true, }, }Testlerde dize tabanlı yansıma:
tracereferences, bayt kodu sabit havuz referanslarını inceler ve testlerde dize tabanlı yansımayı (Class.forName,getDeclaredField,getDeclaredMethodveya yansımalı alan yerleştirme yardımcıları) algılayamaz. Yansıtmalı olarak erişilen üretim alanlarına ve yöntemlerine@VisibleForTesting(veya@UsedByReflection) ile ek açıklama ekleyin.
Uygulama kitaplığını testlere bağlama (
static_libs): Üretim APK'sında yalnızca test amaçlı giriş noktası kalmamasını ve test değişikliklerinin üretim hedefinde R8'i yeniden tetiklememesini istiyorsanız uygulama kaynak dosyalarını birandroid_library(MyApp.impl) içine yerleştirin veMyApp.implöğesini hemMyApphem deMyAppTestsöğesine statik olarak bağlayın: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"], }Bu 3 modüllü kalıp,
MyAppTestsmodülünün dahili sınıflara tam erişimle kendi kendini izleyen bir enstrümantasyon testi olarak çalışmasına olanak tanır. Aynı zamandaMyAppmodülünün yalnızca canlı sürüm giriş noktalarına göre küçültülüp kodunun karartılmasına izin verir.Test kancalarına
@VisibleForTestingile ek açıklama ekleyin: Harici bir test APK'sı, birandroid_apphedefinde yalnızca birkaç dahili yöntem veya kurucu çağırıyorsa bu bildirimlere@VisibleForTestingile ek açıklama ekleyebilirsiniz. Genelbuild/make/core/proguard.flagstemel çizgisi, özel.flagsdosyaları olmadanandroid.**,com.android.**vecom.google.android.**paketlerindeki@VisibleForTestingöğeyi otomatik olarak saklar. (Bu ad alanlarının dışındaki tedarikçi modülleri içintrace_references_from,@UsedByReflectionveya dışa aktarılan kitaplık kurallarını kullanın.)trace_references_fromveyatrace_referencesyerine@VisibleForTestingile manuel olarak ek açıklama eklerken Mockitomock(...)veyaspy(...)'ya iletilen sınıflara da ek açıklama ekleyin (yalnızca sarmalanmış yöntemlere değil). Bunun nedeni, cihaz üzerindemockito-target(dexmaker-mockito) çalışma zamanı alt sınıfları oluşturması ve R8'in alt sınıfı olmayan sınıflarıfinal(MockitoException: Can't mock/spy class ... - final class) olarak işaretleyebilmesidir.Çakışan statik kitaplıklardan kaçının veya bunları yeniden paketleyin (
jarjar_rules): Hemandroid_apphem deinstrumentation_fortest APK'sı aynı kitaplığı statik olarak bağladığında (doğrudan, örneğinguavaveya geçişli olarak),tracereferencestestte tanımlanan bu sınıfları görür ve uygulama için saklama kuralı yayınlamaz. Çalışma zamanında ise uygulamanın üst sınıf yükleyicisi, R8 ile küçültülmüş sınıflarıyla testin kopyasını gölgeler veIllegalAccessErrorveyaNoSuchMethodErrorhatasına neden olur. Testin kendi paketlenmiş kopyasına ihtiyacı yoksa çakışmayı önlemek için kopyayı testinstatic_libsöğesinden kaldırın (veyalibsaracılığıyla bağlayın). Aksi takdirde, uygulamanın çakışan statik kitaplık paketlerinijarjar_ruleskullanarak modüle özgü bir ön ek altında yeniden paketleyin.
3. adım: Kuralları, sahibi olan kitaplıktan dışa aktarın
Paylaşılan bir java_library veya android_library, kendi dahili yansıma ya da JNI geri çağırmaları için saklama kuralları gerektiriyorsa kuralları kitaplık hedefinde tanımlayın ve export_proguard_flags_files: true değerini ayarlayın:
java_library {
name: "my-shared-library",
srcs: ["src/**/*.java"],
optimize: {
proguard_flags_files: ["proguard.flags"],
export_proguard_flags_files: true,
},
}
my-shared-library öğesini statik olarak bağlayan tüm alt android_app ve kitaplık hedefleri, bu kuralları otomatik olarak devralır. Bu nedenle, alt uygulamaların bu kuralları kopyalaması gerekmez. Farklı dizinlerdeki birden fazla modülün tek bir kod kitaplığına bağlı olmayan bir kural kümesini paylaşması gerektiğinde, modüllerin paket sınırları genelinde :my-shared-flags'e temiz bir şekilde referans verebilmesi için .flags dosyasını Android.bp içinde açık bir filegroup aracılığıyla yayınlayın. Alt uygulama optimizasyonunu kısıtlamadan kitaplık tüketici saklama kuralları yazma hakkında genel bilgi için Kitaplık yazarları için optimizasyon başlıklı makaleyi inceleyin.
4. adım: Kaynak kodundaki bildirimlere ek açıklama ekleme
Bir sınıfa, yönteme, kurucuya veya alana yansıma ya da JNI aracılığıyla erişildiğinde ve AAPT2 veya genel referanslar tarafından kapsanmadığında, .flags dosyalarındaki ayrılmış -keep kurallarını Keep Ek Açıklamaları Kılavuzu'ndaki kaynak ek açıklamalarıyla değiştirin (keepanno Javadoc referansına bakın):
@UsesReflection: Yansımayı gerçekleştiren kodu kontrol ederken bu ek açıklamayı tercih edin. Dinamik olarak erişilen hedef sınıfları, yöntemleri veya alanları bildirmek için bu ek açıklamayı yansıma çağrısı sitesine yerleştirin.@UsesReflection, ek açıklamalı çağrı sitesinin erişilebilir olduğuna dair bir ön koşulu otomatik olarak kodladığından, çağrı sitesi kullanılmıyorsa R8 hem arayanı hem de yansıtıcı hedefi budar.@UsedByReflection: Harici kod veya kitaplıklar tarafından yansıtmalı olarak örneklendirilen ya da çağrılan sınıflara, yöntemlere, alanlara veya oluşturuculara yerleştirin. Örneğin,BundleveyaSettingsanahtarlarındanClass.forNameile yüklenen sınıflar ya da dinamik sınıf yükleyiciler üzerinden yüklenen eklenti sınıfları. R8'in yalnızca tam yansıtıcı sözleşmeyi tutması ve sınıfın kullanılmayan üyelerini optimize etmeye veya ayıklamaya devam edebilmesi içinkind(ör.KeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition) ve parametre kısıtlamalarını belirtin. AAPT2,JobServiceveyaBroadcastReceivergibi manifest dosyasına kayıtlı bileşenleri zaten sakladığı için bunlara@UsedByReflectioneklemeyin.@UsedByNative:GetMethodID,GetStaticMethodIDveyaGetFieldIDkullanılarak C ya da C++ JNI kodundan erişilen yöntemlere veya alanlara yerleştirin.@KeepForApi: Kitaplık API sınıflarına veya üyelerine yerleştirilir. Kitaplık dağıtımdan önce küçültüldüğünde bu sınıfların veya üyelerin bozulmadan kalması gerekir.@Keep(androidx.annotation.Keep):keepannogeçerli olmadığında yedek olarak kullanın. Bir sınıfa@Keepuygulandığında sınıf ve tüm üyeleri koşulsuz olarak saklanır. Bir yönteme veya alana@Keepuygulamak, sınıf hiçbir zaman örneklendirilmese bile üyeyi ve onu içeren sınıfı koruyan koşulsuz bir giriş noktası görevi görür.keepannoise koşullu erişilebilirliği ifade eder.
Soong modülünde R8 keepanno ek açıklamalarını kullanmak için:
Android.bpiçindelibsadlı gruba"keepanno-annotations"adlı kullanıcıyı ekleyin:libs: [ "keepanno-annotations", ],com.android.tools.r8.keepanno.annotations.*öğesini içe aktarın ve Java veya Kotlin kaynak kodunda bildirime ya da çağrı sitesine ek açıklama ekleyin: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,
keepannoek açıklamalarını doğrudan kendi dahili saklama kuralı modeline çevirir ve ek açıklamaları nihai DEX çıkışından çıkararak çalışma zamanı bayt kodu ek yükünü sıfıra indirir.
Yaygın hatalardan kaçınma
Aşağıdaki bölümlerde, platform kodunda sık karşılaşılan proguard.flags ve keep.xml sorunları ve bunların nasıl düzeltileceği açıklanmaktadır.
Geniş bileşen saklama kuralları
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- Performansı neden olumsuz etkiler? Bu kural, AAPT2 ile tamamen gereksizdir.
Bileşenin nihai birleştirilmiş
AndroidManifest.xmliçinde kayıtlı olup olmadığını kontrol etmeden joker karakter kullandığı için R8'i, kullanılmayan kitaplık bileşenleri ve devre dışı bırakılmış hata ayıklama etkinlikleri de dahil olmak üzere sınıf yolunun herhangi bir yerinde bulunan herActivity,ServiceveyaBroadcastReceiveralt sınıfını korumaya zorlar. - Önerilen düzeltme: Kuralı silin. AAPT2, birleştirilmiş manifesti inceler ve kayıtlı bileşenler için tam
-keepkuralları oluşturur.
Geniş XML tıklama işleyici saklama kuralları
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- Performansı neden olumsuz etkiler? Modüldeki her sınıfta her
public void *(View)yöntemini korumak, R8'in tek birViewparametresi kabul eden yöntemleri kaldırmasını veya satır içine almasını engeller. - Önerilen düzeltme: Kuralı silin. AAPT2, düzen XML dosyalarını tarar ve
android:onClicközellikleri tarafından referans verilen yöntemler için hedeflenen saklama kuralları oluşturur.
Broad View alıcı ve ayarlayıcı saklama kuralları
# 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*();
}
- Performansı olumsuz etkileme nedeni: Bu kural, R8'i uygulamadaki her
Viewalt sınıfında ve tüm bağlı kitaplıklarda (AndroidX ve Material kitaplıkları dahil) her alıcı ve ayarlayıcıyı korumaya zorlar. Bu da ölü yöntem kaldırma ve kullanıcı arayüzü kodunda satır içi yerleştirmeyi engeller. - Önerilen düzeltme: Kuralı silin. AAPT2, düzen XML dosyalarından şişirilen özel
Viewsınıfları için yapıcıları zaten korur. Kod,ObjectAnimator.ofFloat(view, "translationZ", ...)gibi yansıtıcı dize adları kullanarak bir görünüm özelliğine animasyon uyguluyorsa yansımayı tamamen önlemek için dize adını yazılı bir özellik referansıyla (View.TRANSLATION_Zveya özel birFloatPropertyya daIntPropertyuygulaması) değiştirin. Yansıtmalı özellik erişiminden kaçınılamıyorsa belirli alıcı veya ayarlayıcıya@UsedByReflectionile ek açıklama ekleyin.
Genel optimizasyon veya gizleme devre dışı bırakma
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Performansı neden olumsuz etkiler?
.flagsdosyasına-dontoptimizeveya-dontshrinkeklemek, modülünAndroid.bpayarlarını sessizce geçersiz kılar ve tüm hedef genelinde optimizasyon geçişlerini devre dışı bırakır. Daha da kötüsü, bir kitaplık-dontoptimizeiçeren bir.flagsdosyası dışa aktarırsa kitaplığı bağlayan her altandroid_appiçin R8 optimizasyonunu devre dışı bırakır. - Önerilen düzeltme:
.flagsdosyadan-dontoptimize,-dontshrinkve-dontobfuscateerişimini kaldırın.Android.bpiçinde optimizasyon davranışını açıkça kontrol etmek için yaprak hedefteoptimizebloğunu (shrink,optimize,obfuscate) kullanın.
Onaylanmış kurallardaki teşhis işaretleri
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- Derlemeyi neden olumsuz etkiler? Teşhis işaretleri, korumalı alana alınmış Soong derlemeleri sırasında derleme günlüklerini doldurur veya çıkış dosyalarını yerel yollara yazmaya çalışır.
- Önerilen düzeltme: Bu işaretleri, kaydedilen
.flagsdosyalardan silin. Soong,proguard_dictionaryveproguard_usage.zipgibi R8 eşleme ve kullanım çıktılarınıout/soong/.intermediates/altındaki modülün ara dizinine otomatik olarak yazar.
Test kodu için üretimde saklama kuralları
- Performansı neden olumsuz etkiler? Sırf test erişimi için özel
-keepkuralları eklemek, bu kodun gizlenmeden kalmasına ve üretim derlemelerinde tutulmasına neden olur.trace_references_from(veyatrace_references: trueileallow_traced_references) yapılandırılırken ya da yöntemlere@VisibleForTestingile ek açıklama eklenirken manuel-keepkurallarının sürdürülmesinden kaçınılır ve yalnızca testlerin referans verdiği öğeler korunur. Ancak bu semboller, üretim ikili programında gönderilmeye devam eder. - Önerilen düzeltme:
trace_references_from(veyaallow_traced_referencesvetrace_references: true) seçeneğini etkinleştirerek özel test-keepkurallarını kaldırın ya da uygulamayı, 2. adım: Test odaklı saklama kurallarını taşıma bölümünde açıklandığı gibi, yalnızca test amaçlı giriş noktalarını üretim APK'sının tamamen dışında tutmak içinstatic_libskullanarak kendi kendini izleyen bir test APK'sına bağlı bir.implkitaplığı halinde yapılandırın.
keep.xml dosyasında geniş kapsamlı kaynak joker karakterleri
<!-- Don't do this in res/raw/keep.xml: -->
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@raw/*,@drawable/*,@string/*" />
- Performansı neden olumsuz etkiler? Genel joker karakterler, modül ve bağımlılıkları genelinde eşleşen türdeki her kaynağı korur. Bu durum, kaynak küçültmeyi (
shrink_resources: true) engeller ve APK ile eşlenenresources.arsctablosunu şişirir. - Önerilen düzeltme:
keep.xmlyerine statik kaynak referanslarını tercih edin:Numaralandırılmış deneme dizeleri veya temalı çizilebilir öğeler gibi sınırlı bir kaynak grubunu dinamik olarak aramak içinResources.getIdentifieryöntemini kullanmaktan kaçının. Bunun yerine, derleme zamanıswitchifadesi kullanın veya statikR.id,R.stringya daR.drawablesabitleri üzerinde eşleme yapın. Statik referanslar, R8 ve AAPT2'nin tam olarak canlı kaynakları izlemesine, çalışma zamanı dize arama ek yükünü ortadan kaldırmasına vekeep.xmlihtiyacını tamamen ortadan kaldırmasına olanak tanır.- Belirli kaynak adlarını listeleyin: Üçüncü taraf lisans okuyucu gibi dinamik arama gerekiyorsa tam kaynak tanımlayıcılarını
tools:keepiçinde listeleyin (örneğin,tools:keep="@raw/third_party_licenses"). - Gereksiz
keep.xmldosyalarını silin: Listelenen kaynaklara kodda (R.raw.foo) veya XML'de (@raw/foo) statik olarak referans veriliyorsa küçültücü bunları otomatik olarak saklar. Bu nedenleres/raw/keep.xmldosyasını silebilirsiniz.
Kural değişikliklerini doğrulama ve denetleme
proguard.flags veya keep.xml dosyasındaki saklama kurallarını kaldırdığınızda ya da daralttığınızda modülün sorunsuz bir şekilde derlendiğini, birim ve enstrümantasyon testlerini geçtiğini ve gerekli tüm giriş noktalarını koruduğunu doğrulayın.
Modül oluşturma ve test etme
R8 ve AAPT2'nin eksik referans uyarıları olmadan tamamlandığını doğrulamak için modülü temiz bir şekilde derleyin:
m <MODULE_NAME>atestkullanarak modül için birim ve enstrümantasyon testleri çalıştırın:atest <TEST_MODULE_NAME>Sistem uygulamaları, ayrıcalıklı hizmetler veya donanıma bağlı modüller için hedef fiziksel cihazlarda ya da cihaz test laboratuvarınızda araç ve kullanıcı arayüzü testleri çalıştırarak çalışma zamanı yansıma yollarını, IPC bağlamalarını ve kaynak şişirmeyi test edin.
DEX ve kaynak farklarını inceleme
R8'in beklenen giriş noktalarını kaldırmadan ölü kodları ve kaynakları kaldırdığını doğrulamak için kural değişikliklerinden önce ve sonra derlenen APK veya JAR'ı karşılaştırın:
Çıkış APK veya DEX dosyalarında tutulan sınıfları, yöntemleri ve alanları incelemek için
apkanalyzerveyadexdumpkullanın:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkkeep.xmlpolitikasını değiştirirken veyashrink_resourcespolitikasını etkinleştirirken derlemenin kullanılmayan kaynakları kaldırdığını ve gerekli kaynakları koruduğunu doğrulamak içinaapt2 dump resourcesaracını kullanın:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkTam bir platform derlemesi olmadan işaret değişikliklerini çevrimdışı doğrulamak için bir modülün R8 öncesi
classes.jardosyasında doğrudanprebuilts/r8/r8.jarçalıştırırken hem modülün--libsınıf yolu JAR'lerini (android.jar,framework.jarve paylaşılanlibs) hem de AAPT2'ninAndroidManifest.xmlve düzen XML'lerinden oluşturulanproguard.optionskurallarını iletin. Bu girişler olmadan R8, çerçeve üst türlerini (Activity,Service,Phone,Handler) çözemez ve hiyerarşi yöntemlerini eksik tutar.
R8 ile saklama yarıçapını ve kural kapsamını analiz etme
Açık kaynak R8 derleyicisi, derleme sırasında her saklama kuralının tam etkisini ölçen bir Keep Radius analiz aracı (Android Studio ve Gradle'da R8 Yapılandırma Analiz Aracı olarak da gösterilir) içerir. Soong, bu analiz aracını doğrudan Android platformu derlemesine entegre eder (build/soong/java/dex.go içinde yapılandırılır).
Bir platform modülü veya derlemenin tamamı için saklama kurallarını analiz etmek istiyorsanız:
Derlemeyi
R8_DUMP_KEEP_RADIUS=trueortam değişkeniyle çalıştırın:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>R8_DUMP_KEEP_RADIUS=trueayarlandığında Soong, R8'eout/soong/.intermediates/altındaki her derlenmiş modül için saklama kuralı metriklerini ara birr8keepradius.pbdosyasına kaydetmesini söyler. R8, her saklama kuralı vekeepannoek açıklaması için şunları kaydeder:- Doğrudan koruma kapsamı: Kural tarafından korunan sınıflar, alanlar ve yöntemler ile küçültme, optimizasyon veya kod karartmaya karşı uyguladığı belirli kısıtlamalar.
- Kural kapsamı: Aynı öğeleri zaten saklayan diğer saklama kuralları veya ek açıklamalar. Özel bir kural, AAPT2 kuralı veya genel temel kural tarafından tamamen kapsanıyorsa bu kuralı güvenle silebilirsiniz.
- Paket genelinde ve global kurallar: Paket genelinde geniş joker karakterler kullanan veya global yapılandırma yönergeleri uygulayan kurallar.
KeepRadiusHtmlReportGenerator(prebuilts/r8/r8.jariçinde paketlenmiş) kullanarakr8keepradius.pbçıkışını etkileşimli bir HTML raporuna dönüştürün:# 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_reportsBir dizin verildiğinde
KeepRadiusHtmlReportGeneratortüm*keepradius*.pbdosyalarını tarar, her modül için bir HTML raporu oluşturur ve derleme genelinde etkin öğe sayılarını, saklanan öğe sayılarını ve en yüksek yarıçaplı saklama kurallarını özetleyenout/keep_radius_reports/keepradius.htmldosyasını oluşturur. Oluşturulan rapordaki küçültme, optimizasyon ve kod karartma puanlarını yorumlama hakkında daha fazla bilgi için R8 Yapılandırma Analiz Aracı'nı kullanma başlıklı makaleyi inceleyin.
Soong, build/soong/java/dex.go içinde ek R8 teşhis ve iç döngü ortam değişkenlerini de destekler:
R8_DUMP_INPUT=true: Bağımsız R8 yeniden üretimi için tüm giriş JAR'larını, kitaplık JAR'larını ve birleştirilmiş ProGuard yapılandırmalarını içeren modülün ara dizininer8inputs.zipyazar.R8_DUMP_PERFETTO_TRACE=true: Perfetto'da R8 derleme geçişlerini incelemek için modülün ara dizininer8trace.ptraceyazar.SOONG_SKIP_TRACE_REFERENCES=true: Test kodunda iterasyon yaparken yerel iç döngü derlemelerini hızlandırmak içintrace_references_fromveyatrace_referencestarafından yapılandırılantracereferenceskurallarının çalıştırılmasını atlar.
Kitaplık tüketici kurallarını doğrulama
Bir java_library veya android_library, kuralları alt tüketicilere (export_proguard_flags_files: true) aktardığında bu kurallar, tüketen uygulama için optimizasyonu değiştiren veya devre dışı bırakan genel işaretler içermemelidir.
R8, Android platformu derlemesinde process-keep-rules ana makine aracı olarak sunulan (prebuilts/r8/Android.bp içinde tanımlanır) açık kaynaklı bir saklama kuralı analiz aracı (ProcessKeepRules) sağlar:
# 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>
process-keep-rules aracı, her yapılandırma dosyasını ayrıştırır ve kitaplık tüketici kurallarında izin verilmeyen yönergelerle karşılaşırsa dosya ve satır teşhisiyle başarısız olur. İzin verilmeyen yönergeler arasında genel optimizasyon, küçültme veya gizleme devre dışı bırakma (ör. -dontoptimize veya -dontshrink), paketi yeniden paketleme ve erişim değiştirme işaretleri, teşhis veya eşleme işaretleri ve uygulama düzeyinde -keepattributes yer alır.
pgaudit.py ile kaynak ağaçlarını denetleme
R8'in derleme zamanı analiz araçlarının yanı sıra derlenmemiş kaynak dizinlerini denetlemek için Android platform ağacı, build/make/core/proguard/tools/ altında pgaudit.py komut dosyasını içerir. Bu statik analiz aracı, bir depodaki Android.bp, proguard.flags ve keep.xml dosyalarını tarayarak AAPT2 veya global platform temelleri, geniş joker karakterler, -dontoptimize geçersiz kılmaları ve yalnızca test amaçlı saklama kuralları tarafından zaten kapsanan kuralları işaretler:
# Audit a single package directory
./build/make/core/proguard/tools/pgaudit.py packages/apps/Provision/
# Scan a subsystem tree and write a structured JSON report
./build/make/core/proguard/tools/pgaudit.py packages/ --json=audit_report.json
Platform ve OEM ekipleri, kaynak ağacını hızlıca önceliklendirmek için pgaudit.py, dışa aktarılan kitaplık kurallarını doğrulamak için process-keep-rules ve bir derlemedeki her kuralın tam sınıf, alan ve yöntem saklama yarıçapını ölçmek için R8_DUMP_KEEP_RADIUS=true ile KeepRadiusHtmlReportGenerator komutlarını birleştirebilir.