將 Fastboot 移至使用者空間

「Fastboot」是開機載入程式模組和模式的名稱。Android 10 以上版本支援可調整大小的分割區,方法是將 fastboot 實作項目從開機載入程式重新定位到使用者空間。這項重定位作業可將刷機程式碼移至可維護及可測試的通用位置,並僅透過硬體抽象層 (HAL) 實作 Fastboot 的供應商專屬部分。此外,Android 12 以上版本支援透過新增的 fastboot 指令刷寫 ramdisk。

統一 Fastboot 和 Recovery

由於使用者空間的 Fastboot 和 Recovery 類似,因此您可以將兩者合併為一個磁碟分割區或二進位檔。這項做法的優點包括減少空間用量、減少整體分割區,以及讓 Fastboot 和復原共用核心和程式庫。

Fastbootd 是使用者空間精靈和模式的名稱。 如要支援 fastbootd,開機載入程式必須實作 boot-fastboot 的新開機控制區塊 (BCB) 指令。如要進入 fastbootd 模式,開機載入器會將 boot-fastboot 寫入 BCB 訊息的指令欄位,並將 BCB 的 recovery 欄位維持不變 (以便重新啟動任何中斷的復原工作)。statusstagereserved 欄位也會維持不變。 看到 BCB 指令欄位中的 boot-fastboot 時,開機載入器會載入並啟動復原映像檔。然後,復原程序會剖析 BCB 訊息,並切換至 fastbootd 模式。

ADB 指令

本節說明整合 fastbootdadb 指令。視執行指令的是系統還是復原功能,指令會產生不同的結果。

指令 說明
reboot fastboot
  • 重新啟動進入 fastbootd (系統)。
  • 直接進入 fastbootd,不必重新啟動 (復原)。

Fastboot 指令

本節說明整合 fastbootd 的 fastboot 指令,包括用於刷寫及管理邏輯分割區的新指令。部分指令的結果會因執行者是開機載入程式或 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> 將邏輯分割區調整為新大小,但不會變更內容。 如果可用空間不足,無法執行大小調整作業,就會失敗。
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>

Fastboot 和系統啟動載入程式

系統啟動載入程式會刷寫 bootloaderradioboot/recovery 分區,之後裝置會啟動進入 Fastboot (使用者空間),並刷寫所有其他分區。開機載入程式應支援下列指令。

指令 說明
download 將圖片下載到快閃記憶體。
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ 刷寫 recovery/boot 分區和啟動載入器。
reboot 重新啟動裝置。
reboot fastboot 重新啟動為 Fastboot。
reboot recovery 重新啟動進入復原模式。
getvar 取得刷寫復原/開機映像檔所需的系統啟動載入程式變數 (例如 current-slotmax-download-size)。
oem <command> 原始設備製造商 (OEM) 定義的指令。

動態分割區

開機載入器不得允許動態分區的刷機或清除作業,且如果嘗試執行這些作業,必須傳回錯誤。如果是改裝的動態分區裝置,fastboot 工具 (和開機載入器) 支援強制模式,可在開機載入器模式下直接刷新動態分區。舉例來說,如果 system 是改裝裝置上的動態分割區,使用 fastboot --force flash system 指令可讓開機載入程式 (而非 fastbootd) 刷寫分割區。

關機充電

如果裝置支援關機充電,或是在供電時自動啟動特殊模式,則 fastboot oem off-mode-charge 0 指令的實作方式必須略過這些特殊模式,讓裝置啟動時如同使用者按下電源鍵。

Fastboot OEM HAL

如要完全取代開機載入程式 Fastboot,Fastboot 必須處理所有現有的 Fastboot 指令。其中許多指令來自 OEM,且已記錄在文件中,但需要自訂實作。許多 OEM 專屬指令並未記錄在文件中。為處理這類指令,fastboot HAL 會指定必要的 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

如要在裝置上啟用 fastbootd,請按照下列步驟操作:

  1. device.mk 中將 fastbootd 新增至 PRODUCT_PACKAGESPRODUCT_PACKAGES += fastbootd

  2. 確認 fastboot HAL、啟動控制 HAL 和健康狀態 HAL 已封裝為復原映像檔的一部分。

  3. 新增 fastbootd 所需的任何裝置專屬 SEPolicy 權限。舉例來說,fastbootd 需要裝置專屬分區的寫入權限,才能將該分區刷寫至裝置。此外,實作 Fastboot HAL 也可能需要裝置專屬權限。

如要驗證使用者空間 Fastboot,請執行供應商測試套件 (VTS)

刷入供應商 ramdisk

Android 12 以上版本支援使用新增的 Fastboot 指令刷寫 RAM 磁碟,從裝置擷取完整的 vendor_boot 映像檔。這個指令會提示主機端的 Fastboot 工具讀取供應商啟動標頭、重新建立映像檔,並刷入新映像檔。

如要提取完整的 vendor_boot 映像檔,Android 12 的 fastboot 協定和協定的 fastbootd 實作項目都新增了 fetch:vendor_boot 指令。請注意,fastbootd 實作這項功能,但開機載入程式本身可能不會。原始設備製造商 (OEM) 可以在通訊協定的開機載入程式實作中新增 fetch:vendor_boot 指令。不過,如果開機載入程式模式無法辨識指令,則在開機載入程式模式中刷入個別供應商 ramdisk,並非供應商支援的選項。

系統啟動載入程式變更

getvar:max-fetch-sizefetch:name 指令是在 fastbootd 中實作。如要在開機載入程式中支援刷入廠商 ramdisk,您必須實作下列兩個指令。

Fastbootd 變更

getvar:max-fetch-sizemax-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,size 的預設值為 partition_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,則會執行下列動作:
      • 使用指定映像檔取代供應商 RAM 磁碟。
      • 刷寫新的 vendor_boot 映像檔。
    • 如果供應商啟動標頭是版本 4,則會執行下列動作:
      • 以指定映像檔取代整個供應商 ramdisk,使指定映像檔成為 vendor_boot 映像檔中唯一的供應商 ramdisk 片段。
      • 重新計算供應商 RAM 磁碟表中的大小和偏移。
      • 刷寫新的 vendor_boot 映像檔。
  • fastboot flash vendor_boot:foo vendor-ramdisk.img

    擷取 vendor_boot image,如同呼叫 fastboot fetch

    • 如果供應商啟動標頭為第 3 版,則會傳回錯誤。
    • 如果供應商啟動標頭為第 4 版,則會執行下列操作:

      • 找出名為 ramdisk_<var>&lt;foo></var> 的供應商 RAM 磁碟片段。如果找不到相符項目,或是有多個相符項目,則會傳回錯誤。
      • 使用指定映像檔取代供應商 ramdisk 片段。
      • 重新計算供應商 RAM 磁碟表中的每個大小和位移。
      • 刷寫新的 vendor_boot 映像檔。
    • 如未指定 <foo>,則會嘗試尋找 ramdisk_

mkbootimg

在 Android 12 以上版本中,名稱 default 保留用於命名供應商 RAM 磁碟片段。雖然 fastboot flash vendor_boot:default 語意保持不變,但不得將 ramdisk 片段命名為 default

SELinux 變更

為支援刷入供應商 ramdisk, fastbootd.te 進行了變更。