Android প্ল্যাটফর্ম বিল্ড সিস্টেম (Soong) R8 কম্পাইলারকে
টার্গেটে রান করে যা DEX বাইটকোড কম্পাইল করে, যার মধ্যে Android অ্যাপ (android_app), টেস্ট
(android_test) এবং compile_dex: true সহ ইনস্টলযোগ্য Java লাইব্রেরি (যেমন
services.jar) অন্তর্ভুক্ত, যাতে অব্যবহৃত কোড এবং রিসোর্স সঙ্কুচিত, অপ্টিমাইজ এবং স্ট্রিপ করা যায়। স্ট্যাটিক লাইব্রেরিতে (android_library এবং স্ট্যাটিক java_library), Soong সরাসরি R8 রান করে না, তবে ডাউনস্ট্রিম DEX টার্গেটে কনজিউমার কিপ রুল (export_proguard_flags_files: true) অ্যাটাচ ও প্রোপাগেট করতে optimize প্রপার্টি ব্লক ব্যবহার করে যা তাদের স্ট্যাটিক্যালি লিঙ্ক করে।
সিস্টেম ইমেজ বা ভেন্ডর প্যাকেজ তৈরি করা প্ল্যাটফর্ম ইঞ্জিনিয়ারদের জন্য, অত্যধিক বিস্তৃত নিয়ম বাদ দিলে তা সরাসরি সিস্টেমের স্বাস্থ্যকে উন্নত করে:
- ছোট সিস্টেম পার্টিশন ফুটপ্রিন্ট: R8,
/system,/system_ext,/productএবং/vendor-এ APK ও JAR প্যাকেজ করার আগে ডেড ক্লাস, পদ্ধতি এবং রিসোর্স সরিয়ে দেয়। - ছোট কম্পাইল করা আর্টিফ্যাক্ট: কম DEX মেথড মানে হল বিল্ড-টাইম বা অন-ডিভাইস কম্পাইলেশনের সময়
dex2oat-এর মাধ্যমে জেনারেট করা ছোট.odexএবং.vdexফাইল। - রানটাইম মেমরি প্রেসার কমানো: কারণ Android, ডিমান্ড-পেজড
mmapকল ব্যবহার করে প্রসেস মেমরিতে.odex,.vdexএবং APK রিসোর্স টেবিল ম্যাপ করে, ছোট বাইনারি অ্যাপ স্টার্টআপের সময় প্রধান পৃষ্ঠা সংক্রান্ত ত্রুটি কমায় এবং প্রসেস জুড়ে রেসিডেন্ট কোড এবং রিসোর্স মেমরি কমায়। কম্পাইল করা অ্যাপ কোড কীভাবে ডিভাইসের মেমরিকে প্রভাবিত করে সেই সম্পর্কে আরও তথ্যের জন্য, অ্যাপ কোড হল মেমরি দেখুন। - আরও কার্যকর সম্পূর্ণ-প্রোগ্রাম অপ্টিমাইজেশন: ন্যারো কিপ কনস্ট্রেন্ট R8 ইনলাইন পদ্ধতি, ডেভার্চুয়ালাইজ ইন্টারফেস ও ভার্চুয়াল কল, অব্যবহৃত ফিল্ড ছাঁটাই এবং ক্লাস জুড়ে কনস্ট্যান্ট প্রোপাগেট করতে দেয়।
Soong-এ R8 অপ্টিমাইজেশন কনফিগার করুন
Android.bp ফাইলে, android_app এবং ইনস্টলযোগ্য java_library টার্গেটে (অথবা
android_library এবং স্ট্যাটিক java_library মডিউলে কনজিউমার কিপ
নিয়ম এক্সপোর্ট করতে) optimize প্রপার্টি ব্লক ব্যবহার করে R8 অপ্টিমাইজেশন কনফিগার করুন:
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 সেট করা থাকে, তবে DEX সাইজ কমাতে এবং
আরও গভীর অপ্টিমাইজেশন আনলক করতে যেখানে সম্ভব সেখানে এটি
true-এ সেট করুন (যেখানে সম্ভব সেখানে অস্পষ্টতা চালু করুন দেখুন)।
|
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 |
সরাসরি DEX-কম্পাইলিং ডিপেন্ডেন্ট টার্গেটের তালিকা (instrumentation_for বা libs-এর মাধ্যমে কানেক্ট করা) যার বাইটকোড
এই টার্গেটে রেফারেন্স R8 অটোমেটিক ট্রেস করে এবং রেখে দেয় (এছাড়াও
override_android_app এবং
override_android_test ভেরিয়েন্ট জুড়ে প্রোপাগেট করা হয় এবং
.impl স্প্লিটের সাথে পেয়ার করা হলে নন-ডিপেন্ডেন্ট কম্প্যানিয়ন জাভা লাইব্রেরির জন্য
সাপোর্ট করা হয়)।
|
allow_traced_references |
সরাসরি DEX-কম্পাইলিং নির্ভর টার্গেটকে (instrumentation_for বা libs-এর মাধ্যমে কানেক্ট করা, যেমন
ক্রস-রিপোজিটরি বা ভেন্ডর টেস্ট যা
trace_references_from-এ তালিকাভুক্ত করা যায় না)
trace_references: true সেট করে এই টার্গেটে তাদের বাইটকোড রেফারেন্স ট্রেস করার জন্য
চালু করার অনুমতি দেয়।
|
trace_references |
allow_traced_references: true সহ কোনও টার্গেটের সরাসরি DEX-কম্পাইলিং ডিপেন্ডেন্টে
true-এ সেট করা হলে, এই মডিউলে R8
tracereferences রান করে এবং জেনারেট করা
কিপ রুল টার্গেট মডিউলে পাস করে।
|
protect_api_surface |
--protect-api-surface থেকে R8-এ পাস করে। java_sdk_library-এ সেট করা হলে,
এটি অটোমেটিক Metalava API কিপ রুল তৈরি করে
এবং সব চালু থাকা API স্কোপ (পাবলিক,
সিস্টেম, মডিউল-লাইব্রেরি, সিস্টেম-সার্ভার এবং টেস্ট) জুড়ে ইমপ্লিমেন্টেশন
লাইব্রেরিতে অ্যাটাচ করে।
|
স্ট্যাটিক লাইব্রেরি (android_library, java_library এবং AAR ইমপোর্ট)
Android.bp-এ required_downstream_optimization: { enabled: true, optimize: true } সেট করতে পারে যাতে যেকোনও ডাউনস্ট্রিম DEX-কম্পাইলিং টার্গেট যা স্ট্যাটিক্যালি
তাদের লিঙ্ক করে (সরাসরি বা ট্রানজিটিভভাবে) R8 সঙ্কোচন এবং বাইটকোড
অপ্টিমাইজেশন চালু করতে পারে। Soong এটি অটোমেটিক চালু করে
androidx.compose.runtime_runtime যাতে Jetpack Compose-এর সাথে লিঙ্ক করা টার্গেট
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 (বা স্পষ্টভাবে পাবলিক API নাম সংরক্ষণ করুন) রাখুন:
- bootclasspath বা
system_serverক্লাসপাথে শেয়ার করা লাইব্রেরি: রান টাইমে অন্যান্য মডিউল দ্বারা ডাইনামিকভাবে লিঙ্ক করা এক্সটার্নাল API সারফেস প্রকাশ করে এমন মডিউল (java_libraryবাjava_sdk_library) (যেমনframework.jar,services.jarবা<uses-library>টার্গেট) হয়obfuscate: falseরাখতে হবে অথবাprotect_api_surface: true,@KeepForApiবা-keepনিয়ম ব্যবহার করে তাদের API সারফেস স্পষ্টভাবে সংরক্ষণ করতে হবে যাতে তাদের স্টাবের বিরুদ্ধে কম্পাইল করা কলার রান টাইমে ক্লাস এবং মেম্বারের নাম সমাধান করতে পারে।java_sdk_libraryমডিউলে,protect_api_surface: trueসেটিং অটোমেটিক Metalava ProGuard-এর নিয়ম তৈরি করে এবং সব চালু থাকা API স্কোপ (পাবলিক, সিস্টেম, মডিউল-লাইব্রেরি, সিস্টেম-সার্ভার এবং টেস্ট) জুড়ে ইমপ্লিমেন্টেশন লাইব্রেরিতে অ্যাটাচ করে। আপডেট করা যাবে না এমন bootclasspath টার্গেটে (framework-minus-apex,extএবংframework-location) সাধারণ R8 অপ্টিমাইজেশন চালু করা হলে, সেগুলিframework-hiddenapi-proguard-rules-কেও (hiddenapi_to_proguard-এর মাধ্যমে জেনারেট করা) অন্তর্ভুক্ত করে যাতে অ্যাক্টিভboot/hiddenapi/*.txtফাইলে (hiddenapi-max-target-o.txtবাদ দিয়ে) তালিকাভুক্ত মেম্বারদের ধরে রাখা যায়।
কোনও অ্যাপ্লিকেশনে obfuscate: true চালু করার আগে, মাইগ্রেশন সংক্রান্ত নিম্নলিখিত
পূর্বশর্তগুলি যাচাই করুন:
- এক্সটার্নাল টেস্ট APK ডিপেন্ডেন্সি: যদি কোনও এক্সটার্নাল
android_testAPKinstrumentation_for: "MyApp"সেট করে এবং সরাসরিMyApp-এর ইন্টার্নাল ক্লাস বা মেথডকে ইনভোক করে, তাহলে সেইসব সিম্বলের নাম পরিবর্তন করলে টেস্ট রান টাইমেNoSuchMethodErrorবাNoClassDefFoundErrorহয়।trace_references_fromকনফিগার করুন (অথবাtrace_references: true-এর সাথেallow_traced_references),MyApp.impl-কে স্ট্যাটিক্যালি লিঙ্ক করে সেল্ফ-ইনস্ট্রুমেন্টিং APK হিসেবে টেস্ট স্ট্রাকচার করুন অথবা@VisibleForTesting-এর সাথে টেস্ট হুক অ্যানোটেট করুন (ধাপ ২: টেস্ট-চালিত কিপ রুল মাইগ্রেট করুন দেখুন) যাতে টেস্টের জন্য প্রয়োজনীয় ইন্টার্নাল সিম্বলগুলি অ্যাপের বাকি অংশ অস্পষ্ট করার সময় সংরক্ষিত থাকে। - স্ট্রিং-ভিত্তিক রিফ্লেকশন ও 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 ফাইল যোগ বা রেখে দেওয়ার আগে, নিয়মটি আগে থেকেই ডিফল্ট বেসলাইন দ্বারা ম্যানেজ করা হচ্ছে কিনা অথবা কোড অ্যানোটেশনে মাইগ্রেট করা যাবে কিনা তা যাচাই করুন।
ডিফল্ট প্ল্যাটফর্ম রাখার নিয়ম সম্পর্কে বোঝা
DEX-কম্পাইলিং টার্গেটে (android_app, android_test এবং
ইনস্টল করা যায় এমন java_library মডিউল) প্রতিটি R8 ইনভোকেশনে Soong অটোমেটিক নিম্নলিখিত গ্লোবাল বেসলাইন নিয়ম পাস করে, যা build/soong/java/dex.go-এ কনফিগার করা আছে:
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ফিল্ড এবং protobufMessageLiteফিল্ডের জন্যSourceFileঅ্যাট্রিবিউট সংরক্ষণ করে।build/make/core/proguard/kotlin.flags: নির্দিষ্ট Kotlin মেটা-অ্যানোটেশনের (kotlin.Metadataএবংkotlin.annotation.{AnnotationRetention,AnnotationTarget,Retention,Target}) জন্য ক্ষতিকর নয় এমন সতর্কতা সাইলেন্স করে এবং রিলিজ বিল্ডে KotlinDebugMetadataঅ্যানোটেশন স্ট্রিপ করে।build/make/core/proguard/checknotnull.flags: সাধারণ নাল চেক হেল্পার কল (com.google.common.base.Preconditions.checkNotNullএবংdagger.internal.Preconditions.checkNotNull*) সংক্ষিপ্ত বাইটকোড নাল চেক দিয়ে প্রতিস্থাপন করে। ফ্রেমওয়ার্ক API বাউন্ডারি জুড়ে ব্যতিক্রমী মেসেজ স্পষ্টভাবে সংরক্ষণ করতে এই ফাইল ইচ্ছাকৃতভাবেObjects.requireNonNullবাদ দেয়।build/make/core/proguard/enumvalues.flags: বিল্ড কনফিগারেশন দ্বারা বন্ধ না করা পর্যন্তenumধরনের উপরvaluesএবংvalueOfপদ্ধতি বজায় রাখে।- AAPT2 অটোমেটিক জেনারেট করা নিয়ম: AAPT2 মার্জ করা
AndroidManifest.xml, লেআউট XML এবং প্রেফারেন্স XML ফাইল পরীক্ষা করে দেখে যাতে প্রতিটি রেজিস্টার করাActivity,Service,BroadcastReceiver,ContentProvider,BackupAgent,Application, কাস্টমViewসাবক্লাস,Preferenceসাবক্লাস এবং XMLandroid:onClickপদ্ধতির জন্য সঠিক নিয়ম বজায় রাখা যায়।
আগে থেকে থাকা রাখার নিয়ম অডিট ও মাইগ্রেট করা
কোনও প্ল্যাটফর্ম রিপোজিটরিতে আগে থেকে থাকা proguard.flags বা keep.xml ফাইল অডিট করার সময়, নিম্নলিখিত চার-ধাপের ক্রম অনুযায়ী প্রতিটি নিয়ম মূল্যায়ন করুন:
ধাপ ১: অপ্রয়োজনীয় বা পুরনো নিয়ম মুছে দিন
গ্লোবাল বেসলাইন, AAPT2 ম্যানিফেস্ট এবং লেআউট রুল বা R8 ডিফল্ট দ্বারা আগে থেকেই কভার করা হয়েছে এমন রুল মুছে দিন, এর পাশাপাশি এমন রুলও মুছে দিন যা আর নেই এমন ক্লাস বা প্যাকেজকে রেফার করে।
.flags ফাইলের সব নিয়ম অপ্রয়োজনীয় হলে, ফাইলটি মুছে দিন এবং Android.bp থেকে
proguard_flags_files সরিয়ে দিন। বাকি optimize ব্লক যদি শুধু
ডিফল্ট সেটিংস রিস্টেট করে, তাহলে অপ্রয়োজনীয় ব্লক সরিয়ে দিন এবং bpfmt -w Android.bp দিয়ে
বিল্ড ফাইল ফর্ম্যাট করুন। কোনও প্যাকেজ ক্লিন-আপ করার সময়, সাবডিরেক্টরিতে (যেমন, Kotlin টার্গেট ভেরিয়েন্ট) কম্প্যানিয়ন মডিউল একই ফ্ল্যাগ ফাইল রেফারেন্স করে কিনা তা চেক করুন এবং একসাথে সেগুলি আপডেট করুন।
ধাপ ২: টেস্ট-ড্রিভেন রাখার নিয়ম মাইগ্রেট করুন
নিম্নলিখিত প্যাটার্নের মধ্যে একটি ব্যবহার করে কাস্টম প্রোডাকশন .flags ফাইল থেকে টেস্ট-ড্রিভেন কিপ রুল সরান:
টেস্ট বা কম্প্যানিয়ন টার্গেট থেকে রেফারেন্স ট্রেস করা (
trace_references_fromবাallow_traced_references): টার্গেট এবং সরাসরি নির্ভরশীল মডিউল, দুটিই যখন নিজস্ব DEX (android_app,android_test, বা dexedjava_library) কম্পাইল করে এবংinstrumentation_forবাlibs-এর মাধ্যমে কানেক্ট করা থাকে, তখন Soong, নির্ভরশীল মডিউলে R8tracereferencesচালাতে পারে এবং তৈরি করা নিয়ম টার্গেটের R8 কম্পাইলেশনে ফিড করতে পারে। এর জন্য কোনও ডিপেন্ডেন্সি সাইকেল তৈরি করতে হয় না বা ম্যানুয়ালি.implলাইব্রেরি স্প্লিট করতে হয় না:একই-রিপোজিটরি টেস্ট (
trace_references_from): টার্গেট মডিউলের উপর সরাসরিinstrumentation_forবাlibsনির্ভরশীলদের তালিকা তৈরি করুন (এটিoverride_android_appএবংoverride_android_testভেরিয়েন্ট জুড়ে অটোমেটিক প্রোপাগেট করে এবং.implস্প্লিটের সাথে পেয়ার করা হলে, নির্ভরশীল নয় এমন কম্প্যানিয়ন Java লাইব্রেরিতে সহায়তা করা চালিয়ে যায়):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"], }ক্রস-রিপোজিটরি বা ভেন্ডর টেস্ট (
allow_traced_referencesএবংtrace_references): টার্গেট মডিউলtrace_references_from-এ সরাসরি ডিপেন্ডেন্ট তালিকাভুক্ত করতে না পারলে (যেমন অন্য রিপোজিটরি বা ভেন্ডর ট্রিতে টেস্ট), টার্গেট মডিউলেallow_traced_references: trueসেট করুন এবংtrace_references: true-এর মাধ্যমে প্রতিটি ডিপেন্ডেন্ট থেকে অপ্ট-ইন করুন: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, }, }টেস্টে স্ট্রিং-ভিত্তিক রিফ্লেকশন:
tracereferencesবাইটকোড কনস্ট্যান্ট-পুল রেফারেন্স পরীক্ষা করে এবং টেস্টে স্ট্রিং-ভিত্তিক রিফ্লেকশন শনাক্ত করতে পারে না (Class.forName,getDeclaredField,getDeclaredMethodবা রিফ্লেক্টিভ ফিল্ড-ইনজেকশন হেল্পার)। রিফ্লেক্টিভভাবে অ্যাক্সেস করা প্রোডাকশন ফিল্ড ও পদ্ধতি@VisibleForTesting(বা@UsedByReflection) দিয়ে অ্যানোটেট করুন।
টেস্টে ইমপ্লিমেন্টেশন লাইব্রেরি লিঙ্ক করা (
static_libs): আপনি যদি প্রোডাকশন APK-তে শূন্য টেস্ট-অনলি এন্ট্রি পয়েন্ট রাখতে চান এবং প্রোডাকশন টার্গেটে R8 রিট্রিগার করার জন্য টেস্ট পরিবর্তন করতে না চান, তাহলে অ্যাপ সোর্স ফাইলগুলি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-কে প্রোডাকশন এন্ট্রি পয়েন্টের বিরুদ্ধে সম্পূর্ণভাবে সঙ্কুচিত ও অস্পষ্ট করতে দেয়।টেস্ট হুককে
@VisibleForTesting: দিয়ে অ্যানোটেট করুন। কোনও এক্সটার্নাল টেস্ট APK যদিandroid_appটার্গেটে শুধুমাত্র কয়েকটি ইন্টার্নাল মেথড বা কনস্ট্রাক্টরকে কল করে, তাহলে আপনি সেইসব ডিক্লারেশনকে@VisibleForTestingদিয়ে অ্যানোটেট করতে পারবেন। গ্লোবালbuild/make/core/proguard.flagsবেসলাইন, কাস্টম.flagsফাইল ছাড়াই@VisibleForTestingআইটেমandroid.**,com.android.**এবংcom.google.android.**প্যাকেজে অটোমেটিক রেখে দেয়। (এইসব নেমস্পেসের বাইরে ভেন্ডর মডিউলের জন্য,trace_references_from,@UsedByReflectionবা এক্সপোর্ট করা লাইব্রেরি নিয়ম ব্যবহার করুন।)trace_references_fromবাtrace_references-এর পরিবর্তে@VisibleForTesting-এর মাধ্যমে হ্যান্ড-অ্যানোটেট করার সময়, Mockitomock(...)বাspy(...)-এ পাস করা ক্লাসও অ্যানোটেট করুন (শুধু স্টাবড পদ্ধতি নয়), কারণ অন-ডিভাইসmockito-target(dexmaker-mockito) রানটাইম সাবক্লাস জেনারেট করে এবং R8 সাবক্লাস করা হয়নি এমন ক্লাসfinal(MockitoException: Can't mock/spy class ... - final class) হিসেবে চিহ্নিত করতে পারে।ওভারল্যাপ করা স্ট্যাটিক লাইব্রেরি (
jarjar_rules) এড়িয়ে চলুন বা আবার প্যাক করুন: যখনandroid_appএবং তারinstrumentation_forটেস্ট APK, উভয়ই স্ট্যাটিক্যালি একই লাইব্রেরি লিঙ্ক করে (সরাসরি, যেমনguava, বা ট্রানজিটিভলি),tracereferencesটেস্টে সংজ্ঞায়িত সেই ক্লাসগুলি দেখে এবং অ্যাপের জন্য কোনও'রাখুন' নিয়ম প্রকাশ করে না এবং রান টাইমে অ্যাপের পেরেন্ট ক্লাসলোডার, টেস্টের কপিকে তার R8-শ্রিঙ্ক করা ক্লাসের সাথে শ্যাডো করে, যার ফলেIllegalAccessErrorবাNoSuchMethodErrorহয়। টেস্টের জন্য নিজস্ব বান্ডেল করা কপির প্রয়োজন না হলে, সংঘর্ষ এড়াতে টেস্টেরstatic_libsথেকে ডুপ্লিকেটটি সরান (অথবাlibs-এর মাধ্যমে লিঙ্ক করুন); অন্যথায়,jarjar_rulesব্যবহার করে মডিউল-নির্দিষ্ট প্রিফিক্সের অধীনে অ্যাপের ওভারল্যাপ করা স্ট্যাটিক লাইব্রেরি প্যাকেজগুলি আবার প্যাকেজ করুন।
ধাপ ৩: মালিকানা থাকা লাইব্রেরি থেকে নিয়ম এক্সপোর্ট করা
শেয়ার করা java_library বা android_library-এর নিজস্ব ইন্টার্নাল রিফ্লেকশন বা JNI কলব্যাকের জন্য নিয়ম রাখার প্রয়োজন হলে, লাইব্রেরি টার্গেটে নিয়মগুলি সংজ্ঞায়িত করুন এবং 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 নিয়মগুলি অ্যানোটেশন রাখার নির্দেশিকা (keepanno Javadoc রেফারেন্স দেখুন) থেকে সোর্স অ্যানোটেশন দিয়ে পরিবর্তন করুন:
@UsesReflection: আপনি রিফ্লেকশন পারফর্ম করা কোড কন্ট্রোল করলে এই অ্যানোটেশন বেছে নিন। কোন টার্গেট ক্লাস, পদ্ধতি বা ফিল্ড ডায়নামিকভাবে অ্যাক্সেস করা হয়েছে তা ঘোষণা করতে, রিফ্লেকশন কল সাইটে এটি রাখুন। কারণ@UsesReflectionঅটোমেটিক একটি পূর্বশর্ত এনকোড করে যে অ্যানোটেট করা কল সাইট নিজেই অ্যাক্সেসযোগ্য, R8 কল সাইট অব্যবহৃত থাকলে কলার এবং রিফ্লেক্টিভ টার্গেট উভয়কেই ছেঁটে ফেলে।@UsedByReflection: ক্লাস, পদ্ধতি, ফিল্ড বা কনস্ট্রাক্টরে রাখুন যা এক্সটার্নাল কোড বা লাইব্রেরি দ্বারা রিফ্লেক্টিভভাবে ইনস্ট্যান্টিয়েট বা ইনভোক করা হয়, যেমনBundleবাSettingsকী থেকেClass.forNameদিয়ে লোড করা ক্লাস বা ডায়নামিক ক্লাসলোডার জুড়ে লোড করা প্লাগ-ইন ক্লাস।kind(যেমনKeepItemKind.CLASS_AND_METHODS),preconditions(@KeepCondition) এবং প্যারামিটার কনস্ট্রেন্ট নির্দিষ্ট করুন যাতে R8 শুধুমাত্র সঠিক রিফ্লেক্টিভ কন্ট্র্যাক্ট রাখে এবং এখনও ক্লাসের অব্যবহৃত মেম্বারদের অপ্টিমাইজ বা ছাঁটাই করতে পারে।JobServiceবাBroadcastReceiver-এর মতো ম্যানিফেস্ট-রেজিস্টার করা কম্পোনেন্টে@UsedByReflectionযোগ করবেন না, কারণ AAPT2-তে এগুলি আগে থেকেই থাকে।@UsedByNative:GetMethodID,GetStaticMethodIDবাGetFieldIDব্যবহার করে C বা C++ JNI কোড থেকে অ্যাক্সেস করা পদ্ধতি বা ফিল্ডে প্লেস করুন।@KeepForApi: লাইব্রেরি API ক্লাস বা মেম্বারদের উপর রাখুন যা ডিস্ট্রিবিউশনের আগে লাইব্রেরি নিজে থেকে সঙ্কুচিত হলে অবশ্যই অক্ষত থাকতে হবে।@Keep(androidx.annotation.Keep):keepannoপ্রযোজ্য না হলে ফলব্যাক হিসেবে ব্যবহার করুন। কোনও ক্লাসে@Keepপ্রয়োগ করলে, ক্লাস এবং এর সব মেম্বারকে শর্তহীনভাবে রেখে দেওয়া হয়। কোনও পদ্ধতি বা ফিল্ডে@Keepপ্রয়োগ করলে তা শর্তহীন এন্ট্রি পয়েন্ট হিসেবে কাজ করে যা মেম্বার ও তার ক্লাসকে ধরে রাখে, এমনকি ক্লাসটি কখনও ইনস্ট্যান্টিয়েট না করা হলেও। অন্যদিকে,keepannoশর্তসাপেক্ষ অ্যাক্সেসযোগ্যতা প্রকাশ করে।
Soong মডিউলে R8 keepanno অ্যানোটেশন ব্যবহার করতে:
Android.bp-এlibs-এর সাথে"keepanno-annotations"যোগ করুন:libs: [ "keepanno-annotations", ],com.android.tools.r8.keepanno.annotations.*ইমপোর্ট করুন এবং Java বা Kotlin সোর্স কোডে ডিক্লারেশন বা কল সাইট অ্যানোটেট করুন:import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.UsedByReflection; public final class CustomPluginController { @UsedByReflection( description = "Instantiated via Class.forName from plugin config", kind = KeepItemKind.CLASS_AND_METHODS) public CustomPluginController(Context context) { // ... } }R8 সরাসরি
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নিয়ম তৈরি করে।
ব্রড XML ক্লিক হ্যান্ডলার রাখার নিয়ম
# Don't do this:
-keepclassmembers class * {
public void *(android.view.View);
}
- কেন এটি পারফর্ম্যান্সের উপর প্রভাব ফেলে: মডিউলের প্রতিটি ক্লাসে প্রতিটি
public void *(View)পদ্ধতি রাখার ফলে R8 এমন কোনও পদ্ধতিকে স্ট্রিপ বা ইনলাইন করতে পারে না যা একটিমাত্রViewপ্যারামিটার গ্রহণ করে। - সাজেস্ট করা সমাধান: নিয়মটি মুছে দিন। AAPT2 লেআউট XML ফাইল স্ক্যান করে এবং
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 লাইব্রেরি সহ) জুড়ে প্রতিটি গেটার এবং সেটার ধরে রাখতে বাধ্য করে, UI কোড জুড়ে ডেড মেথড সরানো এবং ইনলাইনিং ব্লক করে। - সাজেস্ট করা সমাধান: নিয়মটি মুছে দিন। লেআউট XML ফাইল থেকে ইনফ্লেট করা কাস্টম
Viewক্লাসের জন্য AAPT2 আগে থেকেই কনস্ট্রাক্টর প্রিজার্ভ করে। যদি কোডObjectAnimator.ofFloat(view, "translationZ", ...)-এর মতো রিফ্লেক্টিভ স্ট্রিং নাম ব্যবহার করে ভিউ প্রপার্টি অ্যানিমেট করে, তাহলে রিফ্লেকশন সম্পূর্ণভাবে এড়াতে স্ট্রিং নামটি টাইপ করা প্রপার্টি রেফারেন্স (View.TRANSLATION_Zবা কাস্টমFloatPropertyবাIntPropertyইমপ্লিমেন্টেশন) দিয়ে পরিবর্তন করুন। রিফ্লেক্টিভ প্রপার্টি অ্যাক্সেস এড়ানো না গেলে, নির্দিষ্ট গেটার বা সেটার@UsedByReflectionদিয়ে অ্যানোটেট করুন।
ব্ল্যাঙ্কেট অপ্টিমাইজেশন বা অস্পষ্টতা বন্ধ করে দেয়
# 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নিয়ম যোগ করলে, সেই কোডকে অবফাসকেট না করে প্রোডাকশন বিল্ডে রেখে দিতে হয়।trace_references_from(বাallow_traced_references-এর সাথেtrace_references: true) কনফিগার করার সময় অথবা@VisibleForTesting-এর সাথে পদ্ধতি অ্যানোটেট করার সময় ম্যানুয়াল-keepনিয়ম বজায় রাখা এড়িয়ে যায় এবং শুধুমাত্র টেস্ট রেফারেন্স বজায় রাখে, সেইসব চিহ্ন এখনও প্রোডাকশন বাইনারিতে শিপ করা হয়। - সাজেস্ট করা সমাধান:
trace_references_from(অথবাallow_traced_referencesএবংtrace_references: true) চালু করে কাস্টম টেস্ট-keepরুল বাদ দিন অথবা.implলাইব্রেরিতে অ্যাপ স্ট্রাকচার করুন যাstatic_libsব্যবহার করে সেল্ফ-ইনস্ট্রুমেন্টিং টেস্ট APK-তে লিঙ্ক করা থাকে যাতে প্রোডাকশন 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) বা XML (@raw/foo)-এ আগে থেকেই স্ট্যাটিক্যালি রেফারেন্স করা থাকে, তাহলে শ্রিঙ্কার অটোমেটিক সেগুলি রেখে দেয়, তাই আপনিres/raw/keep.xmlমুছে দিতে পারেন।
নিয়মে করা পরিবর্তন যাচাই ও অডিট করা
আপনি যখনই proguard.flags বা keep.xml-এ কিপ রুল সরিয়ে দেন বা ছোট করেন,
তখন যাচাই করুন যে মডিউলটি পরিষ্কারভাবে তৈরি হয়েছে, ইউনিট এবং ইন্সট্রুমেন্টেশন টেস্ট পাস করেছে,
এবং সমস্ত প্রয়োজনীয় এন্ট্রি পয়েন্ট ধরে রেখেছে।
মডিউল তৈরি ও পরীক্ষা করা
R8 এবং AAPT2 কোনও রেফারেন্স মিসিং সংক্রান্ত সতর্কতা ছাড়াই সম্পূর্ণ হয়েছে কিনা তা যাচাই করতে মডিউলটি পরিষ্কারভাবে তৈরি করুন:
m <MODULE_NAME>atestব্যবহার করে মডিউলের জন্য ইউনিট ও ইনস্ট্রুমেন্টেশন টেস্ট রান করুন:atest <TEST_MODULE_NAME>সিস্টেম অ্যাপ, বিশেষাধিকারপ্রাপ্ত পরিষেবা বা হার্ডওয়্যার-নির্ভর মডিউলের জন্য, রানটাইম রিফ্লেকশন পাথ, IPC বাইন্ডিং ও রিসোর্স ইনফ্লেশন অনুশীলন করতে টার্গেট ফিজিক্যাল ডিভাইসে বা আপনার ডিভাইস টেস্ট ল্যাবে ইনস্ট্রুমেন্টেশন ও UI টেস্ট চালান।
DEX ও রিসোর্স ডিফারেন্স ভালোভাবে দেখুন
নিয়ম পরিবর্তনের আগে ও পরে কম্পাইল করা 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
classes.jar-এ সরাসরিprebuilts/r8/r8.jarচালানোর সময়, মডিউলের--libক্লাসপাথ JAR (android.jar,framework.jarএবং শেয়ার করাlibs) এবং AAPT2-এর জেনারেট করাproguard.optionsনিয়মAndroidManifest.xmlএবং লেআউট XML থেকে পাস করুন। এইসব ইনপুট ছাড়া, R8 ফ্রেমওয়ার্ক সুপারটাইপ (Activity,Service,Phone,Handler) এবং আন্ডার-রিটেন হায়ারার্কি পদ্ধতি সমাধান করতে পারে না।
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-এ বান্ডেল করা) ব্যবহার করে একটি ইন্ট্যার্যাক্টিভ HTML রিপোর্টে কনভার্ট করুন:# 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ফাইল চেক করে, প্রতিটি মডিউলের জন্য HTML রিপোর্ট তৈরি করে এবংout/keep_radius_reports/keepradius.htmlতৈরি করে যা লাইভ আইটেমের সংখ্যা, রাখা আইটেমের সংখ্যা এবং বিল্ড জুড়ে সর্বোচ্চ-ব্যাসার্ধের রাখার নিয়ম সংক্ষিপ্ত করে। তৈরি করা রিপোর্টে সঙ্কোচন, অপ্টিমাইজেশন ও অস্পষ্টকরণ স্কোর ব্যাখ্যা করার ব্যাপারে আরও তথ্যের জন্য, R8 কনফিগারেশন অ্যানালাইজার ব্যবহার করুন দেখুন।
এছাড়াও, Soong build/soong/java/dex.go-এ অতিরিক্ত R8 ডায়াগনস্টিক ও ইনার-লুপ এনভায়রনমেন্ট ভেরিয়েবল
সাপোর্ট করে:
R8_DUMP_INPUT=true: মডিউলের ইন্টারমিডিয়েট ডিরেক্টরিতেr8inputs.zipলেখে, যেখানে সব ইনপুট JAR, লাইব্রেরি JAR এবং স্ট্যান্ডঅ্যালোন R8 রিপ্রোডাকশনের জন্য মার্জ করা ProGuard কনফিগারেশন থাকে।R8_DUMP_PERFETTO_TRACE=true: Perfetto-তে R8 কম্পাইলেশন পাস পরীক্ষা করার জন্য মডিউলের ইন্টারমিডিয়েট ডিরেক্টরিতেr8trace.ptraceলেখে।SOONG_SKIP_TRACE_REFERENCES=true: টেস্ট কোড ইটারেট করার সময় লোকাল ইনার-লুপ বিল্ডের স্পিড বাড়াতেtrace_references_fromবাtrace_references-এর মাধ্যমে কনফিগার করাtracereferencesনিয়ম রান করা এড়িয়ে যায়।
লাইব্রেরি গ্রাহক নিয়ম যাচাই করুন
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
দ্রুত সোর্স-ট্রি ট্রায়াজের জন্য প্ল্যাটফর্ম ও OEM টিম pgaudit.py,
এক্সপোর্ট করা লাইব্রেরি নিয়ম যাচাই করার জন্য process-keep-rules এবং
বিল্ডের প্রতিটি নিয়মের সঠিক ক্লাস, ফিল্ড ও পদ্ধতি ধরে রাখার রেডিয়াস পরিমাপ করার জন্য KeepRadiusHtmlReportGenerator-এর সাথে R8_DUMP_KEEP_RADIUS=true
একত্রিত করতে পারে।