ذخیره APK

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

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

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

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

پیش‌نیازها

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

  • نسخه اندروید ۸.۱ (O MR1) نصب شده است
  • پارتیشن A/B پیاده‌سازی شد

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

بنابراین، حافظه پنهان APK را نمی‌توان از طریق OTA به‌روزرسانی کرد؛ فقط می‌توان آن را در کارخانه از قبل بارگذاری کرد. تنظیم مجدد کارخانه فقط بر روی پارتیشن /data تأثیر می‌گذارد. پارتیشن سیستم B تا زمانی که تصویر OTA دانلود شود، همچنان محتوای از پیش بارگذاری شده را دارد. پس از تنظیم مجدد کارخانه، سیستم دوباره بوت اول را طی می‌کند. این بدان معناست که اگر تصویر 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/+/android16-qpr1-release/sepolicy/preloads_copy.te
  4. ثبت دامنه در یک دامنه جدید /sepolicy/file_contexts فایل /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)
    
    این نمونه‌ای از تغییر در Makefile است که امکان کپی کردن منابع کش 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/
    
    این ساختار دایرکتوری نهایی روی دستگاه‌ها است. تولیدکنندگان اصلی تجهیزات (OEM) می‌توانند هر رویکرد پیاده‌سازی را انتخاب کنند، مادامی که ساختار فایل نهایی، ساختار توضیح داده شده در بالا را تکرار کند.

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

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

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

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

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

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

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

فقط برنامه‌های دارای مجوز می‌توانند به دایرکتوری کش preloads دسترسی داشته باشند. برای این دسترسی، برنامه‌ها باید در دایرکتوری /system/priv-app نصب شوند.

اعتبارسنجی

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

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

  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. برنامه را تست کنید. پس از نصب برنامه و ایجاد دایرکتوری test file_cache ، برنامه ApkCacheTest را باز کنید. باید یک فایل test.txt و محتویات آن را نشان دهد. برای مشاهده نحوه نمایش این نتایج در رابط کاربری، به این تصویر مراجعه کنید.

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