Android प्लैटफ़ॉर्म का बिल्ड सिस्टम (Soong), DEX बाइटकोड को कंपाइल करने वाले टारगेट पर R8 कंपाइलर चलाता है. इनमें Android ऐप्लिकेशन (android_app), टेस्ट (android_test), और इंस्टॉल की जा सकने वाली Java लाइब्रेरी (compile_dex: true) शामिल हैं. जैसे, services.jar. ऐसा इसलिए किया जाता है, ताकि इस्तेमाल न किए गए कोड और संसाधनों को छोटा किया जा सके, उन्हें ऑप्टिमाइज़ किया जा सके, और हटाया जा सके. स्टैटिक लाइब्रेरी (android_library और स्टैटिक java_library) पर, Soong सीधे तौर पर R8 को नहीं चलाता है. हालांकि, यह optimize प्रॉपर्टी ब्लॉक का इस्तेमाल करके, उपभोक्ता के कीप नियमों (export_proguard_flags_files: true) को डाउनस्ट्रीम DEX टारगेट से जोड़ता है और उन्हें आगे बढ़ाता है. ये टारगेट, स्टैटिक तौर पर उनसे लिंक होते हैं.
सिस्टम इमेज या वेंडर पैकेज बनाने वाले प्लैटफ़ॉर्म इंजीनियर के लिए, बहुत ज़्यादा फ़ाइलों को सुरक्षित रखने के नियमों को हटाने से, सिस्टम की सेहत को सीधे तौर पर फ़ायदा मिलता है:
- सिस्टम पार्टिशन का छोटा फ़ुटप्रिंट: R8, APK और JAR फ़ाइलों को
/system,/system_ext,/product, और/vendorपर पैकेज करने से पहले, इस्तेमाल न की गई क्लास, तरीकों, और संसाधनों को हटा देता है. - कंपाइल किए गए छोटे आर्टफ़ैक्ट: DEX के कम तरीकों का मतलब है कि
dex2oat, बिल्ड-टाइम या उपयोगकर्ता के डिवाइस पर कंपाइल करने के दौरान.odexऔर.vdexफ़ाइलें जनरेट करता है. - रंटाइम मेमोरी पर कम दबाव: Android,
.odex,.vdex, और APK संसाधन टेबल को मांग के हिसाब से पेजिंगmmapकॉल का इस्तेमाल करके प्रोसेस मेमोरी में मैप करता है. इसलिए, छोटे बाइनरी से ऐप्लिकेशन के स्टार्टअप के दौरान पेज फ़ॉल्ट कम होते हैं. साथ ही, प्रोसेस में मौजूद कोड और संसाधन मेमोरी कम होती है. कंपाइल किए गए ऐप्लिकेशन कोड से डिवाइस की मेमोरी पर पड़ने वाले असर के बारे में ज़्यादा जानने के लिए, ऐप्लिकेशन कोड, मेमोरी है लेख पढ़ें. - पूरे प्रोग्राम को ज़्यादा असरदार तरीके से ऑप्टिमाइज़ करना: कीप की सीमाएं कम होने से, R8 को इनलाइन तरीके से काम करने वाली मेथड, इंटरफ़ेस और वर्चुअल कॉल को डीवर्चुअलाइज़ करने, इस्तेमाल न किए गए फ़ील्ड को हटाने, और क्लास में कॉन्स्टेंट को ट्रांसफ़र करने की सुविधा मिलती है.
Soong में R8 ऑप्टिमाइज़ेशन को कॉन्फ़िगर करना
Android.bp फ़ाइलों में, R8 ऑप्टिमाइज़ेशन को कॉन्फ़िगर करने के लिए, android_app और इंस्टॉल किए जा सकने वाले java_library टारगेट पर optimize प्रॉपर्टी
ब्लॉक का इस्तेमाल करें. इसके अलावा, उपभोक्ता के लिए 'कीप रूल' एक्सपोर्ट करने के लिए, android_library और स्टैटिक java_library मॉड्यूल पर भी इसका इस्तेमाल किया जा सकता है:
android_app {
name: "MySystemApp",
srcs: ["src/**/*.java"],
optimize: {
obfuscate: true,
shrink_resources: true,
},
}
यहां दी गई टेबल में, Soong में इस्तेमाल होने वाली सबसे आम optimize प्रॉपर्टी के बारे में खास जानकारी दी गई है. इन्हें build/soong/java/dex.go में तय किया गया है:
| प्रॉपर्टी | ब्यौरा |
|---|---|
enabled |
यह विकल्प कंट्रोल करता है कि टारगेट पर R8 काम करेगा या नहीं. सभी android_app टारगेट के लिए, डिफ़ॉल्ट रूप से true
पर सेट होता है.
|
shrink |
यह विकल्प, ट्री शेकिंग को कंट्रोल करता है. इससे उन क्लास, फ़ील्ड, और तरीकों को हटाया जाता है जिन तक नहीं पहुंचा जा सकता. android_app
टारगेट के लिए, डिफ़ॉल्ट रूप से true होता है. हालांकि, स्टैंडअलोन java_library और टेस्ट मॉड्यूल के लिए, यह false होता है. ये मॉड्यूल, -dontshrink पास करते हैं, जब तक कि इन्हें साफ़ तौर पर सेट न किया जाए.
|
optimize |
यह बाइटकोड ऑप्टिमाइज़ेशन को कंट्रोल करता है. जैसे, मेथड इनलाइनिंग, क्लास मर्जिंग, कॉन्स्टेंट प्रोपगेशन, और डेड ब्रांच रिमूवल. डिफ़ॉल्ट रूप से, यह android_app टारगेट के लिए true पर सेट होता है. इसे RELEASE_R8_OPTIMIZE_BY_DEFAULT रिलीज़ के लिए तैयार बिल्ड फ़्लैग से कंट्रोल किया जाता है.
|
obfuscate |
यह आइडेंटिफ़ायर को छोटा करने और उसका नाम बदलने की प्रोसेस को कंट्रोल करता है. यह डिफ़ॉल्ट रूप से false पर सेट होता है, ताकि यह पुराने वर्शन के साथ काम कर सके. हालांकि, इसे true पर सेट करें, ताकि DEX का साइज़ कम किया जा सके और ज़्यादा बेहतर ऑप्टिमाइज़ेशन किया जा सके (जहां भी हो सके, अस्पष्ट बनाने की सुविधा चालू करें देखें).
|
shrink_resources |
यह विकल्प, कोड को छोटा करने के बाद पैकेज किए गए APK से, इस्तेमाल न होने वाले संसाधनों (res/ एंट्री) को हटाता है. डिफ़ॉल्ट रूप से, इसकी वैल्यू false होती है.
|
optimized_shrink_resources |
यह इंटिग्रेटेड R8 कोड और रिसोर्स श्रिंकर पाइपलाइन को चलाता है, ताकि R8 एक ही पास में कोड और रिसोर्स रेफ़रंस को एक साथ ट्रेस कर सके. shrink_resources: true सेट होने पर, डिफ़ॉल्ट रूप से RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT (स्टैंडर्ड प्लैटफ़ॉर्म बिल्ड में true) पर सेट होता है.
|
proguard_flags_files |
इस फ़ाइल में, मॉड्यूल के हिसाब से .flags या .pro फ़ाइलों की सूची होती है. इनमें निजी डेटा के रखरखाव के कस्टम नियम शामिल होते हैं. जब स्टैंडर्ड एनोटेशन या डिफ़ॉल्ट सेटिंग से काम चल जाता है, तब कस्टम फ़ाइलें जोड़ने से बचें.
|
export_proguard_flags_files |
इस लाइब्रेरी के proguard_flags_files को उन डाउनस्ट्रीम मॉड्यूल में भेजता है जो इस पर स्टैटिक तौर पर निर्भर होते हैं.
|
trace_references_from |
यह Java लाइब्रेरी के उन कंपैनियन टारगेट की सूची बनाता है जिनके बाइटकोड, इस टारगेट में रेफ़रंस देते हैं. R8, इन बाइटकोड को अपने-आप ट्रेस करता है और बनाए रखता है. |
जहां भी हो सके, कोड को अस्पष्ट बनाने की सुविधा चालू करें
Soong में, पुराने वर्शन के साथ काम करने की सुविधा के लिए, obfuscate डिफ़ॉल्ट रूप से false पर सेट होता है. हालांकि, जहां भी हो सके वहां android_app और स्टैंडअलोन DEX टारगेट पर obfuscate: true को साफ़ तौर पर सेट करना चाहिए:
- छोटा DEX और
.vdexफ़ुटप्रिंट: पैकेज, क्लास, फ़ील्ड, और मेथड के नाम बदलकर छोटे आइडेंटिफ़ायर (a,b) करने से, DEX स्ट्रिंग पूल (string_idsऔरstring_data_item) और टाइप डिस्क्रिप्टर छोटे हो जाते हैं. Android, प्रोसेस मेमोरी में.vdexऔर.odexफ़ाइलों को मैप करता है. इसलिए, छोटी सिंबल टेबल से सिस्टम पार्टीशन का साइज़ और रनटाइम मेमोरी फ़ुटप्रिंट, दोनों कम हो जाते हैं. - पूरे प्रोग्राम को ज़्यादा बेहतर तरीके से ऑप्टिमाइज़ करना: R8 को आइडेंटिफ़ायर का नाम बदलने की अनुमति देने से, क्लास मर्ज करने, पैकेज फ़्लैट करने, और सिंथेटिक क्लास को डुप्लीकेट होने से बचाने की सुविधा मिलती है. ऐसा उन पैकेज के लिए होता है जिन्हें R8 को नाम के टकराव से बचने के लिए छोड़ना पड़ता है.
- पूरे स्टैक ट्रेस का सिंबोलाइज़ेशन: Soong में अस्पष्टता को चालू करने से, डीबग करने की क्षमता कम नहीं होती. R8 से कंपाइल किए गए हर टारगेट के लिए, Soong मॉड्यूल की इंटरमीडिएट डायरेक्ट्री में
proguard_dictionaryमैपिंग फ़ाइल बनाता है. साथ ही, सभी मॉड्यूल डिक्शनरी को बिल्ड केproguard-dict.zipआर्टफ़ैक्ट में बंडल करता है. इसके अलावा, यह DEX हेडर में मैपिंग हैश (--map-id-template) एम्बेड करता है और क्लासSourceFileएट्रिब्यूट (--source-file-template) को फिर से लिखता है, ताकिretraceस्टैक ट्रेस को अपने-आप सिंबोलाइज़ कर सके.
obfuscate: false को सिर्फ़ इन मामलों में इस्तेमाल करें (या सार्वजनिक एपीआई के नामों को साफ़ तौर पर सुरक्षित रखें):
- बूटक्लाथपाथ या
system_serverक्लासपाथ पर शेयर की गई लाइब्रेरी: मॉड्यूल (java_libraryयाjava_sdk_library) जो बाहरी एपीआई को दिखाते हैं जिन्हें रनटाइम के दौरान अन्य मॉड्यूल से डाइनैमिक तरीके से लिंक किया जाता है (जैसे किframework.jar,services.jarया<uses-library>टारगेट) को या तोobfuscate: falseको बनाए रखना होगा या@KeepForApiया-keepनियमों (बूटक्लाथपाथ टारगेट के लिएprotect_api_surface: trueके साथ) का इस्तेमाल करके, अपने एपीआई को साफ़ तौर पर बनाए रखना होगा, ताकि कॉल करने वाले लोग, रनटाइम के दौरान अपने स्टब के ख़िलाफ़ कंपाइल किए गए क्लास और मेंबर के नामों को हल कर सकें.
किसी ऐप्लिकेशन पर obfuscate: true की सुविधा चालू करने से पहले, माइग्रेशन से जुड़ी इन ज़रूरी शर्तों की पुष्टि करें:
- बाहरी टेस्ट APK की डिपेंडेंसी: अगर कोई बाहरी
android_testAPK सेटinstrumentation_for: "MyApp",MyAppकी इंटरनल क्लास या तरीकों को सीधे तौर पर इनवोक करता है, तो उन सिंबल का नाम बदलने से, टेस्ट रनटाइम मेंNoSuchMethodErrorयाNoClassDefFoundErrorमें गड़बड़ी होती है. टेस्ट को ऐसे APK के तौर पर स्ट्रक्चर करें जो खुद को इंस्ट्रुमेंट करता है औरMyApp.implको स्टैटिक तौर पर लिंक करता है. टेस्ट हुक को@VisibleForTestingसे एनोटेट करें याtrace_references_fromको कॉन्फ़िगर करें (दूसरा चरण: टेस्ट-ड्रिवन कीप नियमों को माइग्रेट करना देखें), ताकि टेस्ट के लिए ज़रूरी इंटरनल सिंबल सुरक्षित रहें और ऐप्लिकेशन के बाकी हिस्से को अस्पष्ट किया जा सके. - स्ट्रिंग पर आधारित रिफ़्लेक्शन और JNI: अगर कोई मॉड्यूल, कीप नियमों या एनोटेशन के बिना, लिटरल स्ट्रिंग के नामों (
Class.forName,getDeclaredMethodया JNIFindClassऔरGetMethodID) के हिसाब से क्लास, मेथड या फ़ील्ड ढूंढता है, तो अस्पष्ट करने की प्रोसेस में उन टारगेट के नाम बदल दिए जाते हैं. इससे रनटाइम लुकअप काम नहीं करते. (ध्यान दें कि एनोटेशन के बिना रिफ़्लेक्शन भीshrink: trueऔरoptimize: trueके तहत फ़ेल हो जाता है.) उन एंट्री पॉइंट को एनोटेशन बनाए रखने के लिए गाइड (@UsesReflection,@UsedByReflectionया@UsedByNative) के साथ एनोटेट करें, ताकि R8 उनके नामों को सुरक्षित रख सके और मॉड्यूल के बाकी हिस्से को अस्पष्ट कर सके.
कस्टम फ़्लैग न लगाने के सिद्धांत का पालन करना
आदर्श Android प्लैटफ़ॉर्म मॉड्यूल में, कोई कस्टम proguard.flags या keep.xml फ़ाइलें नहीं होती हैं. Android प्लैटफ़ॉर्म के बिल्ड में, निजी डेटा के रखरखाव के ज़्यादातर कस्टम नियम
ज़रूरी नहीं होते:
- प्लैटफ़ॉर्म की बेसलाइन और AAPT2: ज़्यादातर एंट्री पॉइंट, ग्लोबल प्लैटफ़ॉर्म की बेसलाइन (जैसे कि
@Keep, JNInativeके तरीके, और@VisibleForTesting) से पहले से ही अपने-आप बनाए जाते हैं. इसके अलावा, AAPT2 इन्हेंAndroidManifest.xmlऔर लेआउट रिसॉर्स से जनरेट करता है (प्लैटफ़ॉर्म के डिफ़ॉल्ट कीप नियमों के बारे में जानें देखें). - टारगेट किए गए विकल्प: जहां एंट्री पॉइंट को सुरक्षित रखना ज़रूरी है वहां अलग की गई
.flagsफ़ाइलों के बजाय, एलान वाली साइट के एनोटेशन (keepanno,@VisibleForTesting), एक्सपोर्ट किए गए लाइब्रेरी के नियम (export_proguard_flags_files: true) या स्टैटिक टेस्ट लिंकिंग का इस्तेमाल करें. (मौजूदा कीप नियमों का ऑडिट करना और उन्हें माइग्रेट करना लेख देखें).
कस्टम proguard.flags या keep.xml फ़ाइल जोड़ने या बनाए रखने से पहले, पुष्टि करें कि नियम को डिफ़ॉल्ट बेसलाइन से पहले ही हैंडल किया जा चुका है या इसे कोड एनोटेशन पर माइग्रेट किया जा सकता है.
डिफ़ॉल्ट प्लैटफ़ॉर्म के निजी डेटा के रखरखाव के नियमों के बारे में जानकारी
इसलिए, Soong, build/soong/java/dex.go में कॉन्फ़िगर किए गए DEX-कंपाइलिंग टारगेट (android_app, android_test, और इंस्टॉल किए जा सकने वाले java_library मॉड्यूल) पर, R8 के हर इनवोकेशन को ये ग्लोबल बेसलाइन नियम अपने-आप पास कर देता है:
build/make/core/proguard.flags: यह सभी पैकेज में,@com.android.internal.annotations.VisibleForTestingके साथ एनोटेट की गई क्लास और सदस्यों को सुरक्षित रखता है. साथ ही,android.**,com.android.**, औरcom.google.android.**पैकेज में@VisibleForTesting(androidx.annotation.VisibleForTestingयाcom.google.common.annotations.VisibleForTesting) के साथ एनोटेट की गई क्लास और सदस्यों को सुरक्षित रखता है. यह@TestApi,@Keep(androidx.annotation,android.support.annotation,com.android.internal.annotations),@KeepForWeakReference,@WeaklyReferencedCallback, और@dalvik.annotation.optimization.**को भी सुरक्षित रखता है.build/make/core/proguard_basic_keeps.flags: यह स्टैक ट्रेस, रनटाइम विज़िबिलिटी एनोटेशन (RuntimeVisible*Annotations),ExceptionsऔरAnnotationDefaultएट्रिब्यूट,nativeतरीके,Serializableमेंबर,@JavascriptInterfaceतरीके,Throwable(String)कंस्ट्रक्टर,Parcelable$CREATORफ़ील्ड, और प्रोटोबफ़MessageLiteफ़ील्ड के लिएSourceFileएट्रिब्यूट को सुरक्षित रखता है.build/make/core/proguard/kotlin.flags: यह Kotlin की कुछ मेटा-एनोटेशन (kotlin.Metadataऔरkotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) के लिए, बिना नुकसान वाली चेतावनियों को साइलेंट करता है. साथ ही, रिलीज़ बिल्ड में KotlinDebugMetadataएनोटेशन हटाता है.build/make/core/proguard/checknotnull.flags: यह सामान्य null चेक हेल्पर कॉल (com.google.common.base.Preconditions.checkNotNullऔरdagger.internal.Preconditions.checkNotNull*) को, छोटे बाइटकोड वाले null चेक से बदलता है. इस फ़ाइल में जान-बूझकरObjects.requireNonNullको शामिल नहीं किया गया है, ताकि फ़्रेमवर्क एपीआई की सीमाओं के बीच, अपवाद के मैसेज को सुरक्षित रखा जा सके.build/make/core/proguard/enumvalues.flags: यहenumटाइप परvaluesऔरvalueOfतरीकों को बनाए रखता है. हालांकि, ऐसा तब तक होता है, जब तक कि बिल्ड कॉन्फ़िगरेशन से इन्हें बंद न कर दिया जाए.- AAPT2 के अपने-आप जनरेट होने वाले नियम: AAPT2, मर्ज की गई
AndroidManifest.xml, लेआउट एक्सएमएल, और प्राथमिकता वाली एक्सएमएल फ़ाइलों की जांच करता है. इससे हर रजिस्टर किए गएActivity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, कस्टमViewसबक्लास,Preferenceसबक्लास, और एक्सएमएलandroid:onClickतरीके के लिए, सटीक कीप नियम जनरेट किए जा सकते हैं.
मौजूदा डेटा को सुरक्षित रखने के नियमों का ऑडिट करना और उन्हें माइग्रेट करना
किसी प्लैटफ़ॉर्म रिपॉज़िटरी में मौजूद proguard.flags या keep.xml फ़ाइलों की ऑडिट करते समय, हर नियम का आकलन क्रम से करें. इसके लिए, चार चरणों वाली इस क्रम का पालन करें:
पहला चरण: काम के न रहे या पुराने नियम मिटाना
ऐसे नियमों को मिटाएं जो पहले से ही ग्लोबल बेसलाइन, AAPT2 मेनिफ़ेस्ट, लेआउट के नियमों या R8 के डिफ़ॉल्ट नियमों के तहत आते हैं. साथ ही, उन नियमों को भी मिटाएं जो अब मौजूद नहीं हैं.
अगर किसी .flags फ़ाइल में मौजूद सभी नियम काम के नहीं हैं, तो फ़ाइल मिटाएं और Android.bp से proguard_flags_files हटाएं. अगर बचे हुए optimize ब्लॉक में सिर्फ़ डिफ़ॉल्ट सेटिंग के बारे में बताया गया है, तो फ़ालतू ब्लॉक को हटाएं और बिल्ड फ़ाइल को bpfmt -w Android.bp के साथ फ़ॉर्मैट करें. किसी पैकेज को क्लीन अप करते समय, देखें कि सबडायरेक्ट्री में मौजूद कंपैनियन मॉड्यूल (जैसे, Kotlin टारगेट वैरिएंट) एक ही फ़्लैग फ़ाइल को रेफ़रंस करते हैं या नहीं. अगर ऐसा है, तो उन्हें एक साथ अपडेट करें.
दूसरा चरण: टेस्ट-ड्राइव के दौरान बनाए गए कीप के नियमों को माइग्रेट करना
टेस्ट-ड्रिवन कीप नियमों को कस्टम प्रोडक्शन .flags फ़ाइलों से बाहर ले जाएं. इसके लिए, इनमें से किसी एक पैटर्न का इस्तेमाल करें:
टेस्ट में लागू करने वाली लाइब्रेरी को लिंक करें (
static_libs): जब कोईandroid_test, किसी ऐप्लिकेशन की पैकेज-प्राइवेट या इंटरनल जानकारी का इस्तेमाल करता है, तो सुझाया गया प्लैटफ़ॉर्म आर्किटेक्चर यह है कि ऐप्लिकेशन की सोर्स फ़ाइलों कोandroid_library(MyApp.impl) में रखा जाए. साथ ही,MyApp.implकोMyAppऔरMyAppTests, दोनों में स्टैटिक तौर पर लिंक किया जाए: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"], }तीन मॉड्यूल वाले इस पैटर्न की मदद से,
MyAppTestsको इंटरनल क्लास के पूरे ऐक्सेस के साथ, खुद को इंस्ट्रुमेंट करने वाले टेस्ट के तौर पर चलाया जा सकता है. साथ ही,MyAppको टेस्ट में रुकावट डाले बिना,obfuscate: trueको आसानी से चालू किया जा सकता है. इससे प्रोडक्शन APK में, सिर्फ़ टेस्ट के लिए एंट्री पॉइंट शिप करने से बचा जा सकता है. साथ ही, टेस्ट कोड में बदलाव होने पर,MyAppको फिर से बनाने की ज़रूरत नहीं पड़ती.टेस्ट हुक को
@VisibleForTestingके साथ एनोटेट करें: अगर कोई बाहरी टेस्ट APK,android_appटारगेट पर इंटरनल तरीकों या कंस्ट्रक्टर की कम संख्या को कॉल करता है और.implलाइब्रेरी में फिर से स्ट्रक्चर करना मुश्किल है, तो उन घोषणाओं को@VisibleForTestingके साथ एनोटेट करें. ग्लोबलbuild/make/core/proguard.flagsबेसलाइन में,android.**,com.android.**, औरcom.google.android.**पैकेज में मौजूद@VisibleForTestingआइटम अपने-आप सेव हो जाते हैं. इसके लिए, कस्टम.flagsफ़ाइलों की ज़रूरत नहीं होती. (इन नेमस्पेस के बाहर मौजूद वेंडर मॉड्यूल के लिए,@UsedByReflectionया एक्सपोर्ट किए गए लाइब्रेरी नियमों का इस्तेमाल करें.)प्लेटफ़ॉर्म लाइब्रेरी की सीमाओं के पार
trace_references_fromका इस्तेमाल करें: जब टेस्ट, टारगेट इम्प्लीमेंटेशन को स्टैटिक तौर पर लिंक नहीं कर पाते हैं, तब टारगेट मॉड्यूल परtrace_references_fromकॉन्फ़िगर करें. उदाहरण के लिए, सिस्टम सर्वर सेवाओं याframework-connectivityजैसे प्लैटफ़ॉर्म JAR का इस्तेमाल करने वाले टेस्ट. टारगेट मॉड्यूल, टेस्ट सोर्स वाली Java लाइब्रेरी के कंपैनियन मॉड्यूल की ओर इशारा करता है. R8, कंपैनियन बाइटकोड से रेफ़र की गई सभी क्लास और कोड कॉम्पोनेंट को ट्रेस करता है और उन्हें बनाए रखता है.
तीसरा चरण: मालिकाना हक वाली लाइब्रेरी से नियम एक्सपोर्ट करना
अगर शेयर की गई java_library या android_library को अपने इंटरनल रिफ़्लेक्शन या जेएनआई कॉलबैक के लिए, डेटा को सेव रखने के नियमों की ज़रूरत है, तो लाइब्रेरी टारगेट पर नियम तय करें और 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,
},
}
स्टैटिक तौर पर लिंक किए गए सभी डाउनस्ट्रीम android_app और लाइब्रेरी टारगेट my-shared-library, उन नियमों को अपने-आप लागू कर देते हैं. इसलिए, डाउनस्ट्रीम ऐप्लिकेशन को उन्हें दोहराने की ज़रूरत नहीं होती. जब अलग-अलग डायरेक्ट्री में मौजूद कई मॉड्यूल को ऐसे नियम सेट को शेयर करना होता है जो किसी एक कोड लाइब्रेरी से नहीं जुड़ा होता है, तो Android.bp में साफ़ तौर पर filegroup के ज़रिए .flags फ़ाइल पब्लिश करें. इससे मॉड्यूल, पैकेज की सीमाओं के हिसाब से :my-shared-flags को आसानी से रेफ़रंस कर सकते हैं. डाउनस्ट्रीम ऐप्लिकेशन के ऑप्टिमाइज़ेशन को सीमित किए बिना, लाइब्रेरी के उपभोक्ता के डेटा को सुरक्षित रखने से जुड़े कीप नियमों को लिखने के बारे में सामान्य दिशा-निर्देशों के लिए, लाइब्रेरी तैयार करने वालों के लिए ऑप्टिमाइज़ेशन लेख पढ़ें.
चौथा चरण: सोर्स कोड में एनोटेट किए गए एलान
जब किसी क्लास, तरीके, कंस्ट्रक्टर या फ़ील्ड को रिफ़्लेक्शन या JNI के ज़रिए ऐक्सेस किया जाता है और वह AAPT2 या ग्लोबल बेसलाइन में शामिल नहीं होता है, तो .flags फ़ाइलों में अलग की गई -keep नियमों को Keep ऐनोटेशन के बारे में गाइड में दिए गए सोर्स ऐनोटेशन से बदलें (keepanno Javadoc रेफ़रंस देखें):
@UsesReflection: इस एनोटेशन का इस्तेमाल तब करें, जब आपके पास रिफ़्लेक्शन करने वाले कोड को कंट्रोल करने का विकल्प हो. इसे रिफ़्लेक्शन कॉल साइट पर रखें, ताकि यह एलान किया जा सके कि किन टारगेट क्लास, तरीकों या फ़ील्ड को डाइनैमिक तरीके से ऐक्सेस किया जाता है.@UsesReflection, एनोटेट की गई कॉल साइट के लिए, पहले से मौजूद शर्त को अपने-आप कोड में बदल देता है. इस शर्त के मुताबिक, कॉल साइट तक पहुंचा जा सकता है. इसलिए, अगर कॉल साइट का इस्तेमाल नहीं किया जाता है, तो R8, कॉलर और रिफ़्लेक्टिव टारगेट, दोनों को हटा देता है.@UsedByReflection: इसे उन क्लास, तरीकों, फ़ील्ड या कंस्ट्रक्टर पर रखें जिन्हें बाहरी कोड या लाइब्रेरी से इंस्टैंशिएट या इनवोक किया जाता है. जैसे,BundleयाSettingsकुंजियों सेClass.forNameके साथ लोड की गई क्लास या डाइनैमिक क्लासलोडर में लोड की गई प्लगिन क्लास.kind(जैसे किKeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition), और पैरामीटर की सीमाएं तय करें, ताकि R8 सिर्फ़ सटीक रिफ़्लेक्टिव कॉन्ट्रैक्ट को बनाए रखे. साथ ही, क्लास के इस्तेमाल न किए गए सदस्यों को अब भी ऑप्टिमाइज़ या हटाया जा सके.@UsedByReflectionकोJobServiceयाBroadcastReceiverजैसे मेनिफ़ेस्ट में रजिस्टर किए गए कॉम्पोनेंट में न जोड़ें, क्योंकि AAPT2 पहले से ही इन्हें सेव रखता है.@UsedByNative: इस एनोटेशन को उन तरीकों या फ़ील्ड पर रखें जिन्हें C या C++ JNI कोड से ऐक्सेस किया जाता है. इसके लिए,GetMethodID,GetStaticMethodIDयाGetFieldIDका इस्तेमाल करें.@KeepForApi: इसे लाइब्रेरी की उन एपीआई क्लास या सदस्यों पर रखें जिन्हें डिस्ट्रिब्यूट करने से पहले, लाइब्रेरी को छोटा करने पर भी बरकरार रखना है.@Keep(androidx.annotation.Keep): इसका इस्तेमाल तब करें, जबkeepannoलागू न हो. किसी क्लास पर@Keepलागू करने से, क्लास और उसके सभी कोड कॉम्पोनेंट बिना किसी शर्त के सुरक्षित रहते हैं. किसी तरीके या फ़ील्ड पर@Keepलागू करने से, बिना शर्त एंट्री पॉइंट के तौर पर काम किया जाता है. इससे सदस्य और उसकी क्लास को बनाए रखा जाता है. भले ही, क्लास को कभी इंस्टैंटिएट न किया गया हो. वहीं,keepannoसे शर्त के आधार पर पहुंच का पता चलता है.
Soong मॉड्यूल में R8 keepanno एनोटेशन का इस्तेमाल करने के लिए:
Android.bpमें"keepanno-annotations"कोlibsमें जोड़ें:libs: [ "keepanno-annotations", ],Java या Kotlin सोर्स कोड में,
com.android.tools.r8.keepanno.annotations.*इंपोर्ट करें और एलान या कॉल साइट को एनोटेट करें: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,
keepannoएनोटेशन को सीधे तौर पर अपने इंटरनल कीप रूल मॉडल में बदलता है. साथ ही, फ़ाइनल DEX आउटपुट से एनोटेशन हटा देता है. इससे रनटाइम बाइटकोड ओवरहेड नहीं बढ़ता.
अक्सर होने वाली गलतियों से बचना
यहां दिए गए सेक्शन में, प्लैटफ़ॉर्म कोड में अक्सर होने वाली proguard.flags और keep.xml गड़बड़ियों के बारे में बताया गया है. साथ ही, उन्हें ठीक करने का तरीका भी बताया गया है.
ब्रॉड कॉम्पोनेंट के रखरखाव के नियम
# Don't do this:
-keep class * extends android.app.Activity
-keep class * extends android.app.Service
-keep class * extends android.content.BroadcastReceiver
- इससे परफ़ॉर्मेंस पर क्या असर पड़ता है: यह नियम, AAPT2 के साथ पूरी तरह से काम नहीं करता.
यह वाइल्डकार्ड का इस्तेमाल करता है. हालांकि, यह जांच नहीं करता कि कॉम्पोनेंट को फ़ाइनल मर्ज किए गए
AndroidManifest.xmlमें रजिस्टर किया गया है या नहीं. इसलिए, R8 को क्लासपाथ पर मौजूद हरActivity,ServiceयाBroadcastReceiverसबक्लास को बनाए रखना पड़ता है. इनमें इस्तेमाल न किए गए लाइब्रेरी कॉम्पोनेंट और बंद की गई डीबग गतिविधियां भी शामिल हैं. - सुझाया गया तरीका: नियम को मिटाएं. AAPT2, मर्ज किए गए मेनिफ़ेस्ट की जांच करता है और रजिस्टर किए गए कॉम्पोनेंट के लिए, सटीक
-keepनियम जनरेट करता है.
ब्रॉड एक्सएमएल क्लिक हैंडलर के नियमों को बनाए रखना
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- परफ़ॉर्मेंस पर इसका क्या असर पड़ता है: मॉड्यूल की हर क्लास में हर
public void *(View)तरीके को बनाए रखने से, R8 किसी भी ऐसे तरीके को हटाने या इनलाइन करने से रोकता है जो एकViewपैरामीटर स्वीकार करता है. - सुझाया गया तरीका: नियम को मिटाएं. AAPT2, लेआउट एक्सएमएल फ़ाइलों को स्कैन करता है. साथ ही,
android:onClickएट्रिब्यूट से रेफ़र किए गए तरीकों के लिए, टारगेट किए गए कीप नियम जनरेट करता है.
ब्रॉड व्यू के लिए, गेटर और सेटर के रखरखाव से जुड़े नियम
# 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*();
}
- इससे परफ़ॉर्मेंस पर क्या असर पड़ता है: इस नियम की वजह से, R8 को ऐप्लिकेशन में मौजूद हर
Viewसबक्लास और लिंक की गई सभी लाइब्रेरी (AndroidX और Material लाइब्रेरी भी शामिल हैं) में हर गेटर और सेटर को बनाए रखना पड़ता है. इससे यूज़र इंटरफ़ेस (यूआई) कोड में, इस्तेमाल नहीं किए जा रहे तरीके हटाने और इनलाइन करने की प्रोसेस रुक जाती है. - सुझाया गया तरीका: नियम को मिटाएं. AAPT2, लेआउट एक्सएमएल फ़ाइलों से इन्फ्लेट की गई कस्टम
Viewक्लास के लिए, कंस्ट्रक्टर पहले से ही सेव करता है. अगर कोड, रिफ़्लेक्टिव स्ट्रिंग के नामों का इस्तेमाल करके व्यू प्रॉपर्टी को ऐनिमेट करता है, जैसे किObjectAnimator.ofFloat(view, "translationZ", ...), तो स्ट्रिंग के नाम को टाइप की गई प्रॉपर्टी के रेफ़रंस (View.TRANSLATION_Zया कस्टमFloatPropertyयाIntPropertyलागू करने) से बदलें, ताकि रिफ़्लेक्शन से पूरी तरह बचा जा सके. अगर रिफ़्लेक्टिव प्रॉपर्टी के ऐक्सेस से बचा नहीं जा सकता, तो@UsedByReflectionका इस्तेमाल करके, खास तौर पर getter या setter को एनोटेट करें.
ब्लैंकेट ऑप्टिमाइज़ेशन या ओब्फ़स्केशन की सुविधा बंद हो जाती है
# Don't do this in proguard.flags:
-dontoptimize
-dontshrink
-dontobfuscate
- इससे परफ़ॉर्मेंस पर क्या असर पड़ता है:
.flagsफ़ाइल में-dontoptimizeया-dontshrinkरखने से, मॉड्यूल कीAndroid.bpसेटिंग अपने-आप बदल जाती हैं. साथ ही, पूरे टारगेट के लिए ऑप्टिमाइज़ेशन पास बंद हो जाते हैं. इससे भी बुरी बात यह है कि अगर कोई लाइब्रेरी,-dontoptimizeवाली.flagsफ़ाइल एक्सपोर्ट करती है, तो यह लाइब्रेरी से लिंक होने वाले हर डाउनस्ट्रीमandroid_appके लिए, R8 ऑप्टिमाइज़ेशन को बंद कर देती है. - सुझाया गया तरीका:
.flagsफ़ाइलों से-dontoptimize,-dontshrink, और-dontobfuscateहटाएं. पत्ती वाले टारगेट परoptimizeब्लॉक (shrink,optimize,obfuscate) का इस्तेमाल करके,Android.bpमें ऑप्टिमाइज़ेशन के तरीके को साफ़ तौर पर कंट्रोल करें.
कमिट किए गए नियमों में डाइग्नोस्टिक फ़्लैग
# Don't do this in proguard.flags:
-verbose
-printmapping proguard.map
-printusage usage.txt
-printconfiguration config.txt
- इससे बिल्ड पर क्या असर पड़ता है: गड़बड़ी की जानकारी देने वाले फ़्लैग, बिल्ड लॉग में भर जाते हैं या सैंडबॉक्स किए गए Soong बिल्ड के दौरान, आउटपुट फ़ाइलों को लोकल पाथ पर लिखने की कोशिश करते हैं.
- सुझाया गया तरीका: कमिट की गई
.flagsफ़ाइलों से इन फ़्लैग को मिटाएं. Soong, R8 मैपिंग और इस्तेमाल से जुड़े आउटपुट को अपने-आप लिखता है. जैसे,proguard_dictionaryऔरproguard_usage.zip. ये आउटपुट,out/soong/.intermediates/में मौजूद मॉड्यूल की इंटरमीडिएट डायरेक्ट्री में सेव होते हैं.
टेस्ट कोड के लिए प्रोडक्शन कीप नियम
- इससे परफ़ॉर्मेंस पर क्या असर पड़ता है: सिर्फ़ टेस्ट के लिए कस्टम
-keepनियम जोड़ने से, कोड को प्रोडक्शन बिल्ड में बिना किसी बदलाव के रखा जाता है.@VisibleForTestingका इस्तेमाल करके तरीकों को एनोटेट करने याtrace_references_fromको कॉन्फ़िगर करने से, मैन्युअल-keepनियमों को बनाए रखने से बचा जा सकता है. हालांकि, ये सिंबल अब भी प्रोडक्शन बाइनरी में शामिल होते हैं. - सुझाया गया तरीका: टेस्ट के लिए बनाए गए एंट्री पॉइंट को प्रोडक्शन APK से पूरी तरह से हटाने के लिए, ऐप्लिकेशन को
.implलाइब्रेरी में स्ट्रक्चर करें. इसके बाद,static_libsका इस्तेमाल करके, इसे खुद से इंस्ट्रुमेंट करने वाले टेस्ट APK में लिंक करें. इसके बारे में दूसरे चरण: टेस्ट-ड्रिवन कीप नियमों को माइग्रेट करना में बताया गया है.
keep.xml में ब्लैंकेट रिसॉर्स वाइल्डकार्ड
<!-- Don't do this in res/raw/keep.xml: -->
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@raw/*,@drawable/*,@string/*" />
- परफ़ॉर्मेंस पर इसका क्या असर पड़ता है: ब्लैंकेट वाइल्डकार्ड, मॉड्यूल और उसकी डिपेंडेंसी में मैच होने वाले हर संसाधन को बनाए रखते हैं. इससे संसाधन कम करने (
shrink_resources: true) की प्रोसेस पूरी नहीं हो पाती. साथ ही, APK और मैप की गईresources.arscटेबल का साइज़ बढ़ जाता है. - समस्या हल करने का सुझाव:
keep.xmlके बजाय स्टैटिक रिसॉर्स रेफ़रंस का इस्तेमाल करें:Resources.getIdentifierतरीके का इस्तेमाल करके, एक्सपेरिमेंट की नंबर वाली स्ट्रिंग या थीम वाले ड्रॉएबल जैसे रिसॉर्स के सीमित सेट को डाइनैमिक तरीके से खोजने से बचें. इसके बजाय, कंपाइल-टाइमswitchस्टेटमेंट का इस्तेमाल करें या स्टैटिकR.id,R.stringयाR.drawableकॉन्सटेंट पर मैप करें. स्टैटिक रेफ़रंस की मदद से, R8 और AAPT2, लाइव रिसॉर्स का सटीक पता लगा सकते हैं. साथ ही, रनटाइम स्ट्रिंग लुकअप के ओवरहेड को कम कर सकते हैं. इसके अलावा,keep.xmlकी ज़रूरत भी नहीं पड़ती.- संसाधन के नाम की सूची बनाएं: अगर डाइनैमिक लुकअप की ज़रूरत है, जैसे कि तीसरे पक्ष के लाइसेंस रीडर के लिए, तो
tools:keepमें संसाधन के सटीक आइडेंटिफ़ायर की सूची बनाएं (उदाहरण के लिए,tools:keep="@raw/third_party_licenses"). - बेकार
keep.xmlफ़ाइलें मिटाएं: अगर सूची में दिए गए संसाधनों को कोड (R.raw.foo) या एक्सएमएल (@raw/foo) में पहले से ही स्टैटिक तौर पर रेफ़रंस दिया गया है, तो श्रिंक करने वाला टूल उन्हें अपने-आप बनाए रखता है. इसलिए, आपके पासres/raw/keep.xmlको मिटाने का विकल्प होता है.
नियम में किए गए बदलावों की पुष्टि करना और उनकी जांच करना
proguard.flags या keep.xml में डेटा सुरक्षित रखने से जुड़े नियमों को हटाने या कम करने पर, यह पुष्टि करें कि मॉड्यूल सही तरीके से काम कर रहा हो, यूनिट और इंस्ट्रूमेंटेशन टेस्ट पास कर रहा हो, और सभी ज़रूरी एंट्री पॉइंट बनाए रख रहा हो.
मॉड्यूल बनाना और उनकी जांच करना
मॉड्यूल को इस तरह से बनाएं कि R8 और AAPT2, रेफ़रंस से जुड़ी चेतावनियों के बिना पूरा हो जाए:
m <MODULE_NAME>atestका इस्तेमाल करके, मॉड्यूल के लिए यूनिट और इंस्ट्रुमेंटेशन टेस्ट चलाएं:atest <TEST_MODULE_NAME>सिस्टम ऐप्लिकेशन, खास सेवाओं या हार्डवेयर पर निर्भर मॉड्यूल के लिए, टारगेट किए गए फ़िज़िकल डिवाइसों या अपने डिवाइस के टेस्ट लैब में इंस्ट्रुमेंटेशन और यूआई टेस्ट चलाएं. इससे रनटाइम रिफ़्लेक्शन पाथ, आईपीसी बाइंडिंग, और संसाधन इन्फ़्लेशन का इस्तेमाल किया जा सकेगा.
डीईएक्स और संसाधन के अंतर की जांच करना
नियमों में बदलाव करने से पहले और बाद में, कंपाइल किए गए APK या JAR की तुलना करें. इससे यह पुष्टि की जा सकेगी कि R8, डेड कोड और संसाधनों को हटा देता है. हालांकि, वह एंट्री पॉइंट को नहीं हटाता:
आउटपुट APK या DEX फ़ाइलों में सेव की गई क्लास, तरीकों, और फ़ील्ड की जांच करने के लिए,
apkanalyzerयाdexdumpका इस्तेमाल करें:apkanalyzer dex packages $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apkkeep.xmlमें बदलाव करते समय याshrink_resourcesको चालू करते समय,aapt2 dump resourcesका इस्तेमाल करके यह पुष्टि करें कि बिल्ड, इस्तेमाल न किए गए संसाधनों को हटा देता है और ज़रूरी संसाधनों को बनाए रखता है:aapt2 dump resources $OUT/system/priv-app/<APP_NAME>/<APP_NAME>.apk
R8 की मदद से, कीप रेडियस और नियम के पालन का विश्लेषण करना
ओपन-सोर्स R8 कंपाइलर में, कीप रेडियस ऐनालाइज़र शामिल होता है. इसे Android Studio और Gradle में R8 कॉन्फ़िगरेशन ऐनालाइज़र के तौर पर भी दिखाया जाता है. यह कंपाइलेशन के दौरान, हर कीप रूल के सटीक असर का आकलन करता है. Soong, इस ऐनलाइज़र को सीधे तौर पर Android प्लैटफ़ॉर्म बिल्ड में इंटिग्रेट करता है. इसे build/soong/java/dex.go में कॉन्फ़िगर किया जाता है.
किसी प्लैटफ़ॉर्म मॉड्यूल या पूरे बिल्ड के लिए, कीप रूल का विश्लेषण करने के लिए:
R8_DUMP_KEEP_RADIUS=trueएनवायरमेंट वैरिएबल के साथ बिल्ड चलाएं:R8_DUMP_KEEP_RADIUS=true m <MODULE_NAME>R8_DUMP_KEEP_RADIUS=trueसेट होने पर, Soong, R8 को यह निर्देश देता है कि वहout/soong/.intermediates/के तहत कंपाइल किए गए हर मॉड्यूल के लिए, इंटरमीडिएटr8keepradius.pbफ़ाइल में रिकॉर्ड कीप रूल मेट्रिक रिकॉर्ड करे. हर कीप रूल औरkeepannoएनोटेशन के लिए, R8 यह जानकारी रिकॉर्ड करता है:- तुरंत सुरक्षित रखने का दायरा: नियम के तहत सुरक्षित रखी गई क्लास, फ़ील्ड, और तरीके. साथ ही, कोड को छोटा करने, ऑप्टिमाइज़ करने या छिपाने के ख़िलाफ़ लागू की गई खास पाबंदियां.
- नियमों का पालन करना: कौनसे अन्य कीप रूल या एनोटेशन पहले से ही एक जैसे आइटम सेव करते हैं. अगर कोई कस्टम नियम, AAPT2 के नियम या ग्लोबल बेसलाइन नियम के दायरे में पूरी तरह से आता है, तो उसे सुरक्षित तरीके से मिटाया जा सकता है.
- पूरे पैकेज और ग्लोबल लेवल पर लागू होने वाले नियम: ऐसे नियम जो पूरे पैकेज के लिए वाइल्डकार्ड का इस्तेमाल करते हैं या ग्लोबल कॉन्फ़िगरेशन डायरेक्टिव लागू करते हैं.
r8keepradius.pbआउटपुट को इंटरैक्टिव एचटीएमएल रिपोर्ट में बदलें. इसके लिए,KeepRadiusHtmlReportGenerator(prebuilts/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_reportsकिसी डायरेक्ट्री को इनपुट के तौर पर देने पर,
KeepRadiusHtmlReportGeneratorसभी*keepradius*.pbफ़ाइलों को स्कैन करता है. साथ ही, हर मॉड्यूल के लिए एक एचटीएमएल रिपोर्ट जनरेट करता है. इसके अलावा, यहout/keep_radius_reports/keepradius.htmlबनाता है. इसमें लाइव आइटम की संख्या, रखे गए आइटम की संख्या, और बिल्ड में सबसे ज़्यादा रेडियस वाले कीप नियमों की खास जानकारी होती है. जनरेट की गई रिपोर्ट में, कोड के साइज़ को कम करने, ऑप्टिमाइज़ करने, और कोड को छिपाने से जुड़े स्कोर को समझने के बारे में ज़्यादा जानने के लिए, R8 कॉन्फ़िगरेशन ऐनलिसिस टूल का इस्तेमाल करना लेख पढ़ें.
Soong, build/soong/java/dex.go में R8 के दो अन्य डाइग्नोस्टिक एनवायरमेंट वैरिएबल का भी इस्तेमाल करता है:
R8_DUMP_INPUT=true: यहr8inputs.zipको मॉड्यूल की इंटरमीडिएट डायरेक्ट्री में लिखता है. इस डायरेक्ट्री में सभी इनपुट JAR, लाइब्रेरी JAR, और मर्ज किए गए ProGuard कॉन्फ़िगरेशन होते हैं. इनका इस्तेमाल, स्टैंडअलोन R8 को फिर से बनाने के लिए किया जाता है.R8_DUMP_PERFETTO_TRACE=true: यहr8trace.ptraceको मॉड्यूल की इंटरमीडिएट डायरेक्ट्री में लिखता है, ताकि Perfetto में R8 कंपाइलेशन पास की जांच की जा सके.
लाइब्रेरी के उपभोक्ता नियमों की पुष्टि करना
जब कोई java_library या android_library, डेटा सुरक्षित रखने के नियमों को डाउनस्ट्रीम उपभोक्ताओं (export_proguard_flags_files: true) को एक्सपोर्ट करता है, तो उन नियमों में ऐसे ग्लोबल फ़्लैग शामिल नहीं होने चाहिए जो डेटा का इस्तेमाल करने वाले ऐप्लिकेशन के ऑप्टिमाइज़ेशन में बदलाव करते हैं या उसे बंद करते हैं.
R8, ओपन-सोर्स कीप रूल ऐनललाइज़र (ProcessKeepRules) उपलब्ध कराता है. इसे Android प्लैटफ़ॉर्म के बिल्ड में process-keep-rules होस्ट टूल के तौर पर दिखाया जाता है. इसे 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>
process-keep-rules टूल, हर कॉन्फ़िगरेशन फ़ाइल को पार्स करता है. अगर उसे ऐसे डायरेक्टिव मिलते हैं जिन्हें लाइब्रेरी के उपभोक्ता नियमों में अनुमति नहीं है, तो वह फ़ाइल और लाइन के डाइग्नोस्टिक्स के साथ काम नहीं करता. अनुमति न दिए गए डायरेक्टिव में ये शामिल हैं: ग्लोबल ऑप्टिमाइज़ेशन, छोटा करना या अस्पष्ट करने की सुविधा बंद करना (जैसे कि -dontoptimize या -dontshrink), पैकेज को फिर से पैक करना और ऐक्सेस में बदलाव करने के फ़्लैग, गड़बड़ी की जानकारी देने वाले या मैपिंग फ़्लैग, और ऐप्लिकेशन-लेवल -keepattributes.
pgaudit.py की मदद से सोर्स ट्री की ऑडिट करना
R8 के बिल्ड-टाइम ऐनलाइज़र के साथ-साथ, सोर्स डायरेक्ट्री की ऑडिट करने के लिए, Android प्लैटफ़ॉर्म ट्री में pgaudit.py स्क्रिप्ट को build/make/core/proguard/tools/ में शामिल किया गया है. यह स्टैटिक विश्लेषण टूल, किसी रिपॉज़िटरी में मौजूद Android.bp, proguard.flags, और keep.xml फ़ाइलों को स्कैन करता है. इससे उन नियमों को फ़्लैग किया जा सकता है जो पहले से ही AAPT2 या ग्लोबल प्लैटफ़ॉर्म की बेसलाइन, ब्रॉड वाइल्डकार्ड, -dontoptimize ओवरराइड, और सिर्फ़ टेस्ट के लिए बनाए गए नियमों के दायरे में आते हैं:
# 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
प्लैटफ़ॉर्म और ओईएम टीमें, pgaudit.py का इस्तेमाल करके सोर्स-ट्री की गड़बड़ियों का तुरंत पता लगा सकती हैं. साथ ही, process-keep-rules का इस्तेमाल करके एक्सपोर्ट की गई लाइब्रेरी के नियमों की पुष्टि कर सकती हैं. इसके अलावा, R8_DUMP_KEEP_RADIUS=true और KeepRadiusHtmlReportGenerator का इस्तेमाल करके, किसी बिल्ड में मौजूद हर नियम के क्लास, फ़ील्ड, और तरीके के रिटेंशन रेडियस का सटीक आकलन कर सकती हैं.