חלוקה דינמית מיושמת באמצעות המודול 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 מציג טבלת מחיצות לדוגמה לפני ואחרי ההמרה למחיצות דינמיות.
המחיצות הדינמיות הנתמכות הן:
- מערכת
- ספק
- מוצר
- 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 מוטמעת במחולל האתחול, צריך לכלול את התיקונים הבאים:
- 818cf56740775446285466eda984acedd4baeac0 — "libavb: Only query partition GUIDs when the cmdline needs them".
- 5abd6bc2578968d24406d834471adfd995a0c2e9 — 'Allow system partition to be absent'
- 9ba3b6613b4e5130fa01a11d984c6b5f0eb3af05 – "תיקון AvbSlotVerifyData->cmdline עשוי להיות NULL"
אם משתמשים במחיצות מקושרות, צריך לכלול תיקון נוסף:
- 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
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}