הטמעת מחיצות דינמיות

חלוקה דינמית מיושמת באמצעות המודול dm-linear device-mapper בליבה של Linux. המחיצה super מכילה מטא-נתונים שמפרטים את השמות וטווחי הבלוקים של כל מחיצה דינמית ב-super. בשלב הראשון של init, המטא-נתונים האלה מנותחים ומאומתים, ונוצרים מכשירי בלוק וירטואליים שמייצגים כל מחיצה דינמית.

כשמחילים עדכון OTA, המחיצות הדינמיות נוצרות, משנות את הגודל או נמחקות באופן אוטומטי לפי הצורך. במכשירי A/B יש שתי עותקים של המטא-נתונים, והשינויים חלים רק על העותק שמייצג את חריצי היעד.

מאחר שמחיצות דינמיות מיושמות במרחב המשתמש, אי אפשר להפוך למחיצות דינמיות את המחיצות שנדרשות למחולל האתחול. לדוגמה, boot,‏ dtbo ו-vbmeta נקראים על ידי תוכנת האתחול, ולכן צריך להשאיר אותם כמחיצות פיזיות.

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

הטמעת מחיצות דינמיות במכשירים חדשים

בקטע הזה מוסבר איך מטמיעים מחיצות דינמיות במכשירים חדשים שמשתחררים עם Android מגרסה 10 ואילך. במאמר שדרוג של מכשירי Android מוסבר איך מעדכנים מכשירים קיימים.

שינויים במחיצות

במכשירים שהושקעו עם Android 10, יוצרים מחיצה בשם super. המחיצה super מטפלת במקומות A/B באופן פנימי, כך שמכשירי A/B לא צריכים מחיצות נפרדות של super_a ו-super_b. כל המחיצות של AOSP לקריאה בלבד שלא משמשות את מנהל האתחול חייבות להיות דינמיות, וצריך להסיר אותן מטבלת המחיצות של GUID‏ (GPT). מחיצות ספציפיות לספק לא חייבות להיות דינמיות, ואפשר למקם אותן ב-GPT.

כדי להעריך את הגודל של super, צריך להוסיף את הגדלים של המחיצות שמוחקות מ-GPT. במכשירי A/B, הנתון הזה צריך לכלול את הגודל של שתי המשבצות. איור 1 מציג טבלת מחיצות לדוגמה לפני ואחרי ההמרה למחיצות דינמיות.

פריסת טבלת המחיצות
איור 1. הפריסה החדשה של טבלת המחיצות הפיזיות במהלך המרה למחיצות דינמיות

המחיצות הדינמיות הנתמכות הן:

  • מערכת
  • ספק
  • מוצר
  • System Ext
  • ODM

במכשירים שהושקעו עם Android 10, אפשרות שורת הפקודה של הליבה androidboot.super_partition חייבת להיות ריקה כדי שהפקודה sysprop‏ ro.boot.super_partition תהיה ריקה.

יישור מחיצות

אם המחיצה super לא מותאמת כראוי, יכול להיות שהמודול device-mapper יפעל פחות יעיל. מחיצה super חייבת להיות מותאמת לגודל הבקשה המינימלי של קלט/פלט כפי שנקבע בשכבת הבלוק. כברירת מחדל, מערכת ה-build (דרך lpmake, שמפיקה את קובץ האימג' של המחיצה super) מניחה שאישור (alignment) של 1 MiB מספיק לכל מחיצה דינמית. עם זאת, הספקים צריכים לוודא שהמחיצה super מותאמת כראוי.

כדי לקבוע את גודל הבקשה המינימלי של מכשיר בלוק, צריך לבדוק את sysfs. לדוגמה:

# ls -l /dev/block/by-name/super
lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17
# cat /sys/block/sda/queue/minimum_io_size
786432

אפשר לאמת את היישור של המחיצה super באופן דומה:

# cat /sys/block/sda/sda17/alignment_offset

היסט ההתאמה חייב להיות 0.

שינויים בתצורת המכשיר

כדי להפעיל את חלוקת המרחב לדפים באופן דינמי, מוסיפים את הדגל הבא ב-device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

שינויים בהגדרות הלוח

צריך להגדיר את הגודל של המחיצה super:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

במכשירי A/B, מערכת ה-build תציג שגיאה אם הגודל הכולל של קובצי האימג' של המחיצות הדינמיות גדול ממחצית גודל המחיצה super.

אפשר להגדיר את רשימת המחיצות הדינמיות באופן הבא. במכשירים שמשתמשים בקבוצות עדכונים, צריך לציין את הקבוצות במשתנה BOARD_SUPER_PARTITION_GROUPS. לכל שם קבוצה יהיה משתנה BOARD_group_SIZE ומשתנה BOARD_group_PARTITION_LIST. במכשירי A/B, הגודל המקסימלי של קבוצה צריך לכסות רק משבצת אחת, כי שמות הקבוצות מקבלים סיומת של משבצת באופן פנימי.

דוגמה למכשיר שבו כל המחיצות נמצאות בקבוצה שנקראת example_dynamic_partitions:

BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product

דוגמה למכשיר שמציב שירותי מערכת ושירותי מוצרים ב-group_foo, ו-vendor,‏ product ו-odm ב-group_bar:

BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar
BOARD_GROUP_FOO_SIZE := 4831838208
BOARD_GROUP_FOO_PARTITION_LIST := system product_services
BOARD_GROUP_BAR_SIZE := 1610612736
BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
  • במכשירים להשקה של בדיקות A/B וירטואליות, הסכום של הגדלים המקסימליים של כל הקבוצות חייב להיות לכל היותר:
    BOARD_SUPER_PARTITION_SIZE - תקורה
    אפשר לעיין במאמר הטמעת בדיקות A/B וירטואליות.
  • במכשירים להפעלת בדיקת A/B, הסכום של הגדלים המקסימליים של כל הקבוצות חייב להיות:
    BOARD_SUPER_PARTITION_SIZE / 2 - overhead
  • במכשירים שאינם A/B ובמכשירי A/B מותאמים, הסכום של כל הגדלים המקסימליים של הקבוצות חייב להיות:
    BOARD_SUPER_PARTITION_SIZE - תקורה
  • בזמן ה-build, הסכום של גדלי התמונות של כל מחיצה בקבוצת עדכונים לא יכול לחרוג מהגודל המקסימלי של הקבוצה.
  • העלות הנוספת נדרשת בחישוב כדי להביא בחשבון מטא-נתונים, התאמות וכו'. יתרת סבירה היא 4 MiB, אבל אפשר לבחור יתרה גדולה יותר בהתאם לצורכי המכשיר.

שינוי הגודל של מחיצות דינמיות

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

בתמונות ext4 לקריאה בלבד, מערכת ה-build מקצה באופן אוטומטי את הגודל המינימלי אם לא צוין גודל מחיצה מקודד. מערכת ה-build מתאימה את התמונה כך שמערכת הקבצים תכלול כמה שפחות מקום לא מנוצל. כך מוודאים שלא יאבד מקום במכשיר שאפשר להשתמש בו לעדכוני OTA.

בנוסף, אפשר לדחוס עוד יותר קובצי אימג' בפורמט ext4 על ידי הפעלת מחיקה כפולה ברמת הבלוק. כדי להפעיל את התכונה הזו, משתמשים בתצורה הבאה:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

אם אתם לא רוצים שהקצאה אוטומטית של גודל מינימלי של מחיצה תתבצע, יש שתי דרכים לשלוט בגודל המחיצה. אפשר לציין נפח מינימלי של מקום פנוי באמצעות BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE, או לציין BOARD_partitionIMAGE_PARTITION_SIZE כדי לאלץ את המחיצות הדינמיות להיות בגודל ספציפי. לא מומלץ לבצע אף אחת מהפעולות האלה אלא אם יש צורך בכך.

לדוגמה:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

הפעולה הזו מאלצת את מערכת הקבצים ב-product.img לכלול 50 MiB של מקום פנוי.

שינויים במערכת כ-root

אסור להשתמש ב-system-as-root במכשירים שיושקו עם Android 10.

אסור להשתמש ב-system-as-root במכשירים עם מחיצות דינמיות (בין שהן מופעלות במכשיר במקור ובין שהן מותקנות במכשיר במסגרת שדרוג). לליבת Linux אין אפשרות לפרש את המחיצה super, ולכן היא לא יכולה לטעון את system בעצמה. system מותקן עכשיו על ידי init בשלב הראשון, שנמצא ב-ramdisk.

לא מגדירים את BOARD_BUILD_SYSTEM_ROOT_IMAGE. ב-Android 10, הדגל BOARD_BUILD_SYSTEM_ROOT_IMAGE משמש רק כדי להבדיל בין מצב שבו המערכת מורכבת על ידי הליבה לבין מצב שבו היא מורכבת על ידי init של השלב הראשון ב-ramdisk.

הגדרת BOARD_BUILD_SYSTEM_ROOT_IMAGE ל-true גורמת לשגיאה ב-build כשגם PRODUCT_USE_DYNAMIC_PARTITIONS הוא true.

כשהערך של BOARD_USES_RECOVERY_AS_BOOT מוגדר כ-True, קובץ האימג' לשחזור נוצר בתור boot.img, שמכיל את ה-ramdisk של השחזור. בעבר, bootloader השתמש בפרמטר שורת הפקודה skip_initramfs של הליבה כדי להחליט באיזה מצב להפעיל את המכשיר. במכשירי Android 10, אסור שה-bootloader יעביר את הערך skip_initramfs לשורת הפקודה של הליבה. במקום זאת, bootloader צריך להעביר את androidboot.force_normal_boot=1 כדי לדלג על התהליך של שחזור ולהפעיל את Android הרגיל. במכשירים שפועלים עם Android מגרסה 12 ואילך, צריך להשתמש ב-bootconfig כדי להעביר את androidboot.force_normal_boot=1.

שינויים בהגדרות של AVB

כשמשתמשים ב-Android Verified Boot 2.0, אם המכשיר לא משתמש בתיאורים של מחיצות מוצמדות, אין צורך לבצע שינויים. עם זאת, אם משתמשים במחיצות שרשוריות ואחת מהמחיצות המאומתות היא דינמית, צריך לבצע שינויים.

בהמשך מוצגת דוגמה להגדרה של מכשיר שמקשר את vbmeta למחיצות system ו-vendor.

BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1

BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048
BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1

בהגדרה הזו, מנהל האתחול מצפה למצוא כותרת עליונה של vbmeta בסוף המחיצות system ו-vendor. מכיוון שהמחיצות האלה כבר לא גלויות למחולל האתחול (הן נמצאות ב-super), צריך לבצע שני שינויים.

  • מוסיפים את המחיצות vbmeta_system ו-vbmeta_vendor לטבלת המחיצות של המכשיר. למכשירי A/B, מוסיפים את הערכים vbmeta_system_a,‏ vbmeta_system_b,‏ vbmeta_vendor_a ו-vbmeta_vendor_b. אם מוסיפים מחיצה אחת או יותר מהמחיצות האלה, הן צריכות להיות באותו גודל כמו המחיצה vbmeta.
  • משנים את השם של דגלים בתצורה על ידי הוספת VBMETA_ ומציינים לאילו מחיצות השרשור יתבצע:
    BOARD_AVB_VBMETA_SYSTEM := system
    BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
    
    BOARD_AVB_VBMETA_VENDOR := vendor
    BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1

יכול להיות שמכשיר משתמש באחד מהמחיצות האלה, בשתיהן או באף אחת מהן. צריך לבצע שינויים רק כשמקשרים למחיצה לוגית.

שינויים בתוכנת האתחול של AVB

אם libavb מוטמע ב-bootloader, צריך לכלול את התיקונים הבאים:

אם משתמשים במחיצות מקושרות, צריך לכלול תיקון נוסף:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition"

שינויים בשורת הפקודה של הליבה

צריך להוסיף פרמטר חדש, androidboot.boot_devices, לשורת הפקודה של הליבה. init משתמש בזה כדי להפעיל קישורי /dev/block/by-name. הוא צריך להיות רכיב הנתיב של המכשיר לקישור הלא פורמלי הבסיסי לפי שם שנוצר על ידי ueventd, כלומר /dev/block/platform/device-path/by-name/partition-name. במכשירים שמריצים Android מגרסה 12 ואילך, צריך להשתמש ב-bootconfig כדי להעביר את androidboot.boot_devices אל init.

לדוגמה, אם הקישור הלא פורמלי של מחיצה העל לפי שם הוא /dev/block/platform/soc/100000.ufshc/by-name/super, אפשר להוסיף את הפרמטר של שורת הפקודה בקובץ BoardConfig.mk באופן הבא:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
אפשר להוסיף את הפרמטר bootconfig בקובץ BoardConfig.mk באופן הבא:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

שינויים ב-fstab

אסור שרשומות fstab ייכללו בעץ המכשיר ובשכבות-העל של עץ המכשיר. משתמשים בקובץ fstab שיהיה חלק מה-ramdisk.

צריך לבצע שינויים בקובץ fstab עבור מחיצות לוגיות:

  • השדה fs_mgr flags חייב לכלול את הדגל logical ואת הדגל first_stage_mount, שהוצגו ב-Android 10, שמציינים שצריך לטעון את המחיצה בשלב הראשון.
  • אפשר לציין avb=vbmeta partition name כסימן fs_mgr במחיצה, ואז המחיצה vbmeta שצוינה תאופס על ידי השלב הראשון init לפני שתתבצע ניסיון לחבר מכשירים.
  • השדה dev חייב להיות שם המחיצה.

הרשומות הבאות ב-fstab מגדירות את המערכת, הספק והמוצר כמחיצות לוגיות בהתאם לכללים שלמעלה.

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1        wait,slotselect,avb=vbmeta,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount
product  /product    ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount

מעתיקים את קובץ ה-fstab ל-ramdisk של השלב הראשון.

שינויים ב-SELinux

צריך לסמן את מכשיר הבלוק של מחיצה העל בתווית super_block_device. לדוגמה, אם הקישור הלא פורמלי של מחיצה העל לפי שם הוא /dev/block/platform/soc/100000.ufshc/by-name/super, צריך להוסיף את השורה הבאה לקובץ file_contexts:

/dev/block/platform/soc/10000\.ufshc/by-name/super   u:object_r:super_block_device:s0

fastbootd

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

מידע נוסף על הטמעת fastbootd זמין במאמר העברת Fastboot למרחב המשתמש.

adb remount

למפתחים שמשתמשים ב-builds של eng או userdebug, האפשרות adb remount היא שימושית מאוד ליצירת גרסאות אב מהירות. מחיצות דינמיות יוצרות בעיה ב-adb remount כי אין יותר מקום פנוי בכל מערכת קבצים. כדי לפתור את הבעיה, אפשר להפעיל במכשירים את overlayfs. כל עוד יש מקום פנוי במחיצה הסופר, המערכת של adb remount יוצרת באופן אוטומטי מחיצה דינמית זמנית ומשתמשת ב-overlayfs לכתיבה. המחיצה הזמנית נקראת scratch, לכן אל תשתמשו בשם הזה למחיצות אחרות.

מידע נוסף על הפעלת overlayfs זמין בקובץ README של overlayfs ב-AOSP.

שדרוג של מכשירי Android

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

שינויים בתצורת המכשיר

כדי להוסיף חלוקה דינמית לאחר מכן, מוסיפים את הדגלים הבאים בקובץ device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

שינויים בהגדרות הלוח

צריך להגדיר את משתני הלוח הבאים:

  • מגדירים את BOARD_SUPER_PARTITION_BLOCK_DEVICES כרשימה של מכשירי הבלוק המשמשים לאחסון של קטעי אחסון של מחיצות דינמיות. זוהי רשימת השמות של המחיצות הפיזיות הקיימות במכשיר.
  • מגדירים את BOARD_SUPER_PARTITION_partition_DEVICE_SIZE לגודל של כל מכשיר בלוק ב-BOARD_SUPER_PARTITION_BLOCK_DEVICES, בהתאמה. זוהי רשימת הגדלים של המחיצות הפיזיות הקיימות במכשיר. בדרך כלל זהו הערך BOARD_partitionIMAGE_PARTITION_SIZE בהגדרות הקיימות של הלוח.
  • מבטלים את ההגדרה של BOARD_partitionIMAGE_PARTITION_SIZE הקיים לכל המחיצות ב-BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • מגדירים את BOARD_SUPER_PARTITION_SIZE לסכום של BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • מגדירים את BOARD_SUPER_PARTITION_METADATA_DEVICE למכשיר הבלוק שבו מאוחסנים המטא-נתונים של המחיצות הדינמיות. הפורמט חייב להיות אחד מהפורמטים הבאים: BOARD_SUPER_PARTITION_BLOCK_DEVICES. בדרך כלל הערך שמוגדר הוא system.
  • מגדירים את BOARD_SUPER_PARTITION_GROUPS,‏ BOARD_group_SIZE ו-BOARD_group_PARTITION_LIST, בהתאמה. פרטים נוספים זמינים במאמר שינויים בהגדרות הלוח במכשירים חדשים.

לדוגמה, אם במכשיר כבר יש מחיצות של מערכת ושל ספק, ואתם רוצים להמיר אותן למחיצות דינמיות ולהוסיף מחיצה חדשה של מוצר במהלך העדכון, צריך להגדיר את ההגדרות הבאות ללוח:

BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor
BOARD_SUPER_PARTITION_METADATA_DEVICE := system

# Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE.
BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes>

# Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes>

# This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

# Configuration for dynamic partitions. For example:
BOARD_SUPER_PARTITION_GROUPS := group_foo
BOARD_GROUP_FOO_SIZE := <size-in-bytes>
BOARD_GROUP_FOO_PARTITION_LIST := system vendor product

שינויים ב-SELinux

צריך לסמן את המכשירים של בלוקים של מחיצות סופר במאפיין super_block_device_type. לדוגמה, אם במכשיר כבר יש מחיצות system ו-vendor, רוצים להשתמש בהן כמכשירי בלוק כדי לאחסן קטעי אחסון של מחיצות דינמיות, והקישורים הלא ניתנים לניתוק לפי שם שלהן מסומנים בתור system_block_device:

/dev/block/platform/soc/10000\.ufshc/by-name/system   u:object_r:system_block_device:s0
/dev/block/platform/soc/10000\.ufshc/by-name/vendor   u:object_r:system_block_device:s0

לאחר מכן מוסיפים את השורה הבאה לקובץ device.te:

typeattribute system_block_device super_block_device_type;

להגדרות אחרות, ראו הטמעת מחיצות דינמיות במכשירים חדשים.

מידע נוסף על עדכונים מותאמים לאחור זמין במאמר עדכון OTA למכשירי A/B ללא מחיצות דינמיות.

קובצי אימג' מקוריים

במכשיר שהושק עם תמיכה במחיצות דינמיות, מומלץ להימנע משימוש ב-fastboot של מרחב המשתמש כדי להבהיל קובצי אימג' מברירת המחדל, כי האתחול למרחב המשתמש איטי יותר מאשר שיטות אחרות להבהלה.

כדי לטפל בבעיה הזו, make dist יוצר עכשיו קובץ אימג' נוסף של super.img שאפשר להטמיע ישירות במחיצה הסופר. הוא אוסף באופן אוטומטי את התוכן של מחיצות לוגיות, כלומר הוא מכיל את system.img,‏ vendor.img וכן הלאה, בנוסף למטא-נתונים של המחיצה super. אפשר להטמיע את הקובץ הזה ישירות במחיצה super בלי כלים נוספים או באמצעות fastbootd. אחרי ה-build, הקובץ super.img מועבר ל-${ANDROID_PRODUCT_OUT}.

במכשירי A/B שמופעלים עם מחיצות דינמיות, התמונות נמצאות ב-super.img בחריץ A. אחרי שמיישמים את קובץ האימג' הסופר ישירות, מסמנים את חריץ A כחריץ שניתן לאתחול לפני שמפעילים מחדש את המכשיר.

במכשירים מותאמים מחדש, make dist יוצר קבוצה של קובצי אימג' של super_*.img שאפשר להטמיע ישירות במחיצות הפיזיות התואמות. לדוגמה, make dist יוצר את super_system.img ואת super_vendor.img כש-BOARD_SUPER_PARTITION_BLOCK_DEVICES הוא ספק המערכת. התמונות האלה נמצאות בתיקיית OTA ב-target_files.zip.

התאמת מכשיר האחסון של Device Mapper

חלוקה דינמית מתאימה למספר אובייקטים של device-mapper לא ודאיים. יכול להיות שלא כל ההתקנות יתבצעו כצפוי, לכן צריך לעקוב אחרי כל החיבורים ולעדכן את מאפייני Android של כל המחיצות המשויכות עם מכשירי האחסון הבסיסיים שלהן.

מנגנון ב-init עוקב אחרי החיבורים ומעדכן את מאפייני Android באופן אסינכרוני. אין ערובה שהתהליך יימשך פרק זמן מסוים, לכן צריך להמתין מספיק זמן כדי שכל הטריגרים של on property יגיבו. המאפיינים הם dev.mnt.blk.<partition>, כאשר <partition> הוא root, ‏ system, ‏ data או vendor, לדוגמה. כל מאפיין משויך לשם הבסיסי של מכשיר האחסון, כפי שמוצג בדוגמאות הבאות:

taimen:/ % getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [sda]
[dev.mnt.blk.firmware]: [sde]
[dev.mnt.blk.metadata]: [sde]
[dev.mnt.blk.persist]: [sda]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.vendor]: [dm-1]

blueline:/ $ getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [dm-4]
[dev.mnt.blk.metadata]: [sda]
[dev.mnt.blk.mnt.scratch]: [sda]
[dev.mnt.blk.mnt.vendor.persist]: [sdf]
[dev.mnt.blk.product]: [dm-2]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.system_ext]: [dm-3]
[dev.mnt.blk.vendor]: [dm-1]
[dev.mnt.blk.vendor.firmware_mnt]: [sda]

השפה init.rc מאפשרת להרחיב את המאפיינים של Android כחלק מהכללים, והפלטפורמה יכולה לשפר את מכשירי האחסון לפי הצורך באמצעות פקודות כמו:

write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128

אחרי שתהליך עיבוד הפקודה מתחיל בשלב השני init, ה-epoll loop הופך לפעיל והערכים מתחילים להתעדכן. עם זאת, מכיוון שהטריגרים של הנכס לא פעילים עד סוף init, אי אפשר להשתמש בהם בשלבים הראשונים של האתחול כדי לטפל ב-root, ב-system או ב-vendor. ברירת המחדל של הליבה read_ahead_kb אמורה להספיק עד שסקריפטים של init.rc יוכלו לשנות את ההגדרה ב-early-fs (כששירותים דמונים ומתקנים שונים מתחילים לפעול). לכן, Google ממליצה להשתמש בתכונה on property בשילוב עם מאפיין שנשלט על ידי init.rc, כמו sys.read_ahead_kb, כדי לקבוע את תזמון הפעולות ולמנוע תנאי מרוץ, כמו בדוגמאות הבאות:

on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on early-fs:
    setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048}

on property:sys.boot_completed=1
   setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}