העברת אתחול מהיר למרחב המשתמשים

Fastboot הוא שם של מודול ומצב של מנהל אתחול. ב-Android מגרסה 10 ואילך יש תמיכה במחיצות שניתנות לשינוי גודל על ידי שינוי המיקום של הטמעת האתחול מתוכנת האתחול למרחב המשתמשים. המיקום הזה מאפשר להעביר את הקוד המהבהב למיקום משותף שניתן לתחזק ולבדיקה, שבו רק החלקים הספציפיים לספק של אתחול מהיר הוטמעו על ידי שכבת הפשטה של החומרה (HAL). בנוסף, ב-Android 12 ואילך יש תמיכה בעדכון של דיסקים של זיכרון RAM באמצעות פקודת fastboot נוספת.

איחוד אתחול מהיר ושחזור

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

Fastbootd הוא השם של דימון (daemon) ומצב מרחב משתמשים. כדי לתמוך ב-fastbootd, מנהל האתחול צריך להטמיע פקודה חדשה של boot-fastboot לבקרת אתחול (BCB). כדי להיכנס למצב fastbootd, מנהל האתחול כותב את הערך boot-fastboot בשדה הפקודה של הודעת ה-BCB, ולא משנה את השדה recovery של ה-BCB (כדי לאפשר הפעלה מחדש של משימות שחזור שהופסק). גם השדות status,‏ stage ו-reserved לא ישתנו. תוכנת האתחול נטענת בתמונת השחזור ומתחילה להיכנס אליה כשהיא מופיעה בשדה boot-fastboot בשדה הפקודה של BCB. לאחר מכן, תהליך השחזור מנתח את הודעת ה-BCB ומעביר את המכשיר למצב fastbootd.

פקודות ADB

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

הוראה תיאור
reboot fastboot
  • בוצעה הפעלה מחדש לתוך fastbootd (מערכת).
  • נכנסים ישירות ל-fastbootd בלי הפעלה מחדש (שחזור).

פקודות Fastboot

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

הוראה תיאור
reboot recovery
  • הפעלות מחדש לצורך שחזור (תוכנת אתחול).
  • כניסה ישירה לשחזור ללא הפעלה מחדש (fastbootd).
reboot fastboot הפעלה מחדש תתבצע בעוד fastbootd.
getvar is-userspace
  • הפונקציה מחזירה את הערך yes (fastbootd).
  • הפונקציה מחזירה את הערך no (תוכנת אתחול).
getvar is-logical:<partition> הפונקציה מחזירה את הערך yes אם המחיצה הנתונה היא מחיצה לוגית, ואת הערך no במקרה אחר. מחיצות לוגיות תומכות בכל הפקודות שמפורטות בהמשך.
getvar super-partition-name מחזירה את השם של מחיצת-העל. השם כולל את סיומת המשבצת הנוכחית אם מחיצת ה-Super היא מחיצת A/B (בדרך כלל היא לא).
create-logical-partition <partition> <size> יצירת מחיצה לוגית עם השם והגודל שצוינו. השם לא יכול להיות כבר קיים כמחיצה לוגית.
delete-logical-partition <partition> מחיקה של המחיצה הלוגית שצוינה (מחיקת המחיצה בפועל).
resize-logical-partition <partition> <size> משנה את גודל המחיצה הלוגית לגודל החדש בלי לשנות את התוכן שלה. הפעולה תיכשל אם אין מספיק מקום פנוי לביצוע שינוי הגודל.
update-super <partition> מיזוג שינויים במטא-נתונים של מחיצה העל. אם אי אפשר למזג (לדוגמה, הפורמט במכשיר הוא גרסה שלא נתמכת), הפקודה נכשלת. פרמטר wipe אופציונלי מחליף את המטא-נתונים של המכשיר במקום לבצע מיזוג.
flash <partition><filename> ] כתיבת קובץ למחיצה ב-Flash. נעילת המכשיר צריכה להיות פתוחה.
erase <partition> מחיקה של מחיצה (לא חייבת להיות מחיקה מאובטחת). המכשיר חייב להיות במצב פתוח.
getvar <variable> | all הצגת משתנה של מנהל האתחול או כל המשתנים. אם המשתנה לא קיים, תוחזר שגיאה.
set_active <slot>

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

בתמיכה ב-A/B, חריצי זיכרון הם קבוצות כפולות של מחיצות שאפשר להפעיל מהן בנפרד. השמות של התקציבים הם a, b וכן הלאה, והם נבדלים זה מזה על ידי הוספת הסיומת _a, _b וכן הלאה לשם המחיצה.

reboot הפעלה מחדש של המכשיר באופן רגיל.
reboot-bootloader (או reboot bootloader) הפעלה מחדש של המכשיר לתוכנת האתחול.
fastboot fetch vendor_boot <out.img>

משתמשים ב-Android מגרסה 12 ואילך כדי לתמוך באחסון RAM מהיר (ramdisk) של ספקים לצורך פלאש.

הפונקציה מקבלת את כל גודל המחיצה ואת גודל המקטע. מקבלת נתונים לכל מקטע, ואז מחברת את הנתונים יחד ל-<out.img>

פרטים נוספים זמינים במאמר fastboot fetch vendor_boot <out.img>.

fastboot flash vendor_boot:default <vendor-ramdisk.img>

משתמשים ב-Android 12 ואילך כדי לתמוך ב-flashing של דיסקים של זיכרון RAM של ספקים.

זוהי וריאנט מיוחד של פקודת ה-flash. הוא מבצע פונקציית אימג' של fetch vendor_boot, כאילו fastboot fetch היתה מופעלת. קובץ האימג' החדש של vendor_boot שיועבר תלוי בגרסה של כותרת האתחול, גרסה 3 או גרסה 4.

פרטים נוספים זמינים במאמר fastboot flash vendor_boot:default <vendor-ramdisk.img>.

fastboot flash vendor_boot:<foo> <vendor-ramdisk.img> משתמשים ב-Android 12 ואילך כדי לתמוך ב-flashing של דיסקים של זיכרון RAM של ספקים.

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

פרטים נוספים זמינים במאמר fastboot flash vendor_boot:<foo> <vendor-ramdisk.img>.

Fastboot ותוכנת האתחול

תוכנת האתחול מבצעת פלאש של המחיצות bootloader,‏ radio ו-boot/recovery, ולאחר מכן המכשיר מופעל במצב fastboot (מרחב המשתמש) ומבצע פלאש של כל המחיצות האחרות. מנהל האתחול צריך לתמוך בפקודות הבאות.

הוראה תיאור
download הורדת התמונה ל-Flash.
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ איפוס מחיצת recovery/boot ותוכנת האתחול.
reboot הפעלה מחדש של המכשיר.
reboot fastboot הפעלה מחדש לכלי לאתחול מהיר (fastboot).
reboot recovery הפעלה מחדש למצב שחזור.
getvar הפונקציה מקבלת משתנה של bootloader שנדרש כדי להציג את קובץ האימג' של התאוששות/האתחול (לדוגמה, current-slot ו-max-download-size).
oem <command> פקודה שהוגדרה על ידי יצרן ציוד מקורי (OEM).

מחיצות דינמיות

אסור שה-bootloader יאפשר את ה-flashing או המחיקה של מחיצות דינמיות, וחייב להחזיר שגיאה אם מתבצעים ניסיונות לבצע את הפעולות האלה. במכשירים עם מחיצה דינמית מותאמת, הכלי Fastboot (ו-bootloader) תומכים במצב כפייה כדי לבצע איפוס (flash) ישירות של מחיצה דינמית במצב bootloader. לדוגמה, אם system הוא מחיצה דינמית במכשיר שעבר התאמה, שימוש בפקודה fastboot --force flash system מאפשר למחולל האתחול (במקום fastbootd) לבצע את הפלאש של המחיצה.

טעינה במצב כבוי

אם המכשיר תומך בטעינה במצב כבוי או מופעל באופן אוטומטי למצב מיוחד אחר כשמחברים אותו לחשמל, ההטמעה של הפקודה fastboot oem off-mode-charge 0 צריכה לעקוף את המצבים המיוחדים האלה, כדי שהמכשיר יופעל כאילו המשתמש לחץ על לחצן ההפעלה.

Fastboot OEM HAL

כדי להחליף לחלוטין את fastboot של מנהל האתחול, fastboot צריך לטפל בכל הפקודות הקיימות של fastboot. רבות מהפקודות האלה מגיעות מיצרני ציוד מקורי (OEM) ויש תיעוד עליהן, אבל הן דורשות הטמעה בהתאמה אישית. הרבה פקודות ספציפיות ליצרני ציוד מקורי לא מתועדות. כדי לטפל בפקודות כאלה, ה-HAL של fastboot מציין את פקודות ה-OEM הנדרשות. יצרני ציוד מקורי יכולים גם להטמיע פקודות משלהם.

ההגדרה של אתחול מהיר עם HAL היא:

import IFastbootLogger;

/**
 * IFastboot interface implements vendor specific fastboot commands.
 */
interface IFastboot {
    /**
     * Returns a bool indicating whether the bootloader is enforcing verified
     * boot.
     *
     * @return verifiedBootState True if the bootloader is enforcing verified
     * boot and False otherwise.
     */
    isVerifiedBootEnabled() generates (bool verifiedBootState);

    /**
     * Returns a bool indicating the off-mode-charge setting. If off-mode
     * charging is enabled, the device autoboots into a special mode when
     * power is applied.
     *
     * @return offModeChargeState True if the setting is enabled and False if
     * not.
     */
    isOffModeChargeEnabled() generates (bool offModeChargeState);

    /**
     * Returns the minimum battery voltage required for flashing in mV.
     *
     * @return batteryVoltage Minimum battery voltage (in mV) required for
     * flashing to be successful.
     */
    getBatteryVoltageFlashingThreshold() generates (int32_t batteryVoltage);

    /**
     * Returns the file system type of the partition. This is only required for
     * physical partitions that need to be wiped and reformatted.
     *
     * @return type Can be ext4, f2fs or raw.
     * @return result SUCCESS if the operation is successful,
     * FAILURE_UNKNOWN if the partition is invalid or does not require
     * reformatting.
     */
    getPartitionType(string partitionName) generates (FileSystemType type, Result result);

    /**
     * Executes a fastboot OEM command.
     *
     * @param oemCmd The oem command that is passed to the fastboot HAL.
     * @response result Returns the status SUCCESS if the operation is
     * successful,
     * INVALID_ARGUMENT for bad arguments,
     * FAILURE_UNKNOWN for an invalid/unsupported command.
     */
    doOemCommand(string oemCmd) generates (Result result);

};

הפעלת Fastbootd

כדי להפעיל את fastbootd במכשיר:

  1. הוספה של fastbootd ל-PRODUCT_PACKAGES ב-device.mk: PRODUCT_PACKAGES += fastbootd.

  2. חשוב לוודא שהרכיבים מסוג HAL לאתחול מהיר, HAL של בקרת אתחול ו-HAL נארזים כחלק מקובץ האימג' לשחזור מערכת ההפעלה.

  3. מוסיפים את כל ההרשאות הספציפיות למכשיר של SEPolicy שנדרשות ל-fastbootd. לדוגמה, כדי להפעיל את הפלאש של מחיצה ספציפית למכשיר, צריכה להיות ל-fastbootd הרשאת כתיבה למחיצה הזו. בנוסף, ייתכן שהטמעה של אתחול מהיר עם HAL תדרוש גם הרשאות ספציפיות למכשיר.

כדי לאמת את האתחול המהיר במרחב המשתמשים, מריצים את Vendor Test Suite (VTS).

ramdisks של ספקי Flash

ב-Android מגרסה 12 ואילך יש תמיכה ב-ramdisk מהבהב עם תוספת של פקודת אתחול מהיר (fastboot) שגורמת לשלוף את קובץ התמונה המלא של vendor_boot מהמכשיר. הפקודה מפעילה את הכלי fastboot בצד המארח כדי לקרוא את כותרת האתחול של הספק, ליצור קובץ אימג' מחדש ולהפעיל את האימג' החדש.

כדי לשלוף את קובץ האימג' המלא של vendor_boot, הפקודה fetch:vendor_boot נוספה גם לפרוטוקול fastboot וגם להטמעת הפרוטוקול ב-fastbootd ב-Android 12. לתשומת ליבכם, fastbootd כן מטמיע את זה, אבל יכול להיות שה-bootloader עצמו לא מטמיע את זה. יצרני ציוד מקורי יכולים להוסיף את הפקודה fetch:vendor_boot להטמעת הפרוטוקול של מערך האתחול. עם זאת, אם הפקודה לא מזוהה במצב bootloader, אי אפשר להשתמש באפשרות של פלאש של דיסקים ספציפיים של זיכרון RAM של ספקים במצב bootloader.

שינויים ב-Bootloader

הפקודות getvar:max-fetch-size ו-fetch:name מוטמעות ב-fastbootd. כדי לתמוך בעדכון של דיסקים של זיכרון RAM של ספקים ב-bootloader, צריך להטמיע את שתי הפקודות האלה.

שינויים ב-Fastbootd

getvar:max-fetch-size דומה ל-max-download-size. הוא מציין את הגודל המקסימלי שהמכשיר יכול לשלוח בתשובת DATA אחת. הנהג לא יכול לאחזר גודל גדול מהערך הזה.

fetch:name[:offset[:size]] מבצע סדרה של בדיקות במכשיר. אם כל התנאים הבאים מתקיימים, הפקודה fetch:name[:offset[:size]] תחזיר נתונים:

  • במכשיר פועל build שניתן לניפוי באגים.
  • המכשיר לא נעול (מצב הפעלה כתום).
  • שם המחיצה שאוחזרה הוא vendor_boot.
  • הערך של size נמצא בטווח 0 < size <= max-fetch-size.

כשהם מאומתים, הפונקציה fetch:name[:offset[:size]] מחזירה את גודל המחיצה ואת ההיסט. חשוב לזכור:

  • fetch:name היא שוות-ערך ל-fetch:name:0, שמקבילה ל-fetch:name:0:partition_size.
  • הפונקציה fetch:name:offset שוות ערך לפונקציה fetch:name:offset:(partition_size - offset)

לכן fetch:name[:offset[:size]] = fetch:name:offset:(partition_size - offset).

אם לא מציינים את הערכים של offset או partition_size (או את שניהם), המערכת משתמשת בערכי ברירת המחדל: 0 עבור offset ו-partition_size - offset המחושב עבור size.

  • צוין היסט, לא צוין גודל: size = partition_size - offset
  • לא צוין אף ערך: ערכים שמוגדרים כברירת מחדל ישמשו בשניהם, size = partition_size – 0.

לדוגמה, fetch:foo מאחזרת את כל המחיצה foo במרווח 0.

שינויים במנהלי התקנים

הפקודות נוספו לכלי האתחול המהיר כדי להטמיע שינויים במנהל ההתקן. כל אחת מהן מקושרת להגדרה המלאה שלה בטבלה של פקודות Fastboot.

  • fastboot fetch vendor_boot out.img

    • הפונקציה מפעילה את הפקודה getvar max-fetch-size כדי לקבוע את גודל המקטע.
    • קוראת לפונקציה getvar partition-size:vendor_boot[_a] כדי לקבוע את גודל המחיצה כולה.
    • הפונקציה קוראת ל-fastboot fetch vendor_boot[_a]:offset:size לכל מקטע. (גודל הקטע גדול מגודל vendor_boot, ולכן בדרך כלל יש רק קטע אחד).
    • מקבץ את הנתונים יחד, אל out.img.
  • fastboot flash vendor_boot:default vendor-ramdisk.img

    זוהי וריאנט מיוחד של פקודת ה-flash. הוא מאחזר את התמונה vendor_boot, כאילו הופעלה הפונקציה fastboot fetch.

    • אם האתחול של הספק הוא הכותרת גרסה 3, היא מבצעת את הפעולות הבאות:
      • מחליפה את ה-ramdisk של הספק בתמונה הנתונה.
      • איך מעדכנים את קובץ האימג' החדש של vendor_boot.
    • אם כותרת האתחול של הספק היא גרסה 4, מתבצעים הפעולות הבאות:
      • מחליפה את כל ה-ramdisk של הספק בתמונה הנתונה, כך שהתמונה הנתונה תהפוך למקטע היחיד של ramdisk של הספק בתמונה של vendor_boot.
      • מחשב מחדש את הגודל וההיסט בטבלת ה-ramdisk של הספק.
      • איך מעדכנים את קובץ האימג' החדש של vendor_boot.
  • fastboot flash vendor_boot:foo vendor-ramdisk.img

    אחזור של vendor_boot image, כאילו fastboot fetch הוזמנה.

    • אם כותרת האתחול של הספק היא גרסה 3, היא תחזיר שגיאה.
    • אם כותרת האתחול של הספק היא גרסה 4, היא מבצעת את הפעולות הבאות:

      • מוצא את מקטע ה-ramdisk של הספק בשם ramdisk_<var>&lt;foo></var>. אם לא נמצאה התאמה, או אם יש כמה התאמות, הפונקציה מחזירה שגיאה.
      • החלפת קטע ה-ramdisk של הספק בתמונה שצוינה.
      • חישוב מחדש של כל הגודל וההיסט בטבלת ה-ramdisk של הספק.
      • איך מעדכנים את קובץ האימג' החדש של vendor_boot.
    • אם לא מציינים את <foo>, המערכת תנסה למצוא את ramdisk_.

mkbootimg

השם default שמור למתן שמות לקטעי ramdisk של ספקים ב-Android 12 ואילך. למרות שהסמנטיקה של flash vendor_boot:default בתהליך האתחול המהיר נשארת ללא שינוי, אסור לתת למקטעי ה-ramdisk את השם default.

שינויים ב-SELinux

בוצע שינוי ב-fastbootd.te כדי לתמוך ב-flashing של דיסקים מסוג RAMdisk של ספקים.