Android platformu derleme sistemi (Soong), Android uygulamaları (android_app), testler (android_test) ve compile_dex: true ile yüklenebilir Java kitaplıkları (ör. services.jar) dahil olmak üzere DEX bayt kodu derleyen hedeflerde R8 derleyicisini çalıştırarak kullanılmayan kod ve kaynakları küçültür, optimize eder ve kaldırır. Soong, statik kitaplıklarda (android_library ve static java_library) R8'i doğrudan çalıştırmaz ancak optimize özellik bloğunu kullanarak tüketici koruma kurallarını (export_proguard_flags_files: true) statik olarak bağlayan aşağı akış DEX hedeflerine ekler ve yayar.
Sistem görüntüleri veya satıcı paketleri oluşturan platform mühendisleri için aşırı geniş kapsamlı koruma kurallarının ortadan kaldırılması, doğrudan sistem sağlığı avantajları sunar:
- Daha küçük sistem bölümü alanı: R8, APK'ları ve JAR'ları
/system,/system_ext,/productve/vendorüzerine 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 cihaz üzerinde derleme sırasında
dex2oattarafından oluşturulan daha küçük.odexve.vdexdosyaları anlamına gelir. - Daha düşük çalışma zamanı bellek baskısı: Android,
.odex,.vdexve APK kaynak tablolarını talep üzerine sayfalamammapçağrılarını kullanarak işlem belleğine eşlediğinden, daha küçük ikili dosyalar uygulama başlatma sırasında büyük sayfa hatalarını azaltır ve işlemler genelinde yerleşik kod ile 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 program genelinde optimizasyon: 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ı temizlemesine 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 özelliğini 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 özetlenmektedir (build/soong/java/dex.go içinde tanımlanır):
| Özellik | Açıklama |
|---|---|
enabled |
R8'in hedefte çalışıp çalışmayacağını kontrol eder. Tüm android_app hedefleri için varsayılan değer true
olur.
|
shrink |
Ulaşılamayan sınıfları, alanları ve yöntemleri kaldırmak için ağaç budamayı kontrol eder. android_app hedefleri için varsayılan olarak true değerine ayarlanır (açıkça ayarlanmadığı sürece -dontshrink değerini ileten bağımsız java_library ve test modülleri için false).
|
optimize |
Yöntem satır içi yapma, sınıf birleştirme, sabit yayma ve kullanılmayan dal kaldırma gibi bayt kodu optimizasyonlarını kontrol eder. Varsayılan olarak, android_app hedefleri için true kullanılır (RELEASE_R8_OPTIMIZE_BY_DEFAULT yayınlanan derleme işaretiyle kontrol edilir).
|
obfuscate |
Tanımlayıcı küçültme ve yeniden adlandırma işlemlerini kontrol eder. Geçmişle uyumluluk için varsayılan olarak
false kullanılır ancak DEX boyutunu küçültmek ve daha ayrıntılı optimizasyonlardan yararlanmak için mümkün olan her yerde
true olarak ayarlayın (bkz. Mümkün olan her yerde karartmayı etkinleştirin).
|
shrink_resources |
Kod daraltma işleminden sonra paketlenmiş APK'dan kullanılmayan kaynakları (res/ girişleri) kaldırır. Varsayılan olarak false değerine ayarlanır.
|
optimized_shrink_resources |
Entegre R8 kodu ve kaynak küçültme ardışık düzenini çalıştırır. Böylece R8, tek bir geçişte kod ve kaynak referanslarını birlikte izler. shrink_resources: true ayarlandığında varsayılan olarak RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT
(standart platform derlemelerinde true) olur.
|
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 değerini, statik olarak bağlı olduğu alt akış modüllerine yayar.
|
trace_references_from |
Bu hedefteki R8'in otomatik olarak izlediği ve koruduğu, bu hedefe referans veren Java kitaplığı eşlikçi hedeflerini listeler. |
Mümkün olan her yerde kod karartmayı etkinleştirin
Soong'da, geçmişle uyumluluk için obfuscate varsayılan olarak false değerini alır ancak mümkün olan her yerde 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ılarla (a,b) 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ğine 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, R8'in ad çakışmalarını önlemek için atlaması gereken paketlerde sınıf birleştirme, paket düzleştirme ve sentetik sınıf tekilleştirme işlemlerini mümkün kılar.
- Tam yığın izleme simgeselleştirme: Soong'da kod karartmayı etkinleştirmek hata ayıklanabilirliği 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ıtında paketler, DEX başlığına bir eşleme karması (--map-id-template) yerleştirir ve sınıfSourceFileözelliklerini (--source-file-template) yeniden yazar. Böyleceretrace, yığın izlerini otomatik olarak sembolleştirebilir.
obfuscate: false öğesini yalnızca şu amaçlarla saklayın (veya genel API adlarını açıkça koruyun):
- Önyükleme sınıf yolu veya
system_serversınıf yolu üzerindeki paylaşılan kitaplıklar: Harici bir API'yi kullanıma sunan modüller (java_libraryveyajava_sdk_library), çalışma zamanında diğer modüller tarafından dinamik olarak bağlanır (ör.framework.jar,services.jarveya<uses-library>hedefleri). Bu modüller,obfuscate: falsedeğerini korumalı ya da@KeepForApiveya-keepkurallarını (önyükleme sınıf yolu hedefleri içinprotect_api_surface: trueile birlikte) kullanarak API yüzeylerini açıkça korumalıdır. Böylece, saplamalarına karşı derlenen arayanlar, çalışma zamanında sınıf ve üye adlarını çözebilir.
Bir uygulamada obfuscate: true özelliğini etkinleştirmeden önce aşağıdaki taşıma ön koşullarını doğrulayın:
- Harici test APK'sı bağımlılıkları: Harici bir
android_testAPK grubuinstrumentation_for: "MyApp",MyApp'nin dahili sınıflarını veya yöntemlerini doğrudan çağırıyorsa bu sembollerin yeniden adlandırılması test çalışma zamanındaNoSuchMethodErrorveyaNoClassDefFoundError'ye neden olur. Testi,MyApp.implstatik olarak bağlanan kendi kendini enstrümanlaştıran bir APK olarak yapılandırmayı tercih edin, test kancalarını@VisibleForTestingile açıklama ekleyin veyatrace_references_fromyapılandırın (bkz. 2. adım: Test odaklı koruma kurallarını taşıma). Böylece, testler için gereken dahili semboller korunurken uygulamanın geri kalanı karartılır. - Dize tabanlı yansıtma ve JNI: Bir modül, sınıf, yöntem veya alanları değişmez dize adlarıyla (
Class.forName,getDeclaredMethodveya JNIFindClassveGetMethodID) keep kuralları ya da ek açıklamalar olmadan ararsa karartma, bu hedefleri yeniden adlandırır ve çalışma zamanı aramalarını bozar. (Not: Açıklama eklenmemiş yansıtma dashrink: trueveoptimize: truekapsamında başarısız olur.) Bu giriş noktalarına Keep Açıklamaları Kılavuzu (@UsesReflection,@UsedByReflectionveya@UsedByNative) ile açıklama ekleyin. Böylece R8, adlarını korur ve modülün geri kalanını karartır.
Sıfır özel işaret ilkesine uyun
İdeal Android platform modülünde özel proguard.flags veya keep.xml dosyası yoktur. Android platform derlemesinde, özel saklama kurallarının büyük çoğunluğu gereksizdir:
- Platform temelleri ve AAPT2: Giriş noktalarının çoğu,
@Keep, JNInativeyöntemleri ve@VisibleForTestinggibi küresel platform temelleri tarafından otomatik olarak korunur veyaAndroidManifest.xmlve düzen kaynaklarından AAPT2 tarafından oluşturulur (bkz. Varsayılan platform koruma kurallarını anlama). - Hedeflenen alternatifler: Giriş noktalarının korunması gerektiği durumlarda, ayrılmış
.flagsdosyaları yerine bildirim sitesi ek açıklamaları (keepanno,@VisibleForTesting), dışa aktarılan kitaplık kuralları (export_proguard_flags_files: true) veya statik test bağlantısı tercih edin (bkz. Mevcut saklama kurallarını denetleme ve taşıma).
Özel bir proguard.flags veya keep.xml dosyası eklemeden ya da saklamadan önce kuralın varsayılan temel çizgiler tarafından zaten işlenip işlenmediğini veya kod açıklamalarına taşınıp taşınamayacağını doğrulayın.
Varsayılan platform saklama kurallarını anlama
Soong, build/soong/java/dex.go içinde yapılandırılan DEX derleme hedeflerindeki (android_app, android_test ve yüklenebilir java_library modülleri) her R8 çağırma işlemine aşağıdaki genel temel kuralları otomatik olarak iletir:
build/make/core/proguard.flags:@com.android.internal.annotations.VisibleForTestingile açıklama eklenmiş sınıfları ve üyeleri tüm paketlerde,@VisibleForTesting(androidx.annotation.VisibleForTestingveyacom.google.common.annotations.VisibleForTesting) ile açıklama eklenmiş sınıfları ve üyeleri iseandroid.**,com.android.**vecom.google.android.**paketlerinde korur. Ayrıca@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallbackve@dalvik.annotation.optimization.**öğelerini korur.build/make/core/proguard_basic_keeps.flags: Yığın izlemeleri, çalışma zamanı görünürlüğü ek açıklamaları (RuntimeVisible*Annotations),ExceptionsveAnnotationDefaultözellikleri,nativeyöntemleri,Serializableüyeleri,@JavascriptInterfaceyöntemleri,Throwable(String)oluşturucuları,Parcelable$CREATORalanları ve protobufMessageLitealanları içinSourceFileözelliklerini 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ı devre dışı bırakır ve yayın derlemelerindeki KotlinDebugMetadataek açıklamalarını kaldırır.build/make/core/proguard/checknotnull.flags: Yaygın null kontrolü yardımcı programı ç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çinObjects.requireNonNullkarakterini kasıtlı olarak atlıyor.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, her kayıtlı
Activity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, özelViewalt sınıfı,Preferencealt sınıfı ve XMLandroid:onClickyöntemi için tam koruma kuralları oluşturmak üzere birleştirilmişAndroidManifest.xml, düzen XML'si ve tercih XML'si 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 sırayla 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ın yanı sıra 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'den proguard_flags_files öğesini 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 yardımcı modüllerin (ör. Kotlin hedef varyantları) aynı işaretler dosyasına referans verip vermediğini kontrol edin ve bunları birlikte güncelleyin.
2. adım: Test odaklı saklama kurallarını taşıyın
Aşağıdaki kalıplardan birini kullanarak test odaklı saklama kurallarını özel üretim .flags dosyalarından taşıyın:
Uygulama kitaplığını testlere bağlama (
static_libs): Birandroid_test, bir uygulamanın paket içi veya dahili uygulama ayrıntılarını kullandığında, önerilen platform mimarisi uygulama kaynak dosyalarını birandroid_library(MyApp.impl) içine yerleştirmek veMyApp.implöğesini hemMyApphem deMyAppTestsile statik olarak bağlamaktır: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ü yapı,
MyAppTests'nın dahili sınıflara tam erişimle kendi kendine enstrümantasyon uygulayan bir test olarak çalışmasına,MyApp'nin testleri bozmadanobfuscate: true'ı serbestçe etkinleştirmesine, üretim APK'sında yalnızca test için giriş noktalarının gönderilmesini önlemeye ve test kodu değiştiğindeMyApp'nin yeniden oluşturulmasını ortadan kaldırmaya olanak tanır.Test kancalarına
@VisibleForTestingekleyin: Harici bir test APK'sı,android_apphedefinde az sayıda dahili yöntem veya oluşturucu çağırıyorsa ve.implkitaplığına yeniden yapılandırma pratik değilse bu bildirimlere@VisibleForTestingekleyin. Küreselbuild/make/core/proguard.flagstemelinde, özel.flagsdosyaları olmadanandroid.**,com.android.**vecom.google.android.**paketlerindeki@VisibleForTestingöğeleri otomatik olarak korunur. (Bu ad alanlarının dışındaki tedarikçi modülleri için@UsedByReflectionveya dışa aktarılan kitaplık kurallarını kullanın.)Platform kitaplığı sınırları arasında
trace_references_fromkullanma: Testler, hedef uygulamayı statik olarak bağlayamadığında (örneğin, sistem sunucusu hizmetlerini veyaframework-connectivitygibi platform JAR'larını kullanan testler), hedef modüldetrace_references_from'yi test kaynaklarını içeren bir Java kitaplığı yardımcı modülüne işaret edecek şekilde yapılandırın. R8, yardımcı bayt kodu tarafından referans verilen tüm sınıfları ve üyeleri izler ve saklar.
3. adım: Kuralları sahip kitaplıktan dışa aktarın
Paylaşılan bir java_library veya android_library kendi dahili yansıtması 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,
},
}
Statik olarak bağlanan tüm aşağı akış android_app ve kitaplık hedefleri my-shared-library bu kuralları otomatik olarak devralır. Bu nedenle, aşağı akış uygulamalarının bunları 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, .flags dosyasını Android.bp içinde açık bir filegroup aracılığıyla yayınlayın. Böylece modüller, paket sınırları arasında :my-shared-flags öğesine sorunsuz bir şekilde referans verebilir. Kitaplık tüketicilerinin, aşağı akış uygulama optimizasyonunu kısıtlamadan kitaplık tüketicisi saklama kuralları oluşturmasıyla ilgili genel bilgi için Kitaplık yazarları için optimizasyon başlıklı makaleyi inceleyin.
4. adım: Kaynak kodundaki bildirimlere açıklama ekleyin
Yansıtma veya JNI aracılığıyla erişilen ve AAPT2 ya da genel temel çizgiler tarafından kapsanmayan bir sınıf, yöntem, oluşturucu veya alan olduğunda -keep dosyalarındaki ayrılmış .flags kurallarını Keep Annotations Kılavuzu'ndaki kaynak ek açıklamalarıyla değiştirin (keepanno Javadoc referansına bakın):
@UsesReflection: Yansıtmayı gerçekleştiren kodu kontrol ettiğinizde bu ek açıklamayı tercih edin. Hangi hedef sınıflara, yöntemlere veya alanlara dinamik olarak erişildiğini bildirmek için yansıtma çağrısı sitesine yerleştirin.@UsesReflection, açıklama eklenen çağrı sitesinin kendisinin erişilebilir olduğu ön koşulunu otomatik olarak kodladığından, çağrı sitesi kullanılmıyorsa R8 hem arayanı hem de yansıtıcı hedefi temizler.@UsedByReflection:Class.forNameile yüklenen sınıflar gibi harici kod veya kitaplıklar tarafından yansıtıcı olarak oluşturulan veya çağrılan sınıflara, yöntemlere, alanlara ya da oluşturuculara yerleştirin.BundleveyaSettingsanahtarlarından ya da dinamik sınıf yükleyiciler arasında yüklenen eklenti sınıflarından. R8'in yalnızca tam yansıtıcı sözleşmeyi koruması ve sınıfın kullanılmayan üyelerini optimize etmeye veya budamaya devam edebilmesi içinkind(ör.KeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition) ve parametre kısıtlamalarını belirtin. AAPT2 bu bileşenleri zaten sakladığı içinJobServiceveyaBroadcastReceivergibi manifest'e kaydedilmiş bileşenlere@UsedByReflectioneklemeyin.@UsedByNative:GetMethodID,GetStaticMethodIDveyaGetFieldIDkullanılarak C veya C++ JNI kodundan erişilen yöntemlere ya da alanlara yerleştirin.@KeepForApi: Kitaplığın kendisi dağıtımdan önce küçültüldüğünde bozulmadan kalması gereken kitaplık API sınıflarına veya üyelere yerleştirin.@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 korunur. Bir yönteme veya alana@Keepuygulanması, sınıf hiçbir zaman örneklenmemiş olsa bile üyenin ve onu içeren sınıfın korunmasını sağlayan koşulsuz bir giriş noktası görevi görürkenkeepannokoşullu erişilebilirliği ifade eder.
Soong modülünde R8 keepanno ek açıklamalarını kullanmak için:
Android.bpuygulamasındalibsbölümüne"keepanno-annotations"adlı etkinliği ekleyin:libs: [ "keepanno-annotations", ],com.android.tools.r8.keepanno.annotations.*öğesini içe aktarın ve Java veya Kotlin kaynak kodundaki bildirimi ya da çağrı sitesini açıklama olarak 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 koruma kuralı modeline çevirir ve ek açıklamaları nihai DEX çıkışından kaldırarak çalışma zamanı bayt kodu ek yükünü sıfıra indirir.
Yaygın hatalardan kaçının
Aşağıdaki bölümlerde, platform kodundaki sık karşılaşılan proguard.flags ve keep.xml tuzakları 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 son birleştirilmiş
AndroidManifest.xmliçinde kayıtlı olup olmadığını kontrol etmeden joker karakter kullandığı için R8, kullanılmayan kitaplık bileşenleri ve devre dışı bırakılmış hata ayıklama etkinlikleri de dahil olmak üzere sınıf yolunda 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önteminin korunması, R8'in tek birViewparametresini kabul eden yöntemleri kaldırmasını veya satır içi yapması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.
Geniş Görünüm alıcı ve belirleyici koruma 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ı neden olumsuz etkiler? Bu kural, R8'i uygulamadaki her
Viewalt sınıfında ve tüm bağlı kitaplıklarda (AndroidX ve Materyal kitaplıkları dahil) her alıcı ve belirleyiciyi tutmaya zorlar. Bu durum, ölü yöntemlerin kaldırılmasını ve kullanıcı arayüzü kodunda satır içi işlemleri engeller. - Önerilen düzeltme: Kuralı silin. AAPT2, düzen XML dosyalarından şişirilmiş özel
Viewsınıfları için oluşturucuları zaten korur. Kod,ObjectAnimator.ofFloat(view, "translationZ", ...)gibi yansıtıcı dize adlarını kullanarak bir görünüm özelliğine animasyon uyguluyorsa yansıtmayı tamamen önlemek için dize adını yazılmış bir özellik referansıyla (View.TRANSLATION_Zveya özel birFloatPropertyya daIntPropertyuygulaması) değiştirin. Yansıtıcı özellik erişiminden kaçınılamıyorsa belirli alıcı veya belirleyiciyi@UsedByReflectionile ek açıklama ekleyin.
Genel optimizasyon veya karartma devre dışı bırakılır.
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- Performansa neden zarar veriyor?
-dontoptimizeveya-dontshrinköğelerini.flagsdosyasına yerleştirmek, modülünAndroid.bpayarlarını sessizce geçersiz kılar ve 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 aşağı akışandroid_appiçin R8 optimizasyonunu devre dışı bırakır. - Önerilen düzeltme:
.flagsdosyalarından-dontoptimize,-dontshrinkve-dontobfuscateöğelerini kaldırın.Android.bpkullanarak optimizasyon davranışını açıkça kontrol edin. Bunun için yaprak hedeftekioptimizebloğ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
- Neden derlemeye zarar veriyor?: Teşhis işaretleri, derleme günlüklerini doldurur veya korumalı alan Soong derlemeleri sırasında çıkış dosyalarını yerel yollara yazmaya çalışır.
- Önerilen düzeltme: Bu işaretleri, işlenmiş
.flagsdosyalarından silin. Soong,proguard_dictionaryveproguard_usage.zipgibi R8 eşleme ve kullanım çıkışlarını otomatik olarakout/soong/.intermediates/altındaki modülün ara dizinine yazar.
Test kodu için üretimde saklama kuralları
- Performansı neden olumsuz etkiler? Yalnızca test erişimi için özel
-keepkuralları eklemek, bu kodun karartılmadan kalmasına ve üretim derlemelerinde tutulmasına neden olur. Yöntemleri@VisibleForTestingile açıklama ekleme veyatrace_references_fromyapılandırma, manuel-keepkurallarının korunmasını önlese de bu semboller üretim ikilisine gönderilmeye devam eder. - Önerilen düzeltme: Yalnızca test için kullanılan giriş noktalarını üretim APK'sından tamamen çıkarmak amacıyla uygulamayı bir
.implkitaplığı olarak yapılandırın vestatic_libskullanarak kendi kendini izleyen bir test APK'sına bağlayın. Bu işlem, 2. adım: Test odaklı koruma kurallarını taşıma bölümünde açıklanmıştır.
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ındaki eşleşen türdeki her kaynağı korur. Bu durum, kaynak küçültmeyi (
shrink_resources: true) engeller ve APK ile eşlenmişresources.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.drawablesabitlerini eşleyin. 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.xml'nin tamamen kaldırılmasına olanak tanır.- Belirli kaynak adlarını listeleyin: Üçüncü taraf lisans okuyucusu gibi dinamik arama gerekiyorsa
tools:keepiçinde tam kaynak tanımlayıcılarını 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 korur. Bu nedenleres/raw/keep.xmlöğesini silebilirsiniz.
Kural değişikliklerini doğrulama ve denetleme
proguard.flags veya keep.xml'de saklama kurallarını her kaldırdığınızda ya da daralttığınızda,
modülün sorunsuz bir şekilde oluşturulduğunu, 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 oluşturun:
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ğımlı modüller için hedef fiziksel cihazlarda ya da cihaz test laboratuvarınızda enstrümantasyon ve kullanıcı arayüzü testleri çalıştırarak çalışma zamanı yansıtma yollarını, IPC bağlamalarını ve kaynak genişletmeyi kullanın.
DEX ve kaynak farklılıklarını inceleme
R8'in, beklenen giriş noktalarını kaldırmadan kullanılmayan kodu ve kaynakları kaldırdığını doğrulamak için derlenmiş APK veya JAR'ı kural değişikliklerinden önce ve sonra karşılaştırın:
Çıkış APK veya DEX dosyalarındaki tutulan sınıfları, yöntemleri ve alanları incelemek için
apkanalyzerveyadexdumptuşlarını kullanın:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkkeep.xmldeğiştirilirken veyashrink_resourcesetkinleştirilirken, derlemenin kullanılmayan kaynakları temizlediğini ve gerekli olanları koruduğunu doğrulamak içinaapt2 dump resourceskullanın:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
R8 ile saklama yarıçapını ve kural kapsamasını analiz etme
Açık kaynaklı R8 derleyicisi, derleme sırasında her saklama kuralının tam etkisini ölçen bir Saklama Yarıçapı analiz aracı içerir (Android Studio ve Gradle'da R8 Yapılandırma Analiz Aracı olarak da sunulur). Soong, bu analiz aracı doğrudan Android platform derlemesine entegre eder (build/soong/java/dex.go içinde yapılandırılır).
Bir platform modülündeki veya tüm derlemedeki saklama kurallarını analiz etmek için:
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ında derlenen her modül için arar8keepradius.pbdosyasına keep rule metriklerini kaydetmesini söyler. R8, her saklama kuralı vekeepannoek açıklaması için şunları kaydeder:- Hemen koruma yarıçapı: Kural tarafından korunan sınıflar, alanlar ve yöntemler ile küçültme, optimizasyon veya karartmaya karşı uyguladığı kısıtlamalar.
- Kural kapsama: Hangi diğer saklama kuralları veya ek açıklamalar aynı öğeleri zaten saklıyor? Özel bir kural tamamen bir AAPT2 kuralı veya genel temel kural tarafından kapsanıyorsa bu kuralı güvenle silebilirsiniz.
- Paket genelinde ve genel kurallar: Paket genelinde geniş joker karakterler kullanan veya genel yapılandırma yönergeleri uygulayan kurallar.
r8keepradius.pbçıktısınıKeepRadiusHtmlReportGenerator(prebuilts/r8/r8.jariçinde paketlenmiş) kullanarak 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 dosyaları*keepradius*.pbtarar, her modül için bir HTML raporu oluşturur veout/keep_radius_reports/keepradius.htmlözetleyen bir rapor oluşturur. Bu raporda, derleme genelinde canlı öğe sayıları, saklanan öğe sayıları ve en yüksek yarıçaplı saklama kuralları yer alır. Oluşturulan rapordaki küçültme, optimizasyon ve 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 iki ek R8 teşhis ortam değişkenini 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ünr8trace.ptraceara dizinine yazar.
Kitaplık tüketici kurallarını doğrulama
Bir java_library veya android_library dışa aktarma işlemi, kuralları aşağı akış tüketicilerine (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 platform derlemesinde process-keep-rules ana makine aracı olarak kullanıma 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üketicisi kurallarında izin verilmeyen yönergelerle karşılaşırsa dosya ve satır teşhisleriyle başarısız olur. İzin verilmeyen yönergeler arasında genel optimizasyon, küçültme veya karartma devre dışı bırakma (ör. -dontoptimize veya -dontshrink), paket 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
Android platform ağacı, R8'in derleme zamanı analiz araçlarıyla birlikte oluşturulmamış kaynak dizinleri denetlemek için build/make/core/proguard/tools/ altında pgaudit.py komut dosyasını içerir. Bu statik analiz aracı, Android.bp, proguard.flags ve keep.xml dosyalarını bir depoda tarayarak AAPT2 veya genel platform temelleri, geniş joker karakterler, -dontoptimize geçersiz kılmaları ve yalnızca test için saklama kuralları tarafından halihazırda 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, hızlı kaynak ağacı triyajı 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'ü birleştirebilir.