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

חלוקה דינמית מיושמת באמצעות המודול 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, האפשרות של שורת הפקודה בליבה (kernel) androidboot.super_partition חייבת להיות ריקה, כך שהפקודה syspro ro.boot.super_partition תהיה ריקה.

יישור מחיצות

יכול להיות שהמודול של מיפוי המכשירים יפעל פחות ביעילות אם המחיצה super לא מיושרת כמו שצריך. מחיצה 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 – תקורה
  • במכשירים שאינם 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 של השחזור. בעבר, מנהל האתחול השתמש בפרמטר שורת הפקודה skip_initramfs של הליבה כדי להחליט באיזה מצב להפעיל את המכשיר. במכשירי Android 10, אסור שה-bootloader יעביר את הערך skip_initramfs לשורת הפקודה של הליבה. במקום זאת, bootloader צריך להעביר את androidboot.force_normal_boot=1 כדי לדלג על התהליך של שחזור ולהפעיל את Android הרגיל. מכשירים שמותקנת בהם מערכת ההפעלה Android בגרסה 12 ואילך חייבים להשתמש בהגדרת אתחול כדי להעביר את 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 מוטמעת במחולל האתחול, צריך לכלול את התיקונים הבאים:

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

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: תמיכה ב-vbmeta blobs בתחילת חלוקת".

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

צריך להוסיף פרמטר חדש, 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 חייב לכלול את הדגל 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 to User Space.

adb remount

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

למידע נוסף על הפעלה של שכבות-על, ראו overlayfs README ב-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 לא ודאיים. יכול להיות שלא כל ההתקנות יתבצעו כצפוי, לכן צריך לעקוב אחרי כל החיבורים ולעדכן את מאפייני 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}