التخزين المؤقت لحِزم APK

يصف هذا المستند تصميم حلّ لتخزين حِزم APK مؤقتًا من أجل تثبيت التطبيقات المُحمَّلة مُسبَقًا بشكلٍ سريع على جهاز متوافق مع أقسام A/B.

يمكن لمصنّعي الأجهزة الأصليين وضع التطبيقات الرائجة والتطبيقات التي تم تحميلها مسبقًا في ذاكرة التخزين المؤقت لملف APK المخزّنة في القسم B الذي يكون خاليًا في أغلب الأحيان على الأجهزة الجديدة المقسّمة إلى قسمَين A/B بدون التأثير في أي مساحة بيانات موجّهة للمستخدم. من خلال توفُّر ذاكرة تخزين مؤقتة لملفات APK على الجهاز، تصبح الأجهزة الجديدة أو التي تم إعادة ضبطها مؤخرًا على الإعدادات الأصلية جاهزة للاستخدام على الفور تقريبًا بدون الحاجة إلى تنزيل ملفات APK من Google Play.

حالات الاستخدام

  • تخزين التطبيقات المحمَّلة مُسبَقًا في القسم B لإعداد أسرع
  • تخزين التطبيقات الشائعة في القسم B لاستعادتها بشكل أسرع

المتطلّبات الأساسية

لاستخدام هذه الميزة، يجب أن يستوفي الجهاز المتطلبات التالية:

  • تثبيت الإصدار 8.1 (O MR1) من نظام التشغيل Android
  • تم تنفيذ التقسيم أ/ب

لا يمكن نسخ المحتوى المحمَّل مسبقًا إلا أثناء عملية التشغيل الأولى. ويعود السبب في ذلك إلى أنّه على الأجهزة التي تتيح تحديثات نظام A/B، لا يخزِّن القسم B ملفّات صور النظام، بل يخزِّن بدلاً من ذلك المحتوى المحمَّل مسبقًا، مثل موارد العروض التوضيحية للبيع بالتجزئة، وملفات OAT وذاكرة التخزين المؤقت لحِزمة APK. بعد نسخ الموارد إلى القسم /data (يحدث ذلك عند التشغيل الأول)، سيتم استخدام القسم B من خلال التحديثات عبر شبكة غير سلكية (OTA) لتنزيل الإصدارات المعدَّلة من صورة النظام.

لذلك، لا يمكن تحديث ذاكرة التخزين المؤقت لملف APK من خلال التحديث عبر الهواء، بل يمكن تحميلها مسبقًا فقط في المصنع. لا تؤثّر ميزة "إعادة الضبط على الإعدادات الأصلية" إلا في قسم ‎ /data. سيظل القسم B للنظام يحتوي على المحتوى المحمَّل مسبقًا إلى أن يتم تنزيل صورة OTA. بعد إعادة الضبط على الإعدادات الأصلية، سيخضع النظام لعمليات التشغيل الأولى مرة أخرى. وهذا يعني أنّه لا يمكن الاحتفاظ بذاكرة التخزين المؤقت لملف APK إذا تم تنزيل صورة OTA إلى القسم B، ثم تتم إعادة ضبط الجهاز على الإعدادات الأصلية.

التنفيذ

الطريقة 1 المحتوى على القسم system_other

ملاحظة للمحترفين: لا يتم فقدان المحتوى المحمَّل مسبقًا بعد إعادة الضبط على الإعدادات الأصلية، بل سيتم نسخه من القسم B بعد إعادة التشغيل.

Con: يتطلب مساحة في قسم 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/+/main/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)
    
    في ما يلي مثال على تغيير في ملف Makefile يسمح بنسخ موارد ملف التخزين المؤقت لملف APK من مستودع Git الخاص بالمورّد (في حالتنا، كان vendor/google_devices/marlin/preloads) إلى الموقع في القسم system_other الذي سيتم نسخه لاحقًا إلى ‎ /data/preloads عند تشغيل الجهاز للمرة الأولى. يتم تشغيل هذا النص البرمجي في وقت الإنشاء لإعداد صورة system_other. ويفترض أن يكون المحتوى المُحمَّل مُسبَقًا متاحًا في vendor/google_devices/marlin/preloads. يمكن لمصنّع المعدّات الأصلية اختيار اسم/مسار المستودع الفعلي.
  6. تقع ذاكرة التخزين المؤقت لملف APK في /data/preloads/file_cache وتتضمّن التنسيق التالي:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    هذه هي بنية الدليل النهائية على الأجهزة. يمكن لمصنّعي المعدّات الأصلية اختيار أيّ نهج لتنفيذ الملفات طالما أنّ بنية الملف النهائية تكرّر البنية الموضّحة أعلاه.

الطريقة 2: محتوى حول بيانات المستخدمين صورة تم عرضها في المصنع

يفترض هذا النهج البديل أنّ المحتوى المحمَّل مسبقًا مضمّن في directory /data/preloads على قسم /data.

المزايا: تعمل هذه الطريقة مباشرةً بدون الحاجة إلى إجراء تعديلات على الجهاز لنسخ الملفات عند تشغيله لأول مرة. المحتوى متوفّر حاليًا في القسم /data.

السلبيات: يتم فقدان المحتوى المحمَّل مسبقًا بعد إعادة الضبط على الإعدادات الأصلية. قد يكون هذا الإجراء مقبولًا لدى بعض المستخدمين، ولكن قد لا يكون مناسبًا دائمًا لمصنعي الأجهزة الأصليين الذين يُعيدون برمجة الأجهزة على الإعدادات الأصلية بعد إجراء عمليات فحص للتحقّق من الجودة.

تمت إضافة طريقة جديدة في واجهة برمجة التطبيقات getPreloadsFileCache() من SystemApi إلى 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 ومحتوياته. اطّلِع على لقطة الشاشة هذه لمعرفة كيفية ظهور هذه النتائج في واجهة المستخدم.

    الشكل 1: نتائج ApkCacheTest