將 Fastboot 移至用戶空間

Android 10 及更高版本通過將 fastboot 實現從引導加載程序重新定位到用戶空間來支持可調整大小的分區。這種重新定位允許將閃存代碼移動到可維護和可測試的公共位置,只有硬件抽象層 (HAL) 實現的 fastboot 的供應商特定部分。此外,Android 12 及更高版本支持通過添加的 fastboot 命令刷新 ramdisk。

統一快速啟動和恢復

因為用戶空間的快速啟動和恢復是相似的,你可以將它們合併到一個分區或二進製文件中。這提供了一些優勢,例如使用更少的空間、總體上具有更少的分區以及讓 fastboot 和 recovery 共享它們的內核和庫。

為了支持fastbootd ,引導加載程序必須實現一個新的引導控制塊 (BCB) 命令boot-fastboot 。為了進入fastbootd模式,bootloader 將boot-fastboot寫入 BCB 消息的命令字段,並保持 BCB 的recovery字段不變(以啟用重新啟動任何中斷的恢復任務)。 statusstagereserved字段也保持不變。在 BCB 命令字段中看到boot-fastboot後,引導加載程序加載並引導到恢復映像。然後,Recovery 會解析 BCB 消息並切換到fastbootd模式。

亞行命令

本節介紹用於集成fastbootdadb命令。該命令具有不同的結果,具體取決於它是由系統執行還是由恢復執行。

命令描述
reboot fastboot
  • 重新啟動進入fastbootd (系統)。
  • 直接進入fastbootd無需重啟(恢復)。

快速啟動命令

本節介紹用於集成fastbootd的 fastboot 命令,包括用於刷新和管理邏輯分區的新命令。某些命令有不同的結果,具體取決於它們是由 bootloader 還是由fastbootd執行的。

命令描述
reboot recovery
  • 重新啟動進入恢復(引導加載程序)。
  • 無需重新啟動( fastbootd )直接進入恢復。
reboot fastboot重新啟動到fastbootd
getvar is-userspace
  • 返回yes ( fastbootd )。
  • 返回no (引導加載程序)。
getvar is-logical: <partition>如果給定分區是邏輯分區,則返回yes ,否則返回no 。邏輯分區支持下面列出的所有命令。
getvar super-partition-name返回超級分區的名稱。如果超級分區是 A/B 分區(通常不是),則名稱包括當前插槽後綴。
create-logical-partition <partition> <size>創建具有給定名稱和大小的邏輯分區。該名稱不能作為邏輯分區存在。
delete-logical-partition <partition>刪除給定的邏輯分區(有效擦除分區)。
resize-logical-partition <partition> <size>將邏輯分區的大小調整為新大小,而不更改其內容。如果沒有足夠的可用空間來執行調整大小,則會失敗。
update-super <partition>合併對超級分區元數據的更改。如果無法進行合併(例如,設備上的格式是不受支持的版本),則此命令將失敗。可選的wipe參數覆蓋設備的元數據,而不是執行合併。
flash <partition> [ <filename> ]將文件寫入閃存分區。設備必須處於解鎖狀態。
erase <partition>擦除分區(不需要安全擦除)。設備必須處於解鎖狀態。
getvar <variable> | all顯示引導加載程序變量或所有變量。如果變量不存在,則返回錯誤。
set_active <slot>

將給定的 A/B 引導槽設置為active 。在下一次引導嘗試時,系統從指定的插槽引導。

對於 A/B 支持,插槽是可以獨立引導的重複分區集。插槽被命名為ab等,並通過在分區名稱中添加後綴_a_b等來區分。

reboot正常重啟設備。
reboot-bootloader (或reboot bootloader將設備重新啟動到引導加載程序。
fastboot fetch vendor_boot <out.img>

Android 12 及更高版本中使用以支持刷新供應商 ramdisk。

獲取整個分區大小和塊大小。獲取每個塊的數據,然後將數據拼接到<out.img>

有關詳細信息,請參閱fastboot fetch vendor_boot <out.img>

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

Android 12及更高版本中使用以支持刷新供應商 ramdisk。

這是 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及更高版本中使用以支持刷新供應商 ramdisk。

獲取vendor_boot映像。如果供應商引導標頭是版本 3,則返回錯誤。如果是版本 4,它會找到正確的供應商 ramdisk 片段(如果可用)。它用給定的圖像替換它,重新計算大小和偏移量,並刷新新的vendor_boot image

有關詳細信息,請參閱fastboot flash vendor_boot: <foo> <vendor-ramdisk.img>

快速啟動和引導加載程序

bootloader 會bootloaderradioboot/recovery分區,之後設備啟動到 fastboot(用戶空間)並刷新所有其他分區。引導加載程序應支持以下命令。

命令描述
download將圖像下載到閃存。
flash recovery <image> / flash boot <image> / flash bootloader <image> /刷新recovery/boot分區和引導加載程序。
reboot重新啟動設備。
reboot fastboot重新啟動到快速啟動。
reboot recovery重新啟動以恢復。
getvar獲取刷新恢復/引導映像所需的引導加載程序變量(例如current-slotmax-download-size )。
oem <command> OEM 定義的命令。

動態分區

引導加載程序不得允許對動態分區進行刷新或擦除,並且在嘗試執行這些操作時必須返回錯誤。對於改裝的動態分區設備,fastboot 工具(和引導加載程序)支持強制模式,以便在引導加載程序模式下直接刷新動態分區。例如,如果system是改裝設備上的動態分區,則使用fastboot --force flash system命令啟用引導加載程序(而不是fastbootd )來刷新分區。

關機模式充電

如果設備支持關閉模式充電或在通電時自動啟動到特殊模式,則fastboot oem off-mode-charge 0命令的實現必須繞過這些特殊模式,以便設備像用戶按下一樣啟動電源按鈕。

快速啟動 OEM HAL

要完全替換 bootloader fastboot,fastboot 必須處理所有現有的 fastboot 命令。其中許多命令來自 OEM 並已記錄在案,但需要自定義實現。許多 OEM 特定的命令記錄在案。為了處理此類命令,fastboot HAL 指定了所需的 OEM 命令。 OEM 還可以實現自己的命令。

fastboot 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

  1. fastbootd添加到device.mk中的PRODUCT_PACKAGES中: PRODUCT_PACKAGES += fastbootd

  2. 確保將 fastboot HAL、啟動控制 HAL 和運行狀況 HAL 打包為恢復映像的一部分。

  3. 添加fastbootd所需的任何特定於設備的 SEPolicy 權限。例如, fastbootd需要對特定於設備的分區進行寫訪問才能刷新該分區。此外,fastboot HAL 實施可能還需要特定於設備的權限。

要驗證用戶空間快速啟動,請運行供應商測試套件 (VTS)

刷新供應商 ramdisk

Android 12 及更高版本通過添加的 fastboot 命令提供對閃存 ramdisk 的支持,該命令可從設備中提取完整的vendor_boot映像。該命令提示主機端快速啟動工具讀取供應商啟動標頭、重新映像並刷新新映像。

為了提取完整的vendor_boot映像,命令fetch:vendor_boot被添加到 fastboot 協議和 Android 12 中該協議的 fastbootd 實現中。請注意,fastbootd確實實現了這一點,但引導加載程序本身可能沒有。 OEM 可以將fetch:vendor_boot命令添加到協議的引導加載程序實現中。但是,如果在引導加載程序模式下無法識別該命令,則在引導加載程序模式下刷新各個供應商 ramdisk 不是供應商支持的選項。

引導加載程序更改

命令getvar:max-fetch-sizefetch:namefastbootd中實現。要在引導加載程序中支持刷新供應商 ramdisk,您必須實現這兩個命令。

快速啟動更改

getvar:max-fetch-size類似於max-download-size 。它指定設備可以在一個 DATA 響應中發送的最大大小。驅動程序不得獲取大於此值的大小。

fetch:name[:offset[:size]]在設備上執行一系列檢查。如果滿足以下所有條件,則fetch:name[:offset[:size]]命令返回數據:

  • 該設備正在運行可調試的構建。
  • 設備已解鎖(啟動狀態為橙色)。
  • 獲取的分區名稱是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)

當未指定offsetpartition_size (或兩者)時,使用默認值,對於offset是 0,對於sizepartition_size - offset的計算值。

  • 指定偏移量,未指定大小: size = partition_size - offset
  • 均未指定:兩者都使用默認值, size = partition_size - 0。

例如, fetch:foo在偏移量 0 處獲取整個foo分區。

驅動程序更改

命令被添加到 fastboot 工具以實現驅動程序更改。每個都鏈接到其在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,以便給定的映像成為vendor_boot映像中唯一的供應商 ramdisk 片段。
      • 重新計算供應商 ramdisk 表中的大小和偏移量。
      • 刷新新的vendor_boot映像。
  • fastboot flash vendor_boot:foo vendor-ramdisk.img

    獲取vendor_boot image ,就像調用了fastboot fetch一樣。

    • 如果供應商引導標頭是版本 3,它會返回錯誤。
    • 如果供應商引導標頭是版本 4,它會執行以下操作:

      • 查找名稱為foo的供應商 ramdisk 片段。如果未找到,或者有多個匹配項,則返回錯誤。
      • 用給定的圖像替換供應商 ramdisk 片段。
      • 重新計算供應商 ramdisk 表中的每個大小和偏移量。
      • 刷新新的vendor_boot映像。

mkbootimg

名稱default保留用於在 Android 12 及更高版本中命名供應商 ramdisk 片段。雖然 fastboot flash vendor_boot:default語義保持不變,但您不能將您的 ramdisk 片段命名為default

SELinux 變化

fastbootd.te中進行了更改以支持刷新供應商 ramdisk。