שמירת 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. לאחר האיפוס להגדרות המקוריות, המערכת תבצע שוב את ההפעלה הראשונה. המשמעות היא שה-APK השמירה במטמון לא זמינה אם מורידים את תמונת ה-OTA למחיצה B, המכשיר מאופס להגדרות המקוריות.

הטמעה

גישה 1. התוכן מופעל מחיצה system_other

גרסת Pro: תוכן שנטען מראש לא אובד אחרי האיפוס להגדרות המקוריות – יועתקו מהמחיצה 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/+/main/sepolicy/preloads_copy.te
  4. רישום הדומיין ב-/sepolicy/file_contexts חדש file:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    קובץ לדוגמה של הקשרים של SELinux זמין בכתובת: device/google/marlin/sepolicy/preloads_copy.te
  5. בזמן ה-build, צריך להעתיק את הספרייה שמכילה את התוכן שנטען מראש מחיצה 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 של הספק (במקרה שלנו, ספק/google_devices/marlin/preloads) למיקום במחיצה system_other שיועתק מאוחר יותר אל /data/preloads כאשר המכשיר יאותחל בפעם הראשונה בזמן האימון. הסקריפט רץ בזמן ה-build כדי להכין קובץ אימג' מסוג system_other. היא מצפה תוכן שנטען מראש שיהיה זמין ב-provider/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) זמינים לבחירה בכל גישת הטמעה, כל עוד מבנה הקובץ הסופי משקף את שמתואר למעלה.

גישה 2. תוכן בנתוני משתמשים התמונה הבהבה במפעל

הגישה החלופית הזו מניחה שתוכן שנטען מראש כבר נכלל הספרייה /data/preloads במחיצה /data.

Pro: פועל ישירות מהאריזה – אין צורך ליצור את המכשיר התאמה אישית להעתקת קבצים בהפעלה הראשונה. התוכן כבר מופיע ב- מחיצה /data.

חסרון: תוכן שנטען מראש אובד אחרי איפוס להגדרות המקוריות. בזמן יכול להיות שהשיטה הזו תתאים לחלק, אבל לא תמיד היא תתאים ליצרני ציוד מקורי (OEM) לאפס מכשירים לאחר ביצוע בדיקות בקרת איכות.

שיטת @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. אם יש צורך, מדמים את ספריית המטמון של הקבצים ואת התוכן שבה (נדרשות גם הרשאות Root):
    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