מחיצת אתחול כללית

ב-Android 12, קובץ האימג' הגנרי boot, שנקרא Generic Kernel Image‏ (GKI), מכיל את ה-ramdisk הגנרי ואת הליבה של GKI.

במכשירים שיושקו עם Android 13, דיסק ה-RAM הגנרי יוסר מהקובץ boot ויוצג בקובץ init_boot נפרד. בעקבות השינוי הזה, בתמונת boot נשאר רק הליבה של GKI.

כשמשדרגים מכשירים שממשיכים להשתמש ב-Android 12 או בגרסאות ליבה ישנות יותר, דיסק ה-RAM הגנרי נשאר במקום שבו הוא היה, ללא צורך בתמונה חדשה של init_boot.

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

במכשירים שבהם:

  • אין להשתמש במחיצה ייעודית של recovery, כל הביטים של השחזור מועברים מ-ramdisk הגנרי ל-ramdisk של vendor_boot.

  • מומלץ להשתמש במחיצה ייעודית של recovery, אין צורך לבצע שינויים ב-ramdisk של recovery כי ה-ramdisk של recovery הוא עצמאי.

ארכיטקטורה

התרשימים הבאים מדגימים את הארכיטקטורה של מכשירים עם Android 12 ואילך. במכשירים שמופעלת בהם מערכת ההפעלה Android 13 יש קובץ אימג' חדש של init_boot שמכיל את ה-ramdisk הגנרי. במכשירים שמשודרגים מ-Android 12 ל-Android 13 נעשה שימוש באותה ארכיטקטורה כמו ב-Android 12.

הפעלה עם Android 13, ללא שחזור ייעודי

הפעלה/שדרוג של מכשיר, GKI, ללא שחזור ייעודי

איור 1. מכשירים שמריצים את Android 13 או משודרגים אליו, עם GKI, ללא שחזור ייעודי.

הפעלה עם Android 13, שחזור ייעודי ו-A/B (ramdisk ייעודי)

הפעלה/שדרוג של מכשיר, GKI, שחזור ייעודי ושחזור A/B

איור 2. מכשירים שהושקתם או ששודרגו ל-Android 13, עם GKI, שחזור ייעודי ושחזור A/B.

יש להיעזר באיור הזה אם במכשיר יש מחיצות recovery_a ו-recovery_b.

הפעלה עם Android 13, שחזור ייעודי ולא A/B (ramdisk ייעודי)

הפעלה/שדרוג של מכשיר, GKI, שחזור ייעודי ולא שחזור A/B

איור 3. מכשירים שהושקתם או שודרגו ל-Android 13, עם GKI, שחזור ייעודי ולא שחזור A/B.

יש להיעזר באיור הזה אם במכשיר יש מחיצה בשם recovery ללא סיומת של חריץ.

הפעלה או שדרוג ל-Android 12, ללא שחזור ייעודי

הפעלה/שדרוג של מכשיר, GKI, ללא שחזור ייעודי

איור 4. מכשירים שהושקעו עם Android 12 או שודרגו ל-Android 12, עם GKI, ללא שחזור ייעודי.

הפעלה או שדרוג ל-Android 12, שחזור ייעודי ו-A/B (ramdisk ייעודי)

הפעלה/שדרוג של מכשיר, GKI, שחזור ייעודי ושחזור A/B

איור 5. מכשירי Android 12 או מכשירי Android 12 משודרגים עם GKI, שחזור ייעודי ושחזור A/B.

יש להיעזר באיור הזה אם במכשיר יש מחיצות recovery_a ו-recovery_b.

הפעלה או שדרוג ל-Android 12, שחזור ייעודי ולא A/B (ramdisk ייעודי)

הפעלה/שדרוג של מכשיר, GKI, שחזור ייעודי ולא שחזור A/B

איור 6. מכשירים שמריצים את Android 12 או משודרגים אליו, עם GKI ושחזור ייעודי שאינו A/B.

יש להיעזר באיור הזה אם במכשיר יש מחיצה בשם recovery ללא סיומת של חריץ.

שדרוג ל-Android 12, recovery-as-boot‏ (recovery-as-ramdisk)

הפעלה/שדרוג של מכשיר, ללא GKI, שחזור כמצב הפעלה

איור 7. מכשירים שעוברים שדרוג ל-Android 12, ללא GKI, שחזור כמצב הפעלה.

שדרוג ל-Android 12, שחזור ייעודי (ramdisk ייעודי)

הפעלה/שדרוג של מכשיר, ללא GKI, שחזור ייעודי

איור 8. מכשירים שעוברים שדרוג ל-Android 12, ללא GKI, שחזור ייעודי.

התוכן של קובצי אימג' לאתחול

קובצי האימג' להפעלה של Android מכילים את הפריטים הבאים.

  • נוספה תמונה של init_boot למכשירים שיושקו עם Android 13

    • גרסת הכותרת V4
    • תמונת ramdisk גנרית
  • תמונה גנרית של boot

    • גרסת הכותרת V3 או V4
      • boot_signature לאישור boot.img של GKI (גרסה 4 בלבד). ה-GKI המאושר boot.img לא חתום להפעלה מאומתת. יצרני ציוד מקורי עדיין צריכים לחתום על קובץ ה-boot.img שנוצר מראש באמצעות מפתח AVB ספציפי למכשיר.
      • cmdline גנרי (GENERIC_KERNEL_CMDLINE)
      • ליבה של GKI
    • תמונת ramdisk גנרית
      • התכונה כלולה רק בתמונות של boot מ-Android 12 ואילך
  • קובץ אימג' של vendor_boot (פרטים נוספים זמינים במאמר מחיצות אתחול של ספקים)

    • vendor_boot header
      • cmdline ספציפי למכשיר (BOARD_KERNEL_CMDLINE)
    • קובץ אימג' של vendor_boot ramdisk
      • lib/modules
      • משאבי שחזור (אם אין שחזור ייעודי)
    • תמונה אחת (dtb)
  • תמונה אחת (recovery)

    • Header version V2
      • cmdline ספציפי למכשיר לצורך שחזור, אם יש צורך
      • במחיצה לא לשחזור A/B, תוכן הכותרת חייב להיות עצמאי. מידע נוסף זמין במאמר תמונות שחזור. לדוגמה:
      • cmdline לא מקושר ל-boot ול-vendor_boot cmdline.
      • הכותרת מציינת את DTBO לשחזור, אם יש צורך.
      • במחיצה לשחזור A/B, אפשר לשרשר את התוכן או להסיק אותו מ-boot ו-vendor_boot. לדוגמה:
      • cmdline מקושר ל-boot ול-vendor_boot cmdline.
      • אפשר להסיק את DTBO מהכותרת vendor_boot.
    • קובץ אימג' של recovery ramdisk
      • משאבים לשחזור
      • במחיצה לא לשחזור מסוג A/B, התוכן של ה-ramdisk חייב להיות עצמאי. אפשר לקרוא מידע נוסף במאמר תמונות שחזור. לדוגמה:
      • lib/modules חייב להכיל את כל המודולים של הליבה שנדרשים להפעלת מצב השחזור
      • דיסק ה-RAM של התאוששות חייב להכיל את init.
      • במחיצה לשחזור A/B, ה-ramdisk לשחזור מצורף ל-ramdisk הגנרי ול-vendor_boot, ולכן הוא לא צריך להיות עצמאי. לדוגמה:
      • lib/modules יכול להכיל רק מודולים נוספים של ליבה שנדרשים כדי להפעיל את מצב השחזור, בנוסף למודולים של הליבה ב-vendor_boot ramdisk.
      • יכול להיות שהקישור הלא פורמלי ב-/init קיים, אבל הוא מוסתר על ידי הקובץ הבינארי של /init בשלב הראשון בתמונת האתחול.

תוכן תמונה גנרי של דיסק RAM

דיסק ה-RAM הגנרי מכיל את הרכיבים הבאים.

  • init
  • system/etc/ramdisk/build.prop
  • ro.PRODUCT.bootimg.* build אביזרי תפאורה
  • ספריות ריקות לנקודות הצמדה: debug_ramdisk/, ‏ mnt/, ‏ dev/, ‏ sys/,‏ proc/, ‏ metadata/
  • first_stage_ramdisk/
    • ספריות ריקות כפולות בנקודות הטעינה: debug_ramdisk/, ‏ mnt/,‏ dev/, ‏ sys/, ‏ proc/, ‏ metadata/

שילוב של קובץ אימג' לאתחול

דגלים של build קובעים איך יוצרים את קובצי האימג' של init_boot,‏ boot,‏ recovery ו-vendor_boot. הערך של משתנה לוח בוליאני חייב להיות המחרוזת true או להיות ריק (זהו ערך ברירת המחדל).

  • TARGET_NO_KERNEL. המשתנה הזה מציין אם ב-build נעשה שימוש בתמונת אתחול שנוצרה מראש. אם המשתנה הזה מוגדר כ-true, צריך להגדיר את BOARD_PREBUILT_BOOTIMAGE למיקום של קובץ האימג' המובנה מראש להפעלה (BOARD_PREBUILT_BOOTIMAGE:= device/${company}/${board}/boot.img)

  • BOARD_USES_RECOVERY_AS_BOOT. המשתנה הזה מציין אם המכשיר משתמש בתמונה recovery בתור התמונה boot. כשמשתמשים ב-GKI, המשתנה הזה ריק וצריך להעביר את משאבי השחזור אל vendor_boot.

  • BOARD_USES_GENERIC_KERNEL_IMAGE. המשתנה הזה מציין שהלוח משתמש ב-GKI. המשתנה הזה לא משפיע על sysprops או על PRODUCT_PACKAGES.

    זהו המתג של GKI ברמת הלוח. כל המשתנים הבאים מוגבלים על ידי המשתנה הזה.

  • BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT. המשתנה הזה קובע אם משאבי שחזור של דיסק RAM נוצרים ב-vendor_boot.

    • כשהערך מוגדר ל-true, משאבי השחזור נוצרים ל-vendor-ramdisk/ בלבד ולא נוצרים ל-recovery/root/.

    • אם השדה ריק, משאבי השחזור ייוצרו רק ל-recovery/root/ ולא ל-vendor-ramdisk/.

  • BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT. המשתנה הזה קובע אם מפתחות GSI AVB נוצרים ב-vendor_boot.

    • כשהיא מוגדרת כ-true, אם BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT:

      • מוגדרת, מפתחות GSI AVB נוצרים לפי $ANDROID_PRODUCT_OUT/vendor-ramdisk/first_stage_ramdisk/avb.

      • אם לא מוגדר, מפתחות GSI AVB נוצרים ל-$ANDROID_PRODUCT_OUT/vendor-ramdisk/avb.

    • כשהשדה ריק, אם BOARD_RECOVERY_AS_ROOT:

      • מפתחות GSI AVB נוצרים לפי $ANDROID_PRODUCT_OUT/recovery/root/first_stage_ramdisk/avb.

      • אם לא מוגדר, מפתחות GSI AVB נוצרים ל-$ANDROID_PRODUCT_OUT/ramdisk/avb.

  • BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE. המשתנה הזה קובע אם קובץ האימג' recovery מכיל ליבה או לא. במכשירים שמריצים Android 12 ומשתמשים במחיצה recovery של A/B, צריך להגדיר את המשתנה הזה ל-true. במכשירים שהושקעו עם Android 12 ומשתמשים ב-A/B, צריך להגדיר את המשתנה הזה ל-false כדי שתמונת השחזור תהיה עצמאית.

  • BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES. המשתנה הזה קובע אם $OUT/boot*.img יועתק אל IMAGES/ בקובצי היעד.

    • aosp_arm64 חייב להגדיר את המשתנה הזה לערך true.

    • במכשירים אחרים, צריך להשאיר את המשתנה הזה ריק.

  • BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE. המשתנה הזה קובע אם init_boot.img נוצר ומגדיר את הגודל. כשמגדירים את האפשרות הזו, ה-ramdisk הגנרי מתווסף ל-init_boot.img במקום ל-boot.img, וצריך להגדיר את המשתנים BOARD_AVB_INIT_BOOT* עבור chained vbmeta.

שילובים מותרים

רכיב או משתנה שדרוג המכשיר בלי מחיצה לשחזור שדרוג המכשיר באמצעות מחיצה לשחזור הפעלת המכשיר ללא מחיצה לשחזור הפעלת המכשיר באמצעות מחיצה לשחזור A/B הפעלת מכשיר עם מחיצה לא לשחזור מסוג A/B aosp_arm64
מכיל את boot כן כן כן כן כן כן
מכיל את init_boot (Android 13) לא לא כן כן כן כן
מכיל את vendor_boot אופציונלי אופציונלי כן כן כן לא
מכיל את recovery לא כן לא כן כן לא
BOARD_USES_RECOVERY_AS_BOOT true ריק ריק ריק ריק ריק
BOARD_USES_GENERIC_KERNEL_IMAGE ריק ריק true true true true
PRODUCT_BUILD_RECOVERY_IMAGE ריק true או ריק ריק true או ריק true או ריק ריק
BOARD_RECOVERYIMAGE_PARTITION_SIZE ריק > 0 ריק > 0 > 0 ריק
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT ריק ריק true ריק ריק ריק
BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT ריק ריק true true true ריק
BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE ריק ריק ריק true ריק ריק
BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES ריק ריק ריק ריק ריק true

במכשירים עם מחיצה ייעודית של recovery, אפשר להגדיר את PRODUCT_BUILD_RECOVERY_IMAGE כ-true או כרייק. במכשירים האלה, אם מגדירים את BOARD_RECOVERYIMAGE_PARTITION_SIZE, נוצרת קובץ אימג' של recovery.

הפעלת vbmeta בשרשור להפעלה

צריך להפעיל את vbmeta המקושר בתמונות boot ו-init_boot. מציינים את הפרטים הבאים:

BOARD_AVB_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_BOOT_ALGORITHM := SHA256_RSA4096
BOARD_AVB_BOOT_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_BOOT_ROLLBACK_INDEX_LOCATION := 2

BOARD_AVB_INIT_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_INIT_BOOT_ALGORITHM := SHA256_RSA2048
BOARD_AVB_INIT_BOOT_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_INIT_BOOT_ROLLBACK_INDEX_LOCATION := 3

דוגמה לכך מופיעה כאן.

System-as-root

אין תמיכה ב-System-as-root במכשירים שמשתמשים ב-GKI. במכשירים כאלה, השדה BOARD_BUILD_SYSTEM_ROOT_IMAGE חייב להיות ריק. בנוסף, לא ניתן להשתמש ב-System-as-root במכשירים שמשתמשים במחיצות דינמיות.

הגדרות מוצרים

במכשירים שמשתמשים ב-ramdisk הגנרי צריך להתקין רשימה של קבצים שמותר להתקין ב-ramdisk. כדי לעשות זאת, צריך לציין את הפרטים הבאים ב-device.mk:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)

הקובץ generic_ramdisk.mk גם מונע מקובצי makefile אחרים להתקין בטעות קבצים אחרים בדיסק ה-RAM (במקום זאת, צריך להעביר קבצים כאלה לקובץ vendor_ramdisk).

הגדרת מכשירים

הוראות ההגדרה משתנות בהתאם למכשירים שהושקו עם Android 13, למכשירים ששודרגו ל-Android 12 ולמכשירים שהושקו עם Android 12. Android 13, ההגדרה דומה לאופן שבו היא הייתה ב-Android 12

  • במכשירים שמשודרגים ל-Android 12:

    • אפשר לשמור את הערך של BOARD_USES_RECOVERY_AS_BOOT. אם הם עושים זאת, הם משתמשים בהגדרות מדור קודם, ומשתני ה-build החדשים חייבים להיות ריקים. אם המכשירים האלה:

      • מגדירים את BOARD_USES_RECOVERY_AS_BOOT ל-true, הארכיטקטורה היא כפי שמוצג באיור 3.

      • מגדירים את BOARD_USES_RECOVERY_AS_BOOT כריק, והארכיטקטורה נראית כמו באיור 4.

    • אפשר להגדיר את BOARD_USES_RECOVERY_AS_BOOT כערך ריק. אם הם עושים זאת, הם משתמשים בתצורות חדשות. אם מכשירים כאלה:

      • לא משתמשים במחיצה ייעודית של recovery, הארכיטקטורה היא כפי שמוצגת באיור 1 והאפשרות להגדרת המכשיר היא אפשרות 1.

      • משתמשים במחיצה recovery ייעודית, הארכיטקטורה היא כפי שמוצגת באיור 2a או באיור 2b, ואפשרות ההגדרה של המכשיר היא אפשרות 2a או אפשרות 2b.

  • במכשירים שיושקו עם Android 12, צריך להגדיר את BOARD_USES_RECOVERY_AS_BOOT כריק ולהשתמש בהגדרות אישיות חדשות. אם המכשירים האלה:

    • לא משתמשים במחיצה ייעודית של recovery, הארכיטקטורה היא כפי שמוצג באיור 1 ואפשרות ההגדרה של המכשיר היא אפשרות 1.

    • משתמשים במחיצה recovery ייעודית, הארכיטקטורה היא כפי שמוצגת באיור 2a או באיור 2b, ואפשרות ההגדרה של המכשיר היא אפשרות 2a או אפשרות 2b.

מכיוון ש-aosp_arm64 יוצר רק GKI (ולא vendor_boot או שחזור), הוא לא יעד מלא. להגדרות build של aosp_arm64, אפשר לעיין במאמר generic_arm64.

אפשרות 1: ללא מחיצה ייעודית לשחזור

במכשירים ללא מחיצה recovery, התמונה הגנרית boot נמצאת במחיצה boot. דיסק ה-RAM‏ vendor_boot מכיל את כל משאבי השחזור, כולל lib/modules (עם מודולים של ליבה של ספקים). במכשירים כאלה, הגדרות המוצר יורשות מ-generic_ramdisk.mk.

הגדרת ערכים של BOARD

מגדירים את הערכים הבאים:

BOARD_USES_RECOVERY_AS_BOOT :=
BOARD_USES_GENERIC_KERNEL_IMAGE := true
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT := true
BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE :=
BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT := true

דיסק ה-RAM‏ vendor_boot יכול להכיל קישור סמלי מ-/init אל /system/bin/init, ו-init_second_stage.recovery ב-/system/bin/init. עם זאת, מכיוון שה-ramdisk הגנרי מקושר אחרי ה-ramdisk של vendor_boot, ה-symlink של /init נכתב מחדש. כשהמכשיר מופעל במצב שחזור, הקובץ הבינארי /system/bin/init נדרש כדי לתמוך בהפעלה של השלב השני. התוכן של vendor_boot + דיסקים זיכרון כלליים הוא:

  • /init (מ-ramdisk כללי, שנוצר מ-init_first_stage)
  • /system/bin/init (מ-vendor_ramdisk, שנוצר מ-init_second_stage.recovery)

העברת קובצי fstab

מעבירים את כל הקבצים מסוג fstab שהותקנו ב-ramdisk הגנרי אל vendor_ramdisk. דוגמה לכך מופיעה כאן.

התקנת מודולים

אפשר להתקין ב-vendor_ramdisk מודולים ספציפיים למכשיר (אפשר לדלג על השלב הזה אם אין לכם מודולים ספציפיים למכשיר להתקנה).

  • כשמתקינים את המודול ב-/first_stage_ramdisk, צריך להשתמש בגרסה vendor_ramdisk שלו. המודול הזה אמור להיות זמין אחרי ש-init מעביר את ה-root ל-/first_stage_ramdisk, אבל לפני ש-init מעביר את ה-root ל-/system. דוגמאות לכך הן סיכומי ביקורת של מטא-נתונים ודחיסת A/B וירטואלית.

  • משתמשים בגרסה recovery של המודול כשהמודול מתקין ב-/. המודול הזה צריך להיות זמין לפני ש-init מעביר את ה-root ל-/first_stage_ramdisk. פרטים על התקנת מודולים ב-/ מופיעים במאמר מסוף שלב ראשון.

מסוף שלב ראשון

מכיוון שמסוף השלב הראשון מתחיל לפעול לפני ש-init מעביר את root ל-/first_stage_ramdisk, צריך להתקין את הווריאנט recovery של המודולים. כברירת מחדל, שתי הווריאציות של המודול מותקנות ב-build/make/target/product/base_vendor.mk, כך שאם קובץ ה-makefile של המכשיר עובר בירושה מהקובץ הזה, אין צורך להתקין את הווריאנט recovery באופן מפורש.

כדי להתקין את מודולי השחזור באופן מפורש, משתמשים בפקודה הבאה.

PRODUCT_PACKAGES += \
    linker.recovery \
    shell_and_utilities_recovery \

כך אפשר לוודא שההתקנה של linker,‏ sh ו-toybox תתבצע ב-$ANDROID_PRODUCT_OUT/recovery/root/system/bin, ולאחר מכן ההתקנה תתבצע ב-/system/bin בקטע vendor_ramdisk.

כדי להוסיף מודולים שנדרשים למסוף של השלב הראשון (לדוגמה, adbd), משתמשים בקוד הבא.

PRODUCT_PACKAGES += adbd.recovery

כך מוודאים שהמודולים שצוינו יותקנו ב-$ANDROID_PRODUCT_OUT/recovery/root/system/bin, ולאחר מכן יותקנו ב-/system/bin בקטע vendor_ramdisk.

סיכומי ביקורת של מטא-נתונים

כדי לתמוך בסיכומי ביקורת של מטא-נתונים במהלך הרכבת השלב הראשון, במכשירים שלא תומכים ב-GKI מותקנת הגרסה של המודולים הבאים ל-ramdisk. כדי להוסיף תמיכה ב-GKI, מעבירים את המודולים אל $ANDROID_PRODUCT_OUT/vendor-ramdisk/first_stage_ramdisk/system/bin:

PRODUCT_PACKAGES += \
    linker.vendor_ramdisk \
    resize2fs.vendor_ramdisk \
    tune2fs.vendor_ramdisk \

דוגמה לכך מופיעה ברשימת השינויים הזו.

דחיסת A/B וירטואלית

כדי לתמוך בדחיסה וירטואלית של A/B, צריך להתקין את snapuserd ב-vendor_ramdisk. המכשיר אמור לרשת מ-virtual_ab_ota/compression.mk, שמתקין את הווריאנט vendor_ramdisk של snapuserd.

שינויים בתהליך האתחול

תהליך האתחול למצב שחזור או ל-Android לא משתנה, מלבד החריג הבא:

  • דיסק ה-RAM build.prop עובר אל /second_stage_resources כדי שאפשר יהיה לקרוא את חותמת הזמן של ה-build של האתחול בשלב השני init.

מאחר שהמשאבים מועברים מ-ramdisk גנרי ל-ramdisk של vendor_boot, התוצאה של שרשור ה-ramdisk הגנרי ל-ramdisk של vendor_boot לא משתנה.

הפעלת e2fsck

קובצי ה-makefile של המכשיר יכולים לרשת מ:

  • virtual_ab_ota/launch_with_vendor_ramdisk.mk אם המכשיר תומך ב-A/B וירטואלי אבל לא בהצפנה.

  • virtual_ab_ota/compression.mk אם המכשיר תומך בווירטואליזציה של דחיסת A/B.

קובצי ה-makefile של המוצר מתקינים את $ANDROID_PRODUCT_OUT/vendor-ramdisk/first_stage_ramdisk/system/bin/e2fsck. במהלך זמן הריצה, השלב הראשון init מעביר את root ל-/first_stage_ramdisk ואז מבצע את /system/bin/e2fsck.

אפשרות 2a: מחיצה ייעודית לשחזור A/B

אפשר להשתמש באפשרות הזו במכשירים עם מחיצות recovery מסוג A/B, כלומר במכשירים שיש בהם מחיצה recovery_a וגם מחיצה recovery_b partition. מכשירים כאלה כוללים מכשירי A/B ומכשירי A/B וירטואליים שבהם אפשר לעדכן את מחיצת השחזור, עם ההגדרות הבאות:

AB_OTA_PARTITIONS += recovery

דיסק ה-RAM‏ vendor_boot מכיל את הביטים של הספק של דיסק ה-RAM ושל מודולי הליבה של הספק, כולל:

  • קבצים fstab ספציפיים למכשיר

  • lib/modules (כולל מודולים של ליבה של ספקים)

דיסק ה-RAM‏ recovery מכיל את כל משאבי השחזור. במכשירים כאלה, הגדרות המוצר יורשות מ-generic_ramdisk.mk.

הגדרת ערכים של BOARD

מגדירים את הערכים הבאים למכשירים עם מחיצה recovery של A/B:

BOARD_USES_RECOVERY_AS_BOOT :=
BOARD_USES_GENERIC_KERNEL_IMAGE := true
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT :=
BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE := true
BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT := true

דיסק ה-RAM‏ recovery יכול להכיל קישור ל-/init -> /system/bin/init, ו-init_second_stage.recovery ב-/system/bin/init. עם זאת, מכיוון ש-ramdisk של האתחול מקושר אחרי ה-ramdisk של recovery, הקישור הלא ישיר (symlink) של /init נמחק. כשהמכשיר מופעל במצב שחזור, הקבצים הבינאריים של /system/bin/init נדרשים כדי לתמוך בהפעלה הראשונית של השלב השני.

כשהמכשיר מופעל ב-recovery, התוכן של recovery + vendor_boot + דיסקים רגילים של זיכרון RAM הוא:

  • /init (מ-ramdisk, נוצר מ-init_first_stage)
  • /system/bin/init (מ-ramdisk של recovery, שנוצר מ-init_second_stage.recovery ומופעל מ-/init)

כשהמכשיר מופעל ל-Android, התוכן של vendor_boot + generic ramdisks הוא:

  • /init (מ-ramdisk כללי, שנוצר מ-init_first_stage)

העברת קובצי fstab

מעבירים את כל הקבצים מסוג fstab שהותקנו ב-ramdisk הגנרי אל vendor_ramdisk. דוגמה לכך מופיעה כאן.

התקנת מודולים

אפשר גם להתקין ב-vendor_ramdisk מודולים ספציפיים למכשיר (אפשר לדלג על השלב הזה אם אין לכם מודולים ספציפיים למכשיר להתקנה). Init לא מחליף את הרשאת root. וריאנט vendor_ramdisk של המודולים מתקין את המודולים ברמה הבסיסית של vendor_ramdisk. דוגמאות להתקנת מודולים ב-vendor_ramdisk מפורטות במאמרים מסוף שלב ראשון, סיכומי ביקורת של מטא-נתונים ודחיסת A/B וירטואלית.

מסוף שלב ראשון

כדי להתקין את הווריאנט vendor_ramdisk של המודולים, משתמשים באפשרות הבאה:

PRODUCT_PACKAGES += \
    linker.vendor_ramdisk \
    shell_and_utilities_vendor_ramdisk \

כך אפשר לוודא שההתקנה של linker,‏ sh ו-toybox תתבצע ב-$ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin, ולאחר מכן ההתקנה תתבצע ב-/system/bin בקטע vendor_ramdisk.

כדי להוסיף מודולים שנדרשים למסוף של השלב הראשון (לדוגמה, adbd), מפעילים את הווריאנט vendor_ramdisk של המודולים האלה על ידי העלאת התיקונים הרלוונטיים ל-AOSP, ואז משתמשים בקוד הבא:

PRODUCT_PACKAGES += adbd.vendor_ramdisk

כך מוודאים שהמודולים שצוינו יותקנו ב-$ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin. אם ה-ramdisk של vendor_boot נטען במצב שחזור, המודול זמין גם ב-recovery. אם דיסק ה-RAM של vendor_boot לא נטען במצב שחזור, אפשר להתקין במכשיר גם את adbd.recovery.

סיכומי ביקורת של מטא-נתונים

כדי לתמוך בסיכומי ביקורת של מטא-נתונים במהלך הרכבת השלב הראשון, במכשירים שלא תומכים ב-GKI מותקנת הגרסה של המודולים הבאים ל-ramdisk. כדי להוסיף תמיכה ב-GKI, מעבירים את המודולים אל $ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin:

PRODUCT_PACKAGES += \
    linker.vendor_ramdisk \
    resize2fs.vendor_ramdisk \
    tune2fs.vendor_ramdisk \

דוגמה לכך מופיעה ברשימת השינויים הזו.

דחיסת A/B וירטואלית

כדי לתמוך ב-Virtual A/B compression, צריך להתקין את snapuserd ב-vendor_ramdisk. המכשיר אמור לרשת מ-virtual_ab_ota/compression.mk, שמתקין את הווריאנט vendor_ramdisk של snapuserd.

שינויים בתהליך האתחול

תהליך האתחול לא משתנה כשמפעילים את Android. vendor_boot + generic ramdisk דומה לתהליך האתחול הקיים, מלבד העובדה ש-fstab נטען מ-vendor_boot. מכיוון ש-system/bin/recovery לא קיים, first_stage_init מטפל בו כבהפעלה רגילה.

כשמפעילים את המכשיר במצב שחזור, תהליך האתחול משתנה. התהליך של שחזור + vendor_boot + דיסק אחסון RAM גנרי דומה לתהליך השחזור הקיים, אבל הליבה נטענת מהתמונה boot במקום מהתמונה recovery. תהליך האתחול למצב שחזור הוא כדלקמן.

  1. תוכנת האתחול מתחילה לפעול ומבצעת את הפעולות הבאות:

    1. דחיפה של recovery +‏ vendor_boot +‏ generic ramdisk אל /. (אם ה-OEM מעתיק את מודולי הליבה ב-recovery ramdisk על ידי הוספה שלהם ל-BOARD_RECOVERY_KERNEL_MODULES), השדה vendor_boot הוא אופציונלי.)
    2. הפעלת הליבה מהמחיצה boot.
  2. הליבה מחברת את ה-ramdisk אל / ואז מבצעת את /init מה-ramdisk הגנרי.

  3. השלב הראשון של init מתחיל, ולאחר מכן מבצע את הפעולות הבאות:

    1. מגדיר את IsRecoveryMode() == true ו-ForceNormalBoot() == false.
    2. טוען מודולים של ליבה של ספקים מ-/lib/modules.
    3. קוראת ל-DoFirstStageMount() אבל מדלגת על הטעינה כי IsRecoveryMode() == true. (המכשיר לא משחרר את ה-ramdisk (כי הערך של / עדיין זהה), אבל הוא כן קורא ל-SetInitAvbVersionInRecovery()).
    4. הפעלת שלב שני של init מ-/system/bin/init מ-recovery ramdisk.

הפעלת e2fsck

קובצי ה-makefile של המכשיר יכולים לרשת מ:

  • virtual_ab_ota/launch_with_vendor_ramdisk.mk אם המכשיר תומך ב-A/B וירטואלי אבל לא בהצפנה.

  • virtual_ab_ota/compression.mk אם המכשיר תומך ברזולוציה וירטואלית של A/B.

קובצי ה-makefile של המוצר מתקינים את $ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin/e2fsck. בזמן הריצה, השלב הראשון init מפעיל את /system/bin/e2fsck.

אפשרות 2ב: מחיצה ייעודית לשחזור שאינה מחיצה A/B

משתמשים באפשרות הזו במכשירים עם מחיצה recovery שאינה A/B, כלומר במכשיר יש מחיצה בשם recovery ללא סיומת של חריץ. המכשירים האלה כוללים:

  • מכשירים שאינם A/B
  • מכשירים עם חלוקה A/B ומכשירים וירטואליים עם חלוקה A/B, שבהם לא ניתן לעדכן את מחיצת השחזור. (הדבר הזה לא רגיל).

דיסק ה-RAM‏ vendor_boot מכיל את הביטים של הספק של דיסק ה-RAM ושל מודולי הליבה של הספק, כולל:

  • קבצים fstab ספציפיים למכשיר
  • lib/modules (כולל מודולים של ליבה של ספקים)

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

  • קובץ האימג' של הליבה
  • קובץ האימג' של DTBO
  • מודולים של ליבה ב-lib/modules
  • שלב ראשון של init כקישור סימלי /init -> /system/bin/init
  • קובץ הפעלה בינארי של שלב שני /system/bin/init
  • קבצים fstab ספציפיים למכשיר
  • כל שאר משאבי השחזור, כולל הקובץ הבינארי recovery

במכשירים כאלה, הגדרות המוצר יורשות מ-generic_ramdisk.mk.

הגדרת ערכים של BOARD

מגדירים את הערכים הבאים למכשירים שאינם A/B:

BOARD_USES_RECOVERY_AS_BOOT :=
BOARD_USES_GENERIC_KERNEL_IMAGE := true
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT :=
BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE :=
BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT := true

דיסק ה-RAM‏ recovery חייב להכיל קישור ל-/init -> /system/bin/init, ו-init_second_stage.recovery ב-/system/bin/init. כשהמכשיר מופעל במצב שחזור, קובץ ה-binary של /system/bin/init נדרש כדי לתמוך גם בשלב הראשון וגם בשלב השני של init.

כשהמכשיר מופעל ב-recovery, התוכן של דיסקים וירטואליים ב-RAM של recovery הוא:

  • /init -> /system/bin/init (מ-recovery ramdisk)
  • /system/bin/init (מ-ramdisk של recovery, שנוצר מ-init_second_stage.recovery ומופעל מ-/init)

כשהמכשיר מופעל ל-Android, התוכן של vendor_boot + generic ramdisks הוא:

  • /init (מ-ramdisk, נוצר מ-init_first_stage)

העברת קובצי fstab

מעבירים את כל הקבצים מסוג fstab שהותקנו ב-ramdisk הגנרי ל-ramdisk‏ vendor_ramdisk ול-recovery. דוגמה לכך מופיעה כאן.

התקנת מודולים

אפשר להתקין מודולים ספציפיים למכשיר ב-vendor_ramdisk וב-recovery של דיסק ה-RAM (אפשר לדלג על השלב הזה אם אין לכם מודולים ספציפיים למכשיר להתקנה). init לא מחליף את הרשאת root. וריאנט vendor_ramdisk של המודולים מתקין את המודולים ברמה הבסיסית של vendor_ramdisk. וריאנט recovery של המודולים מתקין את המודולים ברמה הבסיסית של דיסק ה-RAM‏ recovery. דוגמאות להתקנת מודולים ב-vendor_ramdisk וב-recovery ramdisk מפורטות במאמרים מסוף שלב ראשון וסיכומי ביקורת של מטא-נתונים.

מסוף שלב ראשון

כדי להתקין את הווריאנט vendor_ramdisk של המודולים, משתמשים באפשרות הבאה:

PRODUCT_PACKAGES += \
    linker.vendor_ramdisk \
    shell_and_utilities_vendor_ramdisk \

כך אפשר לוודא שההתקנה של linker,‏ sh ו-toybox תתבצע ב-$ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin, ולאחר מכן ההתקנה תתבצע ב-/system/bin בקטע vendor_ramdisk.

כדי להוסיף מודולים שנדרשים למסוף של השלב הראשון (לדוגמה, adbd), מפעילים את הווריאנט vendor_ramdisk של המודולים האלה על ידי העלאת התיקונים הרלוונטיים ל-AOSP, ואז משתמשים בקוד הבא:

PRODUCT_PACKAGES += adbd.vendor_ramdisk

כך מוודאים שהמודולים שצוינו יותקנו ב-$ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin.

כדי להתקין את הווריאנט recovery של המודולים, מחליפים את vendor_ramdisk ב-recovery:

PRODUCT_PACKAGES += \
    linker.recovery \
    shell_and_utilities_recovery \
    adbd.recovery \

סיכומי ביקורת של מטא-נתונים

כדי לתמוך בסיכומי ביקורת של מטא-נתונים במהלך הרכבת השלב הראשון, במכשירים שלא תומכים ב-GKI מותקנת הגרסה של המודולים הבאים ל-ramdisk. כדי להוסיף תמיכה ב-GKI, מעבירים את המודולים אל $ANDROID_PRODUCT_OUT/vendor-ramdisk/system/bin:

PRODUCT_PACKAGES += \
    linker.vendor_ramdisk \
    resize2fs.vendor_ramdisk \
    tune2fs.vendor_ramdisk \

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

שינויים בתהליך האתחול

תהליך האתחול לא משתנה כשמפעילים את Android. vendor_boot + generic ramdisk דומה לתהליך האתחול הקיים, מלבד העובדה ש-fstab נטען מ-vendor_boot. מכיוון ש-system/bin/recovery לא קיים, first_stage_init מטפל בו כבהפעלה רגילה.

תהליך האתחול לא משתנה כשמפעילים את המכשיר במצב שחזור. ה-ramdisk של התהליך לשחזור נטען באותו אופן שבו נטען תהליך השחזור הקיים. הליבה נטענת מהתמונה recovery. תהליך האתחול למצב שחזור הוא:

  1. תוכנת האתחול מתחילה לפעול ומבצעת את הפעולות הבאות:

    1. דחיפה של דיסק RAM לשחזור אל /.
    2. הפעלת הליבה מהמחיצה recovery.
  2. הליבה מחברת את ה-ramdisk אל / ואז מבצעת את /init, שהוא קישור סימלי ל-/system/bin/init מה-ramdisk של recovery.

  3. השלב הראשון של init מתחיל, ואז מבצע את הפעולות הבאות:

    1. מגדיר את IsRecoveryMode() == true ו-ForceNormalBoot() == false.
    2. טוען מודולים של ליבה של ספקים מ-/lib/modules.
    3. קוראת ל-DoFirstStageMount() אבל מדלגת על הטעינה כי IsRecoveryMode() == true. (המכשיר לא משחרר את ה-ramdisk (כי הערך של / עדיין זהה), אבל הוא כן קורא ל-SetInitAvbVersionInRecovery()).
    4. הפעלת שלב שני של init מ-/system/bin/init מ-recovery ramdisk.

חותמות זמן של קובץ אימג' לאתחול

הקוד הבא הוא דוגמה לקובץ חותמת זמן של תמונה בפורמט boot:

####################################
# from generate-common-build-props
# These properties identify this partition image.
####################################
ro.product.bootimage.brand=Android
ro.product.bootimage.device=generic_arm64
ro.product.bootimage.manufacturer=unknown
ro.product.bootimage.model=AOSP on ARM64
ro.product.bootimage.name=aosp_arm64
ro.bootimage.build.date=Mon Nov 16 22:46:27 UTC 2020
ro.bootimage.build.date.utc=1605566787
ro.bootimage.build.fingerprint=Android/aosp_arm64/generic_arm64:S/MASTER/6976199:userdebug/test-keys
ro.bootimage.build.id=MASTER
ro.bootimage.build.tags=test-keys
ro.bootimage.build.type=userdebug
ro.bootimage.build.version.incremental=6976199
ro.bootimage.build.version.release=11
ro.bootimage.build.version.release_or_codename=S
ro.bootimage.build.version.sdk=30
# Auto-added by post_process_props.py
persist.sys.usb.config=none
# end of file
  • בזמן ה-build, קובץ system/etc/ramdisk/build.prop מתווסף ל-ramdisk הכללי. הקובץ הזה מכיל את פרטי חותמת הזמן של ה-build.

  • במהלך זמן הריצה, השלב הראשון init מעתיק קבצים מה-ramdisk אל tmpfs לפני שמשחררים את ה-ramdisk, כדי שהשלב השני init יוכל לקרוא את הקובץ הזה כדי להגדיר את מאפייני חותמת הזמן של התמונה boot.