ذخیره کردن APK در حافظه نهان

این سند طراحی راهکار ذخیره کردن APK در حافظه نهان برای نصب سریع برنامه‌های ازپیش‌بارگذاری‌شده در دستگاهی که از پارتیشن‌های A/B پشتیبانی می‌کند را شرح می‌دهد.

تولیدکنندگان تجهیزات اصلی می‌توانند برنامه‌های پیش‌بارگذاری‌شده و محبوب را در حافظه نهان APK ذخیره‌شده در پارتیشن B که در دستگاه‌های جدید دارای پارتیشن A/B عمدتاً خالی است قرار دهند، بدون اینکه بر فضای داده کاربر تأثیر بگذارند. با دردسترس بودن حافظه نهان APK در دستگاه، دستگاه‌های جدید یا دستگاه‌هایی که به‌تازگی بازنشانی کارخانه‌ای شده‌اند تقریباً بلافاصله آماده استفاده می‌شوند و نیازی به بارگیری فایل‌های APK از Google Play ندارند.

موارد استفاده

  • ذخیره برنامه‌های ازپیش بارگذاری‌شده در پارتیشن B برای راه‌اندازی سریع‌تر
  • برنامه‌های پرطرفدار را در بخش B ذخیره کنید تا سریع‌تر بازیابی شوند

پیش‌نیازها

برای استفاده از این ویژگی، دستگاه باید:

  • نسخه پخش Android 8.1 (O MR1) نصب شد
  • پارتیشن A/B پیاده‌سازی شد

محتوای ازپیش بارگذاری‌شده را فقط درطول اولین راه‌اندازی می‌توان کپی کرد. دلیل این امر این است که در دستگاه‌هایی که از به‌روزرسانی‌های سیستم A/B پشتیبانی می‌کنند، بخش B درواقع فایل‌های تصویر سیستم را ذخیره نمی‌کند، بلکه محتوای پیش‌بارشده مانند منابع نمونه برای خرده‌فروشان، فایل‌های OAT، و حافظه پنهان APK را ذخیره می‌کند. پس‌از کپی شدن منابع در پارتیشن data/ (این اتفاق در اولین راه‌اندازی می‌افتد)، پارتیشن B توسط به‌روزرسانی‌های ازطریق هوا (OTA) برای بارگیری نسخه‌های به‌روزشده تصویر سیستم استفاده خواهد شد.

بنابراین، حافظه نهان APK ازطریق OTA به‌روزرسانی نمی‌شود؛ فقط در کارخانه می‌تواند ازقبل بارگذاری شود. بازنشانی کارخانه‌ای فقط بر بخش /data تأثیر می‌گذارد. تا زمانی که تصویر OTA بارگیری نشود، بخش B سیستم همچنان محتوای پیش‌بارشده را دارد. پس‌از بازنشانی کارخانه‌ای، سیستم دوباره راه‌اندازی اولیه را انجام خواهد داد. این یعنی اگر تصویر OTA در پارتیشن B بارگیری شود و سپس دستگاه بازنشانی کارخانه‌ای شود، حافظه نهان APK دردسترس نخواهد بود.

پیاده‌سازی

رویکرد ۱. محتوا در پارتیشن system_other

مزیت: محتوای ازپیش بارگذاری‌شده پس‌از بازنشانی کارخانه‌ای ازدست نمی‌رود - پس‌از بازراه‌اندازی، از پارتیشن B کپی خواهد شد.

عیب: به فضای پارتیشن B نیاز دارد. راه‌اندازی پس‌از بازنشانی کارخانه‌ای به زمان بیشتری برای کپی کردن محتوای ازپیش بارگذاری‌شده نیاز دارد.

برای اینکه پیش‌بارگذاری‌ها در اولین راه‌اندازی کپی شوند، سیستم یک دستورگان در /system/bin/preloads_copy.sh فراخوانی می‌کند. برنامه با یک آرگومان فراخوانده می‌شود (مسیر نقطه نصب فقط خواندنی برای پارتیشن system_b):

برای پیاده‌سازی این ویژگی، این تغییرات مختص دستگاه را انجام دهید. در اینجا نمونه‌ای از Marlin آورده شده است:

  1. دستورگان کپی کردن را به فایل device-common.mk (در این مورد، device/google/marlin/device-common.mk) اضافه کنید، مانند این:
    # Script that copies preloads directory from system_other to data partition
    PRODUCT_COPY_FILES += \
        device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh
    
    منبع نمونه دستورگان را در اینجا پیدا کنید: device/google/marlin/preloads_copy.sh
  2. فایل init.common.rc را ویرایش کنید تا فهرست راهنمای لازم /data/preloads و زیرفهرست‌های راهنما را ایجاد کند:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    منبع فایل نمونه init را در اینجا پیدا کنید: device/google/marlin/init.common.rc
  3. دامنه SELinux جدیدی را در فایل preloads_copy.te تعریف کنید:
    type preloads_copy, domain, coredomain;
    type preloads_copy_exec, exec_type, vendor_file_type, file_type;
    
    init_daemon_domain(preloads_copy)
    
    allow preloads_copy shell_exec:file rx_file_perms;
    allow preloads_copy toolbox_exec:file rx_file_perms;
    allow preloads_copy preloads_data_file:dir create_dir_perms;
    allow preloads_copy preloads_data_file:file create_file_perms;
    allow preloads_copy preloads_media_file:dir create_dir_perms;
    allow preloads_copy preloads_media_file:file create_file_perms;
    
    # Allow to copy from /postinstall
    allow preloads_copy system_file:dir r_dir_perms;
    
    نمونه فایل دامنه SELinux را در اینجا پیدا کنید: /device/google/marlin/+/android17-release/sepolicy/preloads_copy.te
  4. دامنه را در /sepolicy/file_contexts فایل جدید ثبت کنید:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    نمونه فایل زمینه‌های SELinux را در اینجا پیدا کنید: device/google/marlin/sepolicy/preloads_copy.te
  5. در زمان ساخت، دایرکتوری محتوای ازپیش بارگذاری‌شده باید در system_other پارتیشن کپی شود:
    # Copy contents of preloads directory to system_other partition
    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)
    
    این نمونه‌ای از تغییر در «فایل ساخت» است که امکان کپی کردن منابع حافظه نهان APK از مخزن Git فروشنده (در مورد ما vendor/google_devices/marlin/preloads) به مکان پارتیشن system_other را فراهم می‌کند که بعداً وقتی دستگاه برای اولین‌بار راه‌اندازی می‌شود در /data/preloads کپی خواهد شد. این اسکریپت در زمان ساخت اجرا می‌شود تا تصویر system_other را آماده کند. انتظار دارد محتوای ازپیش بارشده در vendor/google_devices/marlin/preloads دردسترس باشد. OEM می‌تواند نام/مسیر مخزن واقعی را آزادانه انتخاب کند.
  6. حافظه نهان APK در /data/preloads/file_cache قرار دارد و چیدمان زیر را دارد:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    این ساختار دایرکتوری نهایی در دستگاه‌ها است. تولیدکنندگان اصلی تجهیزات می‌توانند هر رویکرد پیاده‌سازی را انتخاب کنند، به‌شرطی که ساختار فایل نهایی مشابه ساختار شرح‌داده‌شده در بالا باشد.

رویکرد ۲. محتوای داده‌های کاربر تصویر در کارخانه نمایش داده شد

این رویکرد جایگزین فرض می‌کند که محتوای پیش‌بارشده ازقبل در دایرکتوری /data/preloads در پارتیشن /data گنجانده شده است.

Pro: آماده استفاده است - برای کپی کردن فایل‌ها در اولین راه‌اندازی، نیازی به سفارشی‌سازی دستگاه نیست. محتوا ازقبل در بخش /data قرار دارد.

عیب: محتوای ازپیش بارگذاری‌شده پس‌از بازنشانی کارخانه‌ای ازدست می‌رود. اگرچه این ممکن است برای برخی قابل‌قبول باشد، اما ممکن است همیشه برای سازندگان اصلی تجهیزات که دستگاه‌ها را پس‌از انجام بازرسی‌های کنترل کیفیت بازنشانی کارخانه‌ای می‌کنند، کارساز نباشد.

روش جدید ‎ @SystemApi،‏ getPreloadsFileCache()، به android.content.Context اضافه شد. این روش مسیر مطلق به دایرکتوری مختص برنامه را در حافظه نهان پیش‌بارشده برمی‌گرداند.

روش جدیدی، IPackageManager.deletePreloadsFileCache، اضافه شد که اجازه می‌دهد برای پس‌گرفتن همه فضا، دایرکتوری پیش‌بارگذاری‌ها را حذف کنید. این روش فقط توسط برنامه‌های دارای SYSTEM_UID، یعنی سرور سیستم یا «تنظیمات»، قابل فراخوانی است.

آماده‌سازی برنامه

فقط برنامه‌های ممتاز می‌توانند به دایرکتوری حافظه نهان پیش‌بارگیری‌ها دسترسی داشته باشند. برای آن دسترسی، برنامه‌ها باید در دایرکتوری /system/priv-app نصب شوند.

اعتبارسنجی

  • پس‌از اولین راه‌اندازی، دستگاه باید در فهرست راهنمای /data/preloads/file_cache محتوا داشته باشد.
  • اگر فضای ذخیره‌سازی دستگاه کم شود، محتوای موجود در دایرکتوری file_cache/ باید حذف شود.

از برنامه نمونه ApkCacheTest برای آزمایش حافظه نهان APK استفاده کنید.

  1. با اجرای این فرمان از فهرست راهنمای ریشه، برنامه را بسازید:
    make ApkCacheTest
    
  2. برنامه را به‌عنوان برنامه ممتاز نصب کنید. (به‌یاد داشته باشید که فقط برنامه‌های ممتاز می‌توانند به حافظه نهان APK دسترسی داشته باشند.) این کار به دستگاه با دسترسی ریشه‌ای نیاز دارد:
    adb root && adb remount
    adb shell mkdir /system/priv-app/ApkCacheTest
    adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/
    adb shell stop && adb shell start
    
  3. درصورت نیاز، دایرکتوری حافظه نهان فایل و محتوای آن را شبیه‌سازی کنید (به امتیازات ریشه نیز نیاز دارد):
    adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest
    adb shell restorecon -r /data/preloads
    adb shell "echo "Test File" > /data/preloads/file_cache/com.android.apkcachetest/test.txt"
    
  4. برنامه را آزمایش کنید. پس‌از نصب برنامه و ایجاد دایرکتوری آزمایشی file_cache، برنامه ApkCacheTest را باز کنید. باید یک فایل test.txt و محتوای آن را نشان دهد. برای دیدن نحوه نمایش این نتایج در واسط کاربر، این نماگرفت را ببینید.

    شکل ۱. نتایج ApkCacheTest.