החלוקה הדינמית למחיצות מיושמת באמצעות מודול מיפוי המכשירים dm-linear בליבת 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 מציג דוגמה לטבלת מחיצות לפני ואחרי המרה למחיצות דינמיות.

המחיצות הדינמיות הנתמכות הן:
- מערכת
- ספק
- מוצר
- System Ext
- ODM
במכשירים עם Android 10, האפשרות בשורת הפקודה של ליבת
androidboot.super_partition
צריכה להיות ריקה, כך שהפקודה sysprop
ro.boot.super_partition
תהיה ריקה.
יישור המחיצה
יכול להיות שהמודול device-mapper יפעל בצורה פחות יעילה אם המחיצה super
לא מיושרת כראוי. המחיצה super
חייבת להיות מיושרת לגודל המינימלי של בקשת קלט/פלט, כפי שנקבע על ידי שכבת הבלוקים. כברירת מחדל, מערכת הבנייה (באמצעות lpmake
, שמפיקה את תמונת המחיצה super
) מניחה שיישור של 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
– תקורה - בזמן הבנייה, סכום הגדלים של התמונות של כל מחיצה בקבוצת עדכון לא יכול לחרוג מהגודל המקסימלי של הקבוצה.
- התקורה נדרשת בחישוב כדי להביא בחשבון מטא-נתונים, התאמות וכו'. תקורה סבירה היא 4 MiB, אבל אפשר לבחור תקורה גדולה יותר לפי הצורך של המכשיר.
שינוי הגודל של מחיצות דינמיות
לפני שהיו מחיצות דינמיות, גודל המחיצות היה גדול מדי כדי לוודא שיש מספיק מקום לעדכונים עתידיים. הגודל בפועל נלקח כמו שהוא, ולרוב המחיצות לקריאה בלבד היה נפח אחסון פנוי במערכת הקבצים. במחיצות דינמיות, אי אפשר להשתמש בשטח הפנוי הזה, ואפשר להשתמש בו כדי להגדיל את המחיצות במהלך עדכון OTA. חשוב מאוד לוודא שהמחיצות לא מבזבזות מקום ושהן מוקצות לגודל המינימלי האפשרי.
בתמונות ext4 לקריאה בלבד, מערכת ה-build מקצה באופן אוטומטי את הגודל המינימלי אם לא מצוין גודל מחיצה שמוגדר בהארדקוד. מערכת ה-build מתאימה את התמונה כך שבמערכת הקבצים יהיה כמה שפחות שטח לא מנוצל. כך אפשר לוודא שלא יבוזבז במכשיר מקום שאפשר להשתמש בו לעדכונים.
בנוסף, אפשר לדחוס עוד יותר תמונות ext4 על ידי הפעלת ביטול כפילויות ברמת הבלוק (block- ). כדי להפעיל את ההגדרה הזו, משתמשים בתצורה הבאה:
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 של מקום אחסון שלא בשימוש.
שינויים ב-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
גורמת לשגיאת בנייה כשגם PRODUCT_USE_DYNAMIC_PARTITIONS
מוגדר ל-true
.
כשהערך של BOARD_USES_RECOVERY_AS_BOOT
הוא true, תמונת השחזור נוצרת כ-boot.img, שמכילה את ה-ramdisk של השחזור. בעבר, טוען האתחול השתמש בפרמטר skip_initramfs
של שורת הפקודה של ליבת המערכת כדי להחליט באיזה מצב לבצע אתחול. במכשירי Android 10, טוען האתחול לא יכול להעביר את skip_initramfs
לשורת הפקודה של ליבת המערכת. במקום זאת, טוען האתחול צריך להעביר androidboot.force_normal_boot=1
כדי לדלג על השחזור ולהפעיל את Android כרגיל. במכשירים שהושקו עם Android מגרסה 12 ואילך, צריך להשתמש ב-bootconfig כדי להעביר את androidboot.force_normal_boot=1
.
שינויים בהגדרות של AVB
אם משתמשים ב-Android Verified Boot 2.0, ולא משתמשים בchained partition descriptors, אין צורך לבצע שינוי. אבל אם משתמשים במחיצות בשרשרת ואחת מהמחיצות המאומתות היא דינמית, צריך לבצע שינויים.
דוגמה להגדרה של מכשיר שמשתמש בשרשור
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
footer בסוף המחיצות 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
אם ב-bootloader מוטמעת libavb, צריך לכלול את התיקונים הבאים:
- 818cf56740775446285466eda984acedd4baeac0 — "libavb: Only query partition GUIDs when the cmdline needs them."
- 5abd6bc2578968d24406d834471adfd995a0c2e9 — "Allow system partition to be absent"
- 9ba3b6613b4e5130fa01a11d984c6b5f0eb3af05 — "Fix AvbSlotVerifyData->cmdline might be NULL"
אם משתמשים במחיצות משורשרות, צריך לכלול תיקון נוסף:
- 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — "libavb: Support vbmeta blobs in beginning of partition."
שינויים בשורת הפקודה של הליבה
צריך להוסיף פרמטר חדש, androidboot.boot_devices
, לשורת הפקודה של ליבת המערכת. המשתנה הזה משמש את init
כדי להפעיל קישורי symlink של /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
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
כדגלavb=vbmeta partition name
, ואז מחיצתvbmeta
שצוינה מאותחלת על ידי שלבinit
לפני שמנסים לטעון מכשירים כלשהם.fs_mgr
-
השדה
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
למפתחים שמשתמשים בגרסאות 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;
הגדרות נוספות מפורטות במאמר הטמעה של מחיצות דינמיות במכשירים חדשים.
מידע נוסף על עדכוני Retrofit אפשר למצוא במאמר בנושא 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
.
התאמה של מכשיר אחסון באמצעות מיפוי מכשירים
חלוקה דינמית מאפשרת להשתמש במספר אובייקטים לא דטרמיניסטיים של מיפוי מכשירים. יכול להיות שלא כל המחיצות יופעלו כמו שצריך, ולכן צריך לעקוב אחרי כל ההרכבות ולעדכן את מאפייני 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
הופך לפעיל והערכים מתחילים להתעדכן. עם זאת, אי אפשר להשתמש בהם בשלבי האתחול הראשוניים כדי לטפל ב-root
, ב-system
או ב-vendor
, כי הטריגרים של הנכס לא פעילים עד סוף init
. אפשר לצפות שברירת המחדל של ליבת 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}