از لحاظ تاریخی، اندروید تنها از اندازه صفحات حافظه 4 کیلوبایتی پشتیبانی میکند که عملکرد حافظه سیستم را برای میانگین کل حافظهای که دستگاههای اندرویدی معمولا دارند بهینه میکند. با شروع Android 15، AOSP از دستگاه هایی پشتیبانی می کند که برای استفاده از اندازه صفحه 16 کیلوبایت (دستگاه های 16 کیلوبایت) پیکربندی شده اند. اگر برنامه شما از کتابخانه های NDK استفاده می کند، چه به طور مستقیم یا غیرمستقیم از طریق یک SDK، باید برنامه خود را بازسازی کنید تا بتواند روی این دستگاه های 16 کیلوبایتی کار کند.
از آنجایی که سازندگان دستگاهها به ساخت دستگاههایی با حافظه فیزیکی (RAM) بیشتر ادامه میدهند، بسیاری از این دستگاهها از اندازه صفحه ۱۶ کیلوبایت (و در نهایت بیشتر) برای بهینهسازی عملکرد دستگاه استفاده میکنند. افزودن پشتیبانی برای دستگاههای اندازه صفحه 16 کیلوبایت، برنامه شما را قادر میسازد تا در این دستگاهها اجرا شود و به برنامه شما کمک میکند از بهبودهای عملکرد مرتبط بهره مند شود. بدون کامپایل مجدد، برنامه ها در نسخه های بعدی اندروید روی دستگاه های 16 کیلوبایتی کار نخواهند کرد.
برای کمک به اضافه کردن پشتیبانی از برنامه خود، راهنمایی هایی در مورد نحوه بررسی اینکه آیا برنامه شما تحت تأثیر قرار گرفته است ، نحوه بازسازی برنامه خود (در صورت وجود) و نحوه آزمایش برنامه خود در یک محیط 16 کیلوبایتی با استفاده از شبیه سازها (از جمله تصاویر سیستم Android 15 برای شبیه ساز Android) را ارائه کرده ایم.
الزامات سازگاری Google Play
برای اطمینان از اینکه برنامهتان بهدرستی با جدیدترین نسخه Android کار میکند، همه برنامههایی که Android 15 (سطح API ۳۵) و بالاتر را هدفیابی میکنند باید از اندازههای صفحه حافظه ۱۶ کیلوبایتی در دستگاههای ۶۴ بیتی در Google Play پشتیبانی کنند. از ۱ فوریه ۲۰۲۷، اگر بهروزرسانیهای برنامهتان از اندازههای صفحه حافظه ۱۶ کیلوبایتی پشتیبانی نکند، نمیتوانید این بهروزرسانیها را منتشر کنید.
مزایا و بهبود عملکرد
دستگاه هایی که با اندازه صفحه 16 کیلوبایت پیکربندی شده اند به طور متوسط کمی از حافظه بیشتری استفاده می کنند، اما بهبودهای عملکردی مختلفی را برای سیستم و برنامه ها نیز به دست می آورند:
- زمانهای راهاندازی برنامه کمتر زمانی که سیستم تحت فشار حافظه است: به طور متوسط 3.16٪ کمتر، با بهبودهای قابل توجه (تا 30٪) برای برخی از برنامههایی که آزمایش کردیم.
- کاهش مصرف انرژی در حین راه اندازی برنامه: به طور متوسط 4.56٪ کاهش
- راهاندازی سریعتر دوربین: به طور متوسط 4.48٪ سریعتر استارتهای گرم و 6.60٪ سریعتر شروع سرد.
- بهبود زمان بوت سیستم: به طور متوسط 8٪ (تقریباً 950 میلی ثانیه) بهبود یافته است.
این پیشرفتها بر اساس آزمایش اولیه ما هستند و نتایج روی دستگاههای واقعی احتمالاً متفاوت خواهد بود. در ادامه آزمایش خود، تجزیه و تحلیل بیشتری از دستاوردهای بالقوه برای برنامه ها ارائه خواهیم کرد.
بررسی کنید آیا برنامهتان تحتتأثیر قرار گرفته است یا نه
اگر برنامه شما از هر کد بومی استفاده می کند ، باید برنامه خود را با پشتیبانی از دستگاه های 16 کیلوبایتی بازسازی کنید . اگر مطمئن نیستید که برنامه شما از کد بومی استفاده میکند، میتوانید از APK Analyzer برای شناسایی وجود کد بومی استفاده کنید و سپس تراز بخشهای ELF را برای کتابخانههای مشترکی که پیدا کردید بررسی کنید . Android Studio همچنین ویژگی هایی را ارائه می دهد که به شما کمک می کند تا به طور خودکار مشکلات تراز را تشخیص دهید .
اگر برنامه شما فقط از کدهای نوشته شده به زبان برنامه نویسی جاوا یا کاتلین استفاده می کند که شامل همه کتابخانه ها یا SDK می شود، برنامه شما از قبل از دستگاه های 16 کیلوبایتی پشتیبانی می کند. با این وجود، توصیه می کنیم برنامه خود را در یک محیط 16 کیلوبایتی آزمایش کنید تا مطمئن شوید که هیچ رگرسیون غیرمنتظره ای در رفتار برنامه وجود ندارد.
آیا برنامهتان از کد بومی استفاده میکند؟
اگر هریک از موارد زیر صدق کند، برنامهتان از کد بومی استفاده میکند:
- برنامه شما از هرگونه کد C/C++ (بومی) استفاده میکند. اگر برنامهتان از Android NDK استفاده میکند، برنامهتان از کد بومی استفاده میکند.
- برنامه شما با کتابخانهها یا وابستگیهای بومی شخص ثالث (مانند کیتهای توسعه نرمافزار) که از آنها استفاده میکنند پیوند دارد.
- برنامه شما توسط یک سازنده برنامه طرف سوم ساخته شده است که از کتابخانههای بومی در دستگاه استفاده میکند.
شناسایی کتابخانههای بومی بااستفاده از «تحلیلکننده APK»
تحلیلکننده APK ابزاری است که به شما امکان میدهد جنبههای مختلف APK ساختهشده را ارزیابی کنید. برای بررسی اینکه آیا برنامهتان از کد بومی استفاده میکند (صرفنظر از اینکه با ۱۶ کیلوبایت سازگار باشد یا نه):
- استودیو Android را باز کنید، سپس روی فایل > باز کردن کلیک کنید و پروژهای را انتخاب کنید.
از نوار منو، روی Build > Analyze APK... (ساختن > تجزیهوتحلیل APK…) کلیک کنید
APK موردنظرتان را برای تجزیهوتحلیل انتخاب کنید.
در پوشه
libکه میزبان فایلهای شیء همرسانیشده (.so) است، درصورت وجود، جستجو کنید. اگر فایلهای شیء همرسانیشدهای وجود داشته باشد، برنامهتان از کد بومی استفاده میکند. ستون تراز پیامهای هشدار را برای هر فایلی که مشکل تراز دارد نمایش میدهد. اگر هیچ فایل شیء همرسانیشدهای وجود ندارد یا پوشهlibوجود ندارد، برنامهتان از کد بومی استفاده نمیکند.
تشخیص مشکلات همترازی با بررسیهای خودکار
اگر کتابخانهها یا فایلهای APK ازپیشساختهشده شما با ۱۶ کیلوبایت سازگار نباشند، Android Studio بهطور پیشگیرانه به شما هشدار میدهد. از ابزار تحلیلکننده APK برای بررسی اینکه کدام کتابخانهها باید بهروز شوند یا اینکه آیا تغییرات کد لازم است یا نه استفاده کنید.
Lint در «استودیو Android» نیز کتابخانههای بومی را که با ۱۶ کیلوبایت تراز نیستند برجسته میکند.
بررسی تراز بخشهای ELF برای کتابخانههای مشترک
برای هر کتابخانه مشترک، بررسی کنید که بخشهای ELF کتابخانههای مشترک بهدرستی بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی ترازبندی شده باشند.
استفاده از «تحلیلکننده APK» (توصیهشده)
سادهترین راه برای تأیید همترازی کتابخانههای مشترک شما استفاده از APK Analyzer در Android Studio است. اگر فایل شیء همرسانیشدهای با ۱۶ کیلوبایت ترازبندی نشده باشد، ستون ترازبندی پیام هشدار نمایش خواهد داد.
از اسکریپت check_elf_alignment.sh (Linux یا macOS) استفاده کنید
اگر در Linux یا macOS توسعه میدهید و ترجیح میدهید از اسکریپت استفاده کنید،
میتوانید از اسکریپت check_elf_alignment.sh استفاده کنید:
دستورات
check_elf_alignment.shرا در فایلی ذخیره کنید.اسکریپت را روی فایل APK برنامهتان اجرا کنید:
check_elf_alignment.sh APK_NAME.apkاین اسکریپت برای همه کتابخانههای مشترک
arm64-v8a،ALIGNEDیاUNALIGNEDرا برمیگرداند.اگر کتابخانههای مشترک
arm64-v8aیاx86_64UNALIGNEDهستند، باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش، دوباره آن را آزمایش کنید.
استفاده مستقیم از ابزارهای خط فرمان
برای بررسی تراز بخشهای ELF بااستفاده مستقیم از ابزارهای خط فرمان، این مراحل را دنبال کنید:
- مطمئن شوید که هم Android SDK Build-Tools نسخه ۳۵.۰.۰ یا بالاتر و هم
Android NDK بااستفاده از مدیر SDK در Android Studio یا
ابزار خط فرمان
sdkmanagerنصب شده باشند. فایل APK برنامهتان را استخراج کنید:
Linux یا macOS
unzip APK_NAME.apk -d /tmp/my_apk_outWindows (PowerShell)
Expand-Archive -Path .\APK_NAME.apk -DestinationPath ~\tmp\my_apk_outدر فهرست راهنمای موقتی که فایل APK را در آن از حالت فشرده خارج کردید، محتویات فهرست راهنمای
libرا برای فایلهای شیء همرسانیشده (.so) بررسی کنید. اینها همان فایلهای شیء مشترکی هستند که هنگام شناسایی کتابخانههای بومی بااستفاده از «تحلیلکننده APK» دیدهاید. فرمان زیر را در هر فایل شیء همرسانیشده اجرا کنید:Linux یا macOS
SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objdump -p SHARED_OBJECT_FILE.so | grep LOADWindows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-objdump.exe -p SHARED_OBJECT_FILE.so | Select-String -Pattern "LOAD"که در آن
SDK_ROOT_LOCATIONمسیر دایرکتوریای است که کیت توسعه نرمافزار Android را در آن نصب کردهاید،SHARED_OBJECT_FILEنام فایل شیء همرسانیشدهای است که بررسی میکنید، وNDK_VERSIONنسخه کیت توسعه نرمافزار Android NDK است که نصب کردهاید (برای مثال،28.0.12433566). خروجی برای هر فایلی که بررسی میکنید چیزی شبیه به این خواهد بود:LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**14 LOAD off 0x0000000000042a90 vaddr 0x0000000000043a90 paddr 0x0000000000043a90 align 2**14 LOAD off 0x0000000000046230 vaddr 0x0000000000048230 paddr 0x0000000000048230 align 2**14خطوط خروجی را بررسی کنید تا مطمئن شوید بخشهای بارگذاری مقادیری کمتر از
2**14ندارند. اگر هرکدام از بخشهای بارگذاری2**13،2**12، یا مقادیر پایینتر باشد، باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش دوباره آزمایش کنید.سپس، ابزار خط فرمان
zipalignرا در فایل APK برنامهتان اجرا کنید:Linux یا macOS
SDK_ROOT_LOCATION/Android/sdk/build-tools/35.0.0/zipalign -v -c -P 16 4 APK_NAME.apkWindows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\build-tools\35.0.0\zipalign.exe -v -c -P 16 4 APK_NAME.apkکه
SDK_ROOT_LOCATIONمسیر دایرکتوریای است که کیت توسعه نرمافزار Android را در آن نصب کردهاید، وAPK_NAMEنام فایل APK برنامهتان است. اگر همه کتابخانههای مشترک بهدرستی تراز شده باشند، خط آخر خروجی عبارت «درستیسنجی موفقیتآمیز بود» را نشان میدهد.اگر درستیسنجی ناموفق بود، برخیاز کتابخانههای مشترک باید دوباره تراز شوند، بنابراین باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش دوباره آزمایش کنید.
بررسی پرچم امنیتی RELRO
برای کاهش سوءاستفادههای امنیتی، پیونددهندههای مدرن از پرچم
Relocation Read-Only (RELRO) استفاده میکنند تا بخشهای هدف جابهجایی (مانند .got و .data.rel.ro) فایل شیء مشترک را
پساز تکمیل جابهجاییهای پویا فقط خواندنی کنند.
پرچم RELRO را در ساخت خود فعال کنید.
وقتی GNU_RELRO بخش قابلنوشتن LOAD را با دادههای قابلنوشتن بعدی
(مثل .data یا .bss) همرسانی میکند، نشانی پایانی بخش GNU_RELRO
(VirtAddr + MemSiz) باید با ۱۶ کیلوبایت تراز شود (0x4000). درغیراینصورت، وقتی
پیونددهنده Android صفحه ۱۶ کیلوبایتی حاوی انتهای
GNU_RELRO را بهعنوان فقطخواندنی علامتگذاری میکند، هر داده قابلنوشتن مجاور که در باقیمانده
همان صفحه ۱۶ کیلوبایتی قرار دارد نیز فقطخواندنی میشود و هنگام نوشتن آن داده، برنامه در زمان اجرا
با خطای بخشبندی (SIGSEGV) ازکار میافتد.
این اتفاق معمولاً زمانی میافتد که فایل .so با زنجیره ابزار NDK نسخه r27 و
پایینتر بدون فعال کردن پرچمهای مربوطه ساخته شده باشد.
استفاده از «تحلیلکننده APK» (توصیهشده)
میتوانید از تحلیلکننده APK در Android Studio برای بررسی مستقیم وضعیت تراز RELRO فایلهای شیء مشترک استفاده کنید.
استفاده از ابزارهای خط فرمان
اگر ترجیح میدهید تراز را بهصورت دستی بررسی کنید یا نیاز به خودکارسازی فرایند دارید، این مراحل را دنبال کنید:
مرحله ۱: بازرسی سرصفحههای برنامه
فرمان زیر را در هر فایل شیء همرسانیشده اجرا کنید (در Linux،
darwin-x86_64 را با linux-x86_64 جایگزین کنید):
Linux یا macOS
SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readelf -Wl SHARED_OBJECT_FILE.so | grep 'LOAD\|RELRO\|Type'
Windows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-readelf.exe -Wl SHARED_OBJECT_FILE.so | Select-String -Pattern 'LOAD|RELRO|Type'
اگر بخش RELRO وجود داشته باشد، رشته GNU_RELRO چاپ میشود.
مرحله ۲: درستیسنجی کردن مطابقت با اندازه صفحه ۱۶ کیلوبایتی برای RELRO
یک فایل شیء همرسانیشده ازنظر RELRO با اندازه صفحه ۱۶ کیلوبایتی سازگار است اگر هریک از شرایط زیر برآورده شود:
- بخش
GNU_RELROدر سرصفحههای برنامه وجود ندارد. - نشانی پایانی
GNU_RELROبا ۱۶ کیلوبایت همتراز است: مجموع نشانی مجازی (VirtAddr) و اندازه حافظه (MemSiz) تقسیم بر ۱۶ کیلوبایت (0x4000) باقیمانده (پیمانه) صفر دارد:(VirtAddr + MemSiz) % 0x4000 == 0. - هیچ داده قابلنوشتنی بهدنبال
GNU_RELROدر همان بخشLOADوجود ندارد:GNU_RELROکل باقیمانده بخشLOADحاوی خود را اشغال میکند (یعنیLOAD.VirtAddr + LOAD.MemSiz == RELRO.VirtAddr + RELRO.MemSiz)، بنابراین هیچ بخش قابلنوشتن.dataیا.bssدر صفحه انتهایی مشترک نیست.
مثالها
مثالهای زیر نحوه ارزیابی برونداد llvm-readelf را برای پیکربندیهای مختلف
GNU_RELRO نشان میدهد.
مثال ۱: فایل .so غیرهمراستا (ناسازگار)
در این مثال، GNU_RELRO بخش RW LOAD را با دادههای قابلنوشتن بعدی همرسانی میکند و نشانی پایانی آن مضربی از 0x4000 نیست:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0cfaf0 0x0cfaf0 R E 0x4000
LOAD 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x02510 0x04510 RW 0x4000
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x01510 R 0x1
- فرمول:
(VirtAddr + MemSiz) % 0x4000 == 0 - نتیجه:
(0xdfaf0 + 0x01510) % 0x4000 = 0xE1000 % 0x4000 == 0x1000
چون 0x1000 صفر نیست و بخش LOAD حاوی آن بعداز
0xE1000 ادامه مییابد (در 0xdfaf0 + 0x04510 = 0xE4000 پایان مییابد)، این فایل .so
با ۱۶ کیلوبایت سازگار نیست. در دستگاه ۱۶ کیلوبایتی، پیونددهنده محدوده محافظت RELRO را به مرزهای صفحه ۱۶ کیلوبایتی گرد میکند و 0xDC000 (جداساز صفحه قبلی) تا 0xE4000 را بهعنوان فقط خواندنی علامتگذاری میکند. بااینحال، بخشهای قابلنوشتن .data و .bss فایل .so در زیرمحدوده 0xE1000 تا 0xE4000 قرار دارند که منجر به خطای بخشبندی هنگام اصلاح در زمان اجرا میشود. این فایل .so را همانطور که در بخش کامپایل کردن برنامه بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی توضیح داده شده است بازسازی کنید.
مثال ۲: فایل .so تراز با بخش RELRO (مطابق)
در این مثال، انتهای بخش GNU_RELRO روی مرز صفحه ۱۶ کیلوبایتی قرار میگیرد:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0cfaf0 0x0cfaf0 R E 0x4000
LOAD 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x03510 RW 0x4000
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x00510 0x00510 R 0x1
- فرمول:
(VirtAddr + MemSiz) % 0x4000 == 0 - نتیجه:
(0xdfaf0 + 0x00510) % 0x4000 = 0xE0000 % 0x4000 == 0
چون باقیمانده 0 است، محافظت RELRO بهطور کامل در مرز صفحه 0xE0000 بهپایان میرسد و دادههای قابلنوشتن که از 0xE0000 شروع میشوند تحتتأثیر قرار نمیگیرند.
مثال ۳: فایل .so بدون بخش RELRO (مطابق)
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000680 0x000680 R E 0x4000
LOAD 0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x0001d8 RW 0x4000
این فایل .so بخش GNU_RELRO ندارد، بنابراین مشکلات مرز صفحه RELRO اعمال نمیشود (هرچند فعال کردن RELRO همچنان برای امنیت توصیه میشود).
مثال ۴: GNU_RELRO در بخش LOAD خودش (مطابق با خطمشی)
در این مثال، GNU_RELRO در مرز ۱۶ کیلوبایتی بهپایان نمیرسد، اما همچنان سازگار است زیرا هیچ داده قابلنوشتنی در همان بخش LOAD بهدنبال آن نمیآید:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000680 0x000680 R E 0x4000
LOAD 0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 RW 0x4000
GNU_RELRO 0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 R 0x1
- فرمول:
(VirtAddr + MemSiz) % 0x4000 == 0 - نتیجه:
(0x4680 + 0x0980) % 0x4000 = 0x5000 % 0x4000 == 0x1000
هرچند 0x1000 صفر نیست، این فایل .so همچنان با اندازه صفحه ۱۶ کیلوبایتی سازگار است.
مقایسه GNU_RELRO با بخش LOAD حاوی آن (ورودی دوم LOAD) نشان میدهد که هر دو در VirtAddr 0x4680 شروع میشوند و در نشانی دقیقاً یکسانی (0x4680 + 0x0980 = 0x5000) پایان مییابند.
چون کل بخش LOAD فقط حاوی دادههای RELRO است، هیچ داده .data یا .bss قابلنوشتنی در زیرمحدوده 0x5000 تا 0x8000 وجود ندارد (یا کتابخانه داده قابلنوشتن غیر RELRO ندارد، یا هر بخش LOAD قابلنوشتن بعدی در مرز صفحه ۱۶ کیلوبایتی جداگانهای در 0x8000 یا فراتر از آن شروع میشود). محافظت فقط خواندنی پیونددهنده با هیچ داده قابلنوشتنی همپوشانی نخواهد داشت،
بنابراین هیچ خطای بخشبندی رخ نمیدهد.
برنامهتان را با پشتیبانی از دستگاههای ۱۶ کیلوبایتی بسازید
اگر برنامهتان از کد بومی استفاده میکند، مراحل شرحدادهشده در بخشهای زیر را تکمیل کنید تا مطمئن شوید برنامهتان از دستگاههای ۱۶ کیلوبایتی پشتیبانی میکند:
- بهروزرسانی بستهبندی کتابخانههای مشترک
- کامپایل کردن برنامه بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی
- رفع اشکال کد و حل مشکلات زمان اجرا
- بهینهسازی تخصیصدهندههای حافظه سفارشی (درصورت وجود)
- بررسی کیتهای توسعه نرمافزار برای پشتیبانی از ۱۶ کیلوبایت
بستهبندی کتابخانههای مشترک را بهروز کنید
به AGP نسخه ۸.۵.۱ یا بالاتر ارتقا دهید و از کتابخانههای مشترک فشردهنشده استفاده کنید.
از bundletool برای بررسی تراز بودن زیپ استفاده کنید
برای دیدن تراز بسته، از این مورد استفاده کنید:
bundletool dump config --bundle=<my .aab> | grep alignment
اگر PAGE_ALIGNMENT_16K را میبینید، یعنی دسته شما درخواست ترازبندی zip ۱۶ کیلوبایتی دارد. اگر PAGE_ALIGNMENT_4K را میبینید، این دستورالعمل APK ساختهشده از
این AAB است تا فایلهای .so تراز ۴ کیلوبایتی در فایل zip داشته باشد.
AGP نسخه ۸.۵.۱ یا بالاتر
دستگاههای ۱۶ کیلوبایتی به برنامههایی نیاز دارند که با کتابخانههای مشترک فشردهنشده عرضه میشوند تا آنها را در مرز تراز zip ۱۶ کیلوبایتی تراز کنند. برای انجام این کار، باید به «افزایه Android Gradle» (AGP) نسخه ۸.۵.۱ یا بالاتر ارتقا دهید. برای جزئیات مربوط به فرایند ارتقا، به بخش دستیار ارتقای افزایه Android Gradle مراجعه کنید.
AGP نسخه ۸.۵ یا پایینتر
اگر نمیتوانید AGP را به نسخه ۸.۵.۱ یا بالاتر ارتقا دهید، راه جایگزین این است که به استفاده از کتابخانههای مشترک فشردهشده تغییر دهید. پیکربندی Gradle را بهروز کنید تا Gradle هنگام بستهبندی برنامه، کتابخانههای مشترک را فشرده کند و از بروز مشکلات نصب برنامه با کتابخانههای مشترک ترازنشده جلوگیری شود.
شیک
در فایل build.gradle، گزینه زیر را اضافه کنید:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
کاتلین
در فایل build.gradle.kts، گزینه زیر را اضافه کنید:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
AGP نسخه ۸.۰ یا پایینتر
اگر از AGP نسخه ۸.۰ یا پایینتر استفاده میکنید، باید گزینه کتابخانه بومی فشردهنشده را برای «دستههای برنامه» در فایل gradle.properties غیرفعال کنید:
android.bundle.enableUncompressedNativeLibs=false
برنامهتان را بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی همگردانی کنید
دستگاههای ۱۶ کیلوبایتی برای اجرای برنامهتان نیاز دارند که بخشهای ELF کتابخانههای مشترک بهدرستی بااستفاده از تراز ELF ۱۶ کیلوبایتی تراز شوند.
برای توسعهدهندگان بازی، اگر بازی شما روی موتور بازی Unity اجرا میشود، به راهنمای Unity مراجعه کنید. اگر بازیتان روی موتور بازی Unreal اجرا میشود، به راهنمای Unreal مراجعه کنید. برای موتورهای بازی بومی، این راهنما را ادامه دهید.
برای همگردانی برنامهتان بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی، مراحل یکی از بخشهای زیر را بسته به نسخه Android NDK که استفاده میکنید تکمیل کنید.
Android NDK r28 و بالاتر
NDK نسخه r28 و بالاتر بهطور پیشفرض با ترازبندی ۱۶ کیلوبایتی کامپایل میکنند.
Android NDK r27 و نسخههای پایینتر
برای پشتیبانی از همگردانی کتابخانههای مشترک تراز ۱۶ کیلوبایتی با Android NDK نسخه r27 یا پایینتر، از پرچمهای پیونددهنده زیر استفاده کنید:
-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384
در اینجا نحوه بهروزرسانی فایلهای پیکربندی سیستم ساخت آورده شده است:
ndk-build
اگر از ndk-build استفاده میکنید، Android.mk را بهروز کنید تا تراز ELF ۱۶ کیلوبایتی فعال شود:
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
CMake
اگر از CMake استفاده میکنید، CMakeLists.txt را بهروز کنید تا تراز ELF ۱۶ کیلوبایتی فعال شود:
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,-z,max-page-size=16384"
"-Wl,-z,common-page-size=16384"
)
رفع مشکلات کد و حل مسائل زمان اجرا
حتی اگر برنامهتان با ۱۶ کیلوبایت ترازبندی شده باشد، اگر در جاهایی از کدتان فرض شده باشد که دستگاه از اندازه صفحه خاصی استفاده میکند، ممکن است برنامهتان با خطا مواجه شود. برای جلوگیری از این اتفاق، مراحل زیر را تکمیل کنید:
هرگونه وابستگی کدنویسیشدهای را که به ثابت
PAGE_SIZEارجاع میدهد یا نمونههایی را در منطق کدتان که فرض میکنند اندازه صفحه دستگاه ۴ کیلوبایت (4096) است بردارید.درعوض از
getpagesize()یاsysconf(_SC_PAGESIZE)استفاده کنید.بهدنبال موارد استفاده از
mmap()و دیگر میاناهای برنامهسازی کاربردی که به آرگومانهای همتراز با صفحه نیاز دارند بگردید و درصورت لزوم آنها را با گزینههای جایگزین عوض کنید.
در برخی موارد، اگر برنامهتان از PAGE_SIZE بهعنوان مقدار مناسبی استفاده میکند که به اندازه صفحه زیرین گره نخورده است، این امر باعث ازکار افتادن برنامهتان هنگام استفاده در حالت ۱۶ کیلوبایت نخواهد شد. اما اگر این مقدار با mmap بدون MAP_FIXED به هسته ارسال شود، هسته همچنان از کل صفحه استفاده میکند که باعث هدر رفتن مقداری حافظه میشود. به این دلایل، وقتی حالت ۱۶ کیلوبایتی در NDK r27 و بالاتر فعال باشد، PAGE_SIZE تعریفنشده است.
اگر برنامهتان از PAGE_SIZE به این روش استفاده میکند و هرگز این مقدار را مستقیماً به هسته منتقل نمیکند، بهجای استفاده از PAGE_SIZE، متغیر جدیدی با نام جدید ایجاد کنید تا نشان دهد که برای اهداف دیگری استفاده میشود و صفحه حافظه واقعی را نشان نمیدهد.
بهینهسازی تخصیصدهندههای حافظه سفارشی
در سیستمهای ۱۶ کیلوبایتی، کوچکترین واحد حافظه فیزیکی که سیستمعامل اختصاص میدهد چهار برابر بزرگتر از سیستمهای ۴ کیلوبایتی است. اگر تخصیصدهنده سفارشی براساس فرض ۴ کیلوبایت طراحی شده باشد، میتواند اشیای کوچک را در چندین صفحه ۱۶ کیلوبایتی پراکنده کند و حافظه خالی را بهطور غیرضروری حفظ کند. این کار میتواند استفاده از حافظه فیزیکی (RSS) را بهطور قابلتوجهی افزایش دهد و کارایی فضای مبادله فشردهشده (ZRAM) را کاهش دهد.
اگر کدتان استخرهای حافظه خودش را مدیریت میکند، این توصیهها را دنبال کنید:
۱. از آستانههای بایت کدگذاریشده برای آزاد کردن حافظه اجتناب کنید
بسیاریاز تخصیصدهندهها از محدودیتهای بایت ثابت برای تصمیمگیری درباره زمان بازگرداندن حافظه به سیستمعامل بااستفاده از madvise(MADV_DONTNEED) استفاده میکنند (برای مثال، فقط درصورتی حافظه را آزاد کن که اشیای فعال کمتر از ۸ کیلوبایت را اشغال کنند).
در سیستم ۱۶ کیلوبایتی، حتی یک شیء فعال ۱۶ بایتی کل صفحه ۱۶ کیلوبایتی را (که بزرگتر از ۸ کیلوبایت است) پین میکند. درنتیجه، آستانه انتشار هرگز برآورده نمیشود و تخصیصدهنده هرگز حافظه استفادهنشده اطراف را به هسته برنمیگرداند.
چه باید کرد: هرگز از ثابتهای بایت کدگذاریشده برای اکتشافات انتشار صفحه استفاده نکنید.
آستانههای انتشار مقیاس را بهطور پویا در زمان اجرا براساس اندازه واقعی صفحه
بااستفاده از sysconf(_SC_PAGESIZE) تغییر دهید.
۲. ابتدا صفحههایی که قبلاً استفاده شدهاند پر شوند (تخصیص ابتدا-متراکم)
اگر تخصیصدهنده حافظه را بهترتیب خروج بهترتیب ورود (FIFO) یا نوبتی توزیع کند، تخصیصهای جدید در بسیاری از صفحههای ۱۶ کیلوبایتی که تاحدی پر شدهاند پراکنده میشوند. یک شیء در صفحه باعث میشود کل ۱۶ کیلوبایت در RAM فیزیکی باقی بماند.
چه باید کرد: همیشه اشیای جدید را از پرترین (متراکمترین) صفحه یا اسلب اختصاص دهید و سپس به صفحههای خالی یا کماستفاده بروید. متمرکز کردن تخصیصهای جدید روی صفحههایی که ازقبل کثیف شدهاند باعث میشود صفحههایی که بهندرت استفاده شدهاند بهطور طبیعی به صفر شیء فعال کاهش یابند، بنابراین کل صفحه ۱۶ کیلوبایتی میتواند به سیستمعامل واگذار شود.
۳. تراز کردن استخرهای حافظه با ۱۶ کیلوبایت و حفظ اندازه استخرها در حد متوسط
محدودههای چندصفحهای که برای سیستمهای ۴ کیلوبایتی طراحی شدهاند میتوانند فضای خالی حافظه آزادنشده بیشازحدی را در هستههای ۱۶ کیلوبایتی نگه دارند. علاوهبراین، کلاسهای اندازهای که بهطور مساوی به ۱۶ کیلوبایت تقسیم نمیشوند، باعث تکهتکه شدن در انتهای هر صفحه میشوند.
کاری که باید انجام داد:
- مطمئن شوید که همه استخرهای حافظه، مرزهای اسلب، و ترازهای میانگیر مضربهای دقیقی از اندازه صفحه زمان اجرا باشند.
- اندازههای گستره چندصفحهای را برای کلاسهای شیء کوچک دوباره ارزیابی کنید تا از اختصاص دادن قطعههای بسیار بزرگ که حافظه غیرفعال را به تله میاندازند جلوگیری شود.
۴. حافظه فیزیکی را برای میانگیرهای بزرگ ذخیرهشده در حافظه نهان فوراً آزاد میکند
تخصیصدهندههای سفارشی اغلب میانگیرهای بزرگ (بیشتر از ۶۴ کیلوبایت) را در یک استخر درونحافظهای ذخیره میکنند تا بتوانند بدون پرداخت هزینه سربار فراخوانیهای سیستم mmap یا munmap دوباره از آنها استفاده کنند. اما نگه داشتن این میانگیرهای کثیف در حافظه، مگابایتها از RAM فیزیکی را درحین انتظار برای زمانسنج تخلیه هدر میدهد.
چه باید کرد: محدوده نشانی حافظه مجازی را برای استفاده مجدد سریع رزرو نگه دارید،
اما هنگام برگرداندن میانگیر به حافظه نهان،
بلافاصله madvise(..., MADV_DONTNEED) یا madvise(..., MADV_FREE) را فراخوانی کنید. سیستمعامل بلافاصله RAM فیزیکی را پس میگیرد، درحالیکه برنامه شما همچنان میتواند فوراً از نشانی مجازی بدون تخصیص مجدد استفاده کند.
۵. صفر کردن حافظه هنگام آزاد شدن بهجای هنگام اختصاص دادن برای فشردهسازی ZRAM
Android از حافظه مبادله فشرده (ZRAM) برای نگه داشتن برنامههای پسزمینه در حافظه استفاده میکند. در دستگاههای ۱۶ کیلوبایتی، اگر صفحهای حتی یک شیء فعال داشته باشد، کل صفحه ۱۶ کیلوبایتی مقیم میماند یا به ZRAM منتقل میشود. دادههای زباله باقیمانده (مانند اشارهگرها و رشتههای کهنه) در بخشهایی از آن صفحه که قبلاً آزاد شدهاند بهخوبی فشرده نمیشوند.
اگر تخصیصدهنده شما حافظه را صفر میکند (مثلاً برای امنیت یا تخصیصهای
صفرشده)، بهجای صفر کردن هنگام تخصیص، صفر کردن هنگام لغو تخصیص (free()) را
درنظر بگیرید:
- صفحههای سنجاقشده هزینه کمتری دارند: حافظه غیرفعال در صفحههای ۱۶ کیلوبایتی که تاحدی پر شدهاند در ZRAM تقریباً به صفر فشرده میشود، بنابراین صفحههای سنجاقشده فضای مبادله فیزیکی را هدر نمیدهند.
- سربار حافظه پنهان حداقلی: در زمان فراخوانی
free()، حافظه ازقبل در حافظه پنهان CPU داغ است و از خطاهای حافظه پنهان اضافی در آینده جلوگیری میکند.
خلاصه توصیهها
| ناحیه | توصیه | تأثیر موردانتظار |
|---|---|---|
| آستانههای پاکسازی | آستانههای انتشار را بهطور پویا بااستفاده از sysconf(_SC_PAGESIZE) مقیاسبندی کنید. |
از بنبست دائمی منطق انتشار جلوگیری میکند. |
| سفارش تخصیص | ابتدا از متراکمترین (تقریباً پر) صفحه یا اسلب اختصاص دهید. | با بستهبندی اشیای فعال باهم، حافظه مقیم (RSS) را کاهش میدهد. |
| اندازه دهانه | کلاسهای اندازه را با مضارب ۱۶ کیلوبایت تراز کنید و از دالهای بیشازاندازه بزرگ اجتناب کنید. | تکهتکهسازی صفحه دنباله را حذف میکند و شلی حافظه را کاهش میدهد. |
| حافظههای نهان میانگیر | هنگام ذخیره کردن میانگیرهای بزرگ در حافظه نهان، فوراً madvise(MADV_DONTNEED) را فراخوانی کنید. |
تورم RAM آزاد را حذف میکند و درعینحال استفاده مجدد مجازی سریع را حفظ میکند. |
| Swap / ZRAM | صفر کردن حافظه در free() بهجای تخصیص. |
نسبتهای فشردهسازی ZRAM را بهبود میبخشد تا صفحات سنجاقشده هزینه کمتری داشته باشند. |
بررسی کیتهای توسعه نرمافزار برای پشتیبانی از ۱۶ کیلوبایت
بسیاری از کیتهای توسعه نرمافزار با اندازه صفحه ۱۶ کیلوبایتی سازگار هستند، بهویژه اگر خودتان آنها را بسازید یا از نسخههای پیشساخته اخیر استفاده کنید. بااینحال، چون برخیاز کیتهای توسعه نرمافزار پیشساخته یا نسخههای کیت توسعه نرمافزار با ۱۶ کیلوبایت سازگار نیستند، باید وبسایت هریک از ارائهدهندگان کیت توسعه نرمافزار را بررسی کنید تا مشخص شود کدام نسخه برای استفاده با ۱۶ کیلوبایت مناسب است.
آزمایش کردن برنامه در محیط ۱۶ کیلوبایتی
پساز ساختن برنامه با پشتیبانی از دستگاههای ۱۶ کیلوبایتی، باید برنامه را در محیط ۱۶ کیلوبایتی آزمایش کنید تا ببینید آیا برنامه دچار پسرفت میشود یا نه. برای انجام این کار، این مراحل را دنبال کنید:
کیت توسعه نرمافزار Android 15 یا بالاتر را راهاندازی کنید.
یکی از محیطهای آزمایشی زیر را راهاندازی کنید:
- راهاندازی کردن «شبیهساز Android» با تصویر سیستم Android 15 مبتنی بر ۱۶ کیلوبایت
- استفاده از Cuttlefish با اندازه صفحه ۱۶ کیلوبایت در ARM64
- شبیهسازی Cuttlefish با اندازه صفحه ۱۶ کیلوبایت در x86-64
- فعال کردن حالت ۱۶ کیلوبایتی در دستگاه بااستفاده از گزینههای توسعهدهندگان
- استفاده از Samsung Remote Test Lab در دستگاههای پشتیبانیکننده از ۱۶ کیلوبایت
دستگاه آزمایشیتان را راهاندازی کنید، سپس فرمان زیر را اجرا کنید تا تأیید کنید که از محیط ۱۶ کیلوبایتی استفاده میکند:
adb shell getconf PAGE_SIZEفرمان باید مقدار
16384را برگرداند.فرمان
zipalignزیر را اجرا کنید تا تأیید کنید که برنامهتان تراز ۱۶ کیلوبایتی دارد، که در آن APK_NAME نام فایل APK برنامهتان است:zipalign -c -P 16 -v 4 APK_NAME.apkبرنامهتان را بهطور کامل آزمایش کنید و بر بخشهایی تمرکز کنید که ممکن است تحتتأثیر تغییر نمونههای کد ارجاعدهنده به اندازههای خاص صفحه قرار بگیرند.
راهاندازی «شبیهساز Android» با تصویر سیستم مبتنی بر ۱۶ کیلوبایت
برای راهاندازی محیط ۱۶ کیلوبایتی بااستفاده از «شبیهساز Android»، این مراحل را دنبال کنید:
- در «استودیو Android»، روی ابزارها > مدیر SDK کلیک کنید.
در برگه پلاتفرمهای کیت توسعه نرمافزار، نمایش جزئیات بسته را انتخاب کنید، سپس بخش Android VanillaIceCream یا بالاتر را ازهم باز کنید و بسته به دستگاههای مجازیای که میخواهید ایجاد کنید، یکی یا هر دو تصویر سیستم شبیهساز زیر را انتخاب کنید:
- Google APIs Experimental 16 KB Page Size ARM 64 v8a System Image
- Google APIs Experimental 16 KB Page Size Intel x86_64 Atom System Image
روی اعمال > تأیید کلیک کنید تا هرکدام از ایمیجهای سیستم را که انتخاب کردهاید بارگیری کنید.
مراحل راهاندازی دستگاه مجازی برای Android 15 را دنبال کنید و وقتی از شما خواسته شد ایمیج سیستم را انتخاب کنید، ایمیج سیستم ۱۶ کیلوبایتی را که بارگیری کردهاید انتخاب کنید. اگر بهطور خودکار توصیه نشد، میتوانید ایمیج سیستم ۱۶ کیلوبایتی را در برگه ایمیجهای دیگر پیدا کنید.
راهاندازی شبیهساز
پساز تکمیل راهاندازی «شبیهساز Android» و دستگاههای مجازی، شبیهساز را از منو دستگاه هدف یا از خط فرمان راهاندازی کنید.
فعال کردن حالت ۱۶ کیلوبایت روی دستگاه با استفاده از گزینههای توسعهدهنده

برای بوت کردن دستگاه در حالت ۱۶ کیلوبایت، گزینه توسعهدهنده Boot with 16KB page size را فعال یا غیرفعال کنید.
در نسخههای QPR اندروید ۱۵، میتوانید از گزینه توسعهدهنده که در دستگاههای خاصی موجود است، برای بوت کردن دستگاه در حالت ۱۶ کیلوبایت و انجام آزمایش روی دستگاه استفاده کنید . قبل از استفاده از گزینه توسعهدهنده، به تنظیمات > سیستم > بهروزرسانیهای نرمافزار بروید و هرگونه بهروزرسانی موجود را اعمال کنید.
این گزینه توسعهدهنده در دستگاههای زیر موجود است:
پیکسل ۸ و ۸ پرو (با اندروید ۱۵ QPR1 یا بالاتر)
پیکسل ۸a (با اندروید ۱۵ QPR1 یا بالاتر)
پیکسل ۹، ۹ پرو و ۹ پرو ایکسال (با اندروید ۱۵ نسخه QPR2 یا بالاتر)
پیکسل ۹a (با اندروید ۱۶ یا بالاتر)
حالت سازگاری با نسخههای قدیمی ۱۶ کیلوبایتی
هشدار در حالت سازگاری با اندازه صفحه
گزینه سازگاری معکوس ۱۶ کیلوبایتی زمانی دردسترس است که دستگاه با هسته ۱۶ کیلوبایتی اجرا شود. مدیر بسته برنامه را در حالت سازگاری با نسخههای قبلی ۱۶ کیلوبایتی اجرا میکند اگر شرایط زیر برقرار باشد:
- اگر برنامه فایلهای ELF (با پسوند
.so) با ترازبندی بخش LOAD ۴ کیلوبایتی داشته باشد. - اگر APK فشردهشده دارای فایلهای ELF غیرفشرده باشد که ۴ کیلوبایت تراز ZIP شده باشند.
اگر مدیر بسته حالت سازگاری معکوس ۱۶ کیلوبایتی را برای برنامهای فعال کرده باشد، برنامه هنگام اولین راهاندازی هشداری نمایش میدهد که میگوید در حالت سازگاری معکوس ۱۶ کیلوبایتی اجرا میشود.
حالت سازگاری معکوس ۱۶ کیلوبایتی به برخیاز برنامهها اجازه میدهد کار کنند، اما برای بهترین قابلیت اطمینان و پایداری، برنامهها همچنان باید با ۱۶ کیلوبایت تراز شوند.
در صفحه اطلاعات برنامه، در بخش پیشرفته، تنظیم اجرای برنامه در حالت سازگاری با اندازه صفحه را روشن یا خاموش کنید تا حالت سازگاری با نسخههای قدیمی ۱۶ کیلوبایتی برای برنامه خاصی فعال یا غیرفعال شود. این تنظیم فقط زمانی قابلمشاهده است که دستگاه با اندازه صفحه ۱۶ کیلوبایتی درحال اجرا باشد.
تنظیم حالت سازگاری با اندازه صفحه
برای اجباری کردن سازگاری معکوس ۱۶ کیلوبایتی برای همه برنامههای دستگاه:
adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false
برای خاموش کردن اجباری سازگاری معکوس ۱۶ کیلوبایتی برای همه برنامههای دستگاه:
adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true
در Android 17، همچنین میتوانید سازگاری معکوس ۱۶ کیلوبایتی را برای همه برنامهها بهاجبار خاموش کنید و باعث شوید هر باینری ناسازگار فوراً لغو شود:
adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
adb shell setprop pm.16kb.app_compat.disabled true
برای روشن یا خاموش کردن حالت سازگاری معکوس برای برنامهای خاص در AndroidManifest.xml آن،
ویژگی android:pageSizeCompat را روی فعال یا غیرفعال تنظیم کنید. وقتی این ویژگی تنظیم شود، برنامه هنگام راهاندازی هشدارهای حالت سازگاری با نسخههای قدیمی را نمایش نخواهد داد.