פריסת המחיצות

ב-Android 10, מערכת קבצי הבסיס כבר לא נכללת ב-ramdisk.img, אלא היא ממוזגת לתוך system.img (כלומר, system.img תמיד נוצר כאילו BOARD_BUILD_SYSTEM_ROOT_IMAGE הוגדר). מכשירים שיושקו עם Android 10:

  • משתמשים בפריסת מחיצות של מערכת כשורש (נאכפת אוטומטית על ידי הבנייה ללא אפשרויות לשינוי ההתנהגות).
  • חובה להשתמש ב-ramdisk, שנדרש ל-dm-linear.
  • חובה להגדיר את BOARD_BUILD_SYSTEM_ROOT_IMAGE לערך false. ההגדרה הזו משמשת רק כדי להבחין בין מכשירים שמשתמשים ב-ramdisk לבין מכשירים שלא משתמשים ב-ramdisk (ובמקום זאת מבצעים mount של system.img ישירות).

המשמעות של הגדרת מערכת כבסיס שונה בין Android 9 לבין Android 10. בהגדרת מערכת כשורש ב-Android 9, הערך של BOARD_BUILD_SYSTEM_ROOT_IMAGE הוא true, מה שמאלץ את ה-build למזג את מערכת קבצי השורש לתוך system.img ואז לטעון את system.img כמערכת קבצי השורש (rootfs). ההגדרה הזו נדרשת במכשירים שמושקים עם Android 9, אבל היא אופציונלית במכשירים שמשדרגים ל-Android 9 ובמכשירים שפועלות בהם גרסאות קודמות של Android. במערכת Android 10 עם הגדרת system-as-root, תהליך הבנייה תמיד ממזג את $TARGET_SYSTEM_OUT ואת $TARGET_ROOT_OUT לתוך system.img. ההגדרה הזו היא התנהגות ברירת המחדל לכל המכשירים שמריצים Android 10.

ב-Android 10 בוצעו שינויים נוספים כדי לתמוך במחיצות דינמיות, מערכת חלוקה למחיצות במרחב המשתמש שמאפשרת לעדכונים דרך האוויר (OTA) ליצור, לשנות את הגודל של מחיצות או למחוק אותן. במסגרת השינוי הזה, ליבת Linux לא יכולה יותר לטעון את מחיצת המערכת הלוגית במכשירים עם Android 10, ולכן הפעולה הזו מטופלת על ידי השלב הראשון של init.

בסעיפים הבאים מפורטות הדרישות של מערכת כשורש לעדכוני OTA של המערכת בלבד, ומוסבר איך לעדכן מכשירים כדי להשתמש במערכת כשורש (כולל שינויים בפריסת המחיצות ודרישות הליבה של dm-verity). לפרטים על שינויים ב-ramdisk, אפשר לעיין במאמר בנושא מחיצות ramdisk.

מידע על עדכוני OTA למערכת בלבד

עדכוני OTA למערכת בלבד, שמאפשרים לעדכן את גרסאות Android‏ system.img ו-product.img בלי לשנות מחיצות אחרות, דורשים פריסת מחיצות של מערכת כשורש. כל המכשירים עם Android מגרסה 10 ואילך חייבים להשתמש בפריסת מחיצות של מערכת כבסיס כדי לאפשר עדכוני OTA רק למערכת.

  • מכשירי A/B, שמטמיעים את מחיצת system כ-rootfs, כבר משתמשים ב-system-as-root ולא נדרשים שינויים כדי לתמוך בעדכוני OTA של המערכת.
  • מכשירים שהם לא A/B, שמבצעים mount של מחיצת system ב-/system, צריכים להתעדכן כדי להשתמש בפריסת מחיצות של מערכת כשורש כדי לתמוך בעדכוני מערכת מסוג OTA.

פרטים על מכשירי A/B ומכשירים שאינם A/B מופיעים במאמר עדכוני מערכת מסוג A/B (ללא הפרעה).

שימוש בשכבת-על של ספק (גרסה AOSP 14 ומטה)

שכבת-על של ספק מאפשרת לכם להוסיף שינויים לvendor מחיצה בזמן האתחול של המכשיר. שכבת-על של ספק היא קבוצה של מודולים של ספקים במחיצה product שמוצגת כשכבת-על במחיצה vendor כשהמכשיר מופעל, ומחליפה את המודולים הקיימים ומוסיפה להם מודולים חדשים.

כשהמכשיר מופעל, התהליך של init משלים את ההרכבה של השלב הראשון וקורא את מאפייני ברירת המחדל. לאחר מכן, המערכת מחפשת/product/vendor_overlay/<target_vendor_version> את כל ספריית משנה ומעלה אותה לספריית המחיצה המתאימה vendor, אם התנאים הבאים מתקיימים:

  • העסק /vendor/<overlay_dir> קיים.
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir> has the same file context as /vendor/<overlay_dir>.
  • ל-init יש הרשאה להרכיב בהקשר של הקובץ /vendor/<overlay_dir>.

הטמעה של שכבת-על של ספק

התקנת קובצי שכבת-על של ספקים ב-/product/vendor_overlay/<target_vendor_version>. הקבצים האלה מוחלפים במחיצה vendor כשהמכשיר מופעל, ומחליפים קבצים עם אותו שם ומוסיפים קבצים חדשים. ספק השירות לא יכול להסיר קבצים ממחיצת vendor.

קובצי שכבת-על של ספקים צריכים להיות בעלי אותו הקשר של קובץ כמו קובצי היעד שהם מחליפים במחיצה vendor. כברירת מחדל, הקבצים בספרייה /product/vendor_overlay/<target_vendor_version> הם בהקשר vendor_file. אם יש אי התאמות בהקשר של קבצים בין קובצי שכבת-העל של הספק לבין הקבצים שהם מחליפים, צריך לציין זאת במדיניות ה-SELinux הספציפית למכשיר. ההקשר של הקובץ מוגדר ברמת הספרייה. אם הקשר הקובץ של ספריית שכבת על של ספק לא תואם לספריית היעד, ולא מצוין הקשר הקובץ הנכון במדיניות sepolicy הספציפית למכשיר, ספריית שכבת העל של הספק לא תונח על ספריית היעד.

כדי להשתמש בשכבת-על של ספק, צריך להפעיל את OverlayFS בקרנל על ידי הגדרת CONFIG_OVERLAY_FS=y. בנוסף, צריך למזג את ליבת המערכת מליבת המערכת המשותפת 4.4 ואילך, או להחיל תיקון (patch) באמצעות "overlayfs: override_creds=off option bypass creator_cred".

דוגמה להטמעה של שכבת על של ספק

ההליך הזה מדגים הטמעה של שכבת-על של ספק שמוצגת מעל הספריות /vendor/lib/*, /vendor/etc/* ו-/vendor/app/*.

  1. הוספת קבצים מוכנים מראש של ספקים ב-device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/:

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. מתקינים את קובצי הספקים המוכנים מראש ב-product/vendor_overlay ב-device/google/device/device.mk:

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. מגדירים הקשרים של קבצים אם לקבצי המחיצה של יעד vendor יש הקשרים שונים מ-vendor_file. הספרייה הזו לא מופיעה בדוגמה כי /vendor/lib/* משתמש בהקשר vendor_file.

    מוסיפים את הטקסט הבא לקובץ device/google/device-sepolicy/private/file_contexts:

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. מאפשרים לתהליך init לטעון את שכבת-העל של הספק בהקשרים של קבצים שאינם vendor_file. התהליך init כבר קיבל הרשאה להרכבה בהקשר vendor_file, ולכן בדוגמה הזו לא מוגדרת המדיניות עבור vendor_file.

    מוסיפים את הטקסט הבא לקובץ device/google/device-sepolicy/public/init.te:

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

אימות שכבת-העל של הספק

כדי לאמת את ההגדרה של שכבת העל של הספק, מוסיפים קבצים בתיקייה /product/vendor_overlay/<target_vendor_version>/<overlay_dir> ובודקים אם הקבצים מוצגים כשכבת על על הקבצים בתיקייה /vendor/<overlay_dir>.

בגרסאות build של userdebug, יש מודול בדיקה ל-Atest:

$ atest -v fs_mgr_vendor_overlay_test

עדכון ל-system-as-root

כדי לעדכן מכשירים מסוג non-A/B לשימוש ב-system-as-root, צריך לעדכן את תוכנית החלוקה למחיצות של boot.img ושל system.img, להגדיר dm-verity ולהסיר את כל התלות בהפעלה בתיקיות הבסיס הספציפיות למכשיר.

עדכון מחיצות

בניגוד למכשירי A/B שבהם /boot משמש כמחיצת שחזור, במכשירים שהם לא A/B, המחיצה /recovery צריכה להיות נפרדת כי אין להם מחיצת חריץ לגיבוי (לדוגמה, מ-boot_a ל-boot_b). אם מסירים את /recovery במכשיר שהוא לא A/B ויוצרים דמיון לתוכנית A/B, מצב השחזור עלול להיפסק במהלך עדכון שנכשל למחיצה /boot. לכן, מחיצת /recovery חייבת להיות מחיצה נפרדת מ-/boot במכשירים שאינם A/B, מה שאומר שקובץ אימג' לשחזור מערכת ההפעלה ממשיך להתעדכן באופן מושהה (כלומר, כמו במכשירים עם Android מגרסה 8.1.0 ומטה).

בטבלה הבאה מפורטים ההבדלים בחלוקת התמונות למחיצות במכשירים שאינם A/B לפני ואחרי Android 9.

תמונה Ramdisk (לפני Android 9) מערכת כשורש (אחרי Android 9)
boot.img מכיל ליבה וramdisk.img:
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
מכיל רק ליבת אתחול רגילה.
recovery.img מכיל ליבת שחזור ו-ramdisk.img שחזור.
system.img הוא מכיל את הרכיבים הבאים:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
מכיל את התוכן הממוזג של system.img המקורי ושל ramdisk.img:
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

המחיצות עצמן לא משתנות. גם ramdisk וגם system-as-root משתמשים בסכימת המחיצות הבאה:

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor וכו'.

הגדרת dm-verity

במערכת-כ-root, ליבת המערכת צריכה לטעון את system.img מתחת ל-/ (נקודת טעינה) עם dm-verity. ‫AOSP תומך בהטמעות הבאות של dm-verity עבור system.img.

vboot 1.0

ב-vboot 1.0, ליבת המערכת צריכה לנתח מטא-נתונים ספציפיים ל-Android ב-/system, ואז להמיר אותם לפרמטרים של dm-verity כדי להגדיר את dm-verity (נדרשים תיקוני הליבה האלה). בדוגמה הבאה מוצגות הגדרות שקשורות ל-dm-verity עבור מערכת כשורש בשורת הפקודה של ליבת המערכת:

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

ב-vboot 2.0‏ (AVB), תוכנת האתחול צריכה לשלב את external/avb/libavb, שבהמשך מנתחת את המתאר של עץ הגיבוב עבור /system, ממירה אותו לפרמטרים של dm-verity, ולבסוף מעבירה את הפרמטרים לליבה דרך שורת הפקודה של הליבה. (תיאורי ה-Hashtree של /system יכולים להיות ב-/vbmeta או ב-/system עצמו).

כדי להשתמש ב-vboot 2.0, צריך להחיל את תיקוני הליבה הבאים:

בדוגמה הבאה מוצגות הגדרות שקשורות ל-dm-verity עבור מערכת כשורש בשורת הפקודה של ליבת המערכת:

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

שימוש בתיקיות בסיסיות (root) ספציפיות למכשיר

במערכת עם system-as-root, אחרי שקובץ האימג' הגנרי של המערכת (GSI) נצרב במכשיר (ולפני שמריצים את הבדיקות של Vendor Test Suite), כל תיקיות הבסיס הספציפיות למכשיר שנוספו באמצעות BOARD_ROOT_EXTRA_FOLDERS נעלמות כי התוכן של כל ספריית הבסיס הוחלף על ידי ה-GSI של system-as-root. הסרת התיקיות האלה עלולה לגרום לכך שלא יהיה אפשר להפעיל את המכשיר אם יש תלות בתיקיות הבסיס הספציפיות למכשיר (לדוגמה, אם הן משמשות כנקודות הרכבה).

כדי להימנע מהבעיה הזו, אל תשתמשו בBOARD_ROOT_EXTRA_FOLDERS כדי להוסיף תיקיות בסיס ספציפיות למכשיר. אם אתם צריכים לציין נקודות הרכבה ספציפיות למכשיר, אתם יכולים להשתמש ב-/mnt/vendor/<mount point> (נוסף ברשימות השינויים האלה). אפשר לציין את נקודות הטעינה האלה שספציפיות לספק ישירות גם בפירוט מבנה המכשיר (DT) fstab (לטעינה בשלב הראשון) וגם בקובץ /vendor/etc/fstab.{ro.hardware} בלי לבצע הגדרה נוספת (כי fs_mgr יוצר אותן באופן אוטומטי ב-/mnt/vendor/*).