將 Fastboot 移至使用者空間

Android 10 以上版本將 Fastboot 實作從系統啟動載入程式重新移到使用者空間,以支援可調整大小的分區。這種重置功能可以將刷新程式碼移到可維護且可測試的常用位置,只需要硬體抽象層 (HAL) 實作的供應商專用 Fastboot 部分。此外,Android 12 以上版本支援透過新增的 Fastboot 指令刷新 RAM。

統合 Fastboot 與復原

由於使用者空間 Fastboot 與復原類似,因此您可以合併至單一分區或二進位檔。這樣的好處如下:佔用較少空間、整體分區減少較少,以及讓 Fastboot 和復原共用核心和程式庫。

如要支援 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> 在不變更內容的情況下,將邏輯分區調整至新的大小。如果沒有足夠空間執行大小調整作業,即失敗。
update-super <partition> 合併對超級分區中繼資料所做的變更。如果無法合併 (例如,裝置上的格式是不受支援的版本),這個指令會失敗。選用的 wipe 參數會覆寫裝置的中繼資料,而不會執行合併。
flash <partition><filename> ] 將檔案寫入 Flash 分區。裝置必須處於解鎖狀態。
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 以上版本中使用,以支援刷新供應商 ramdisks 的功能。

取得整個分區大小和區塊大小。取得每個區塊的資料,然後將資料拼接至 <out.img>

詳情請參閱 fastboot fetch vendor_boot <out.img>

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

使用 Android 12 以上版本以支援刷新供應商 ramdisks。

這是 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 以上版本,以支援刷新供應商 ramdisks。

擷取 vendor_boot 圖片。如果廠商啟動標頭為第 3 版,就會傳回錯誤。如果是第 4 版,系統會找出正確的廠商 ramdisk 片段 (如果有的話)。這會取代指定圖片、重新計算大小和偏移,以及刷新新的 vendor_boot image

詳情請參閱 fastboot flash vendor_boot:<foo> <vendor-ramdisk.img>

Fastboot 和系統啟動載入程式

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

指令 說明
download 將映像檔下載為 Flash。
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 指令。在這些指令中,許多來自原始設備製造商 (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

如何在裝置上啟用 fastbootd

  1. 新增 fastbootddevice.mk 中的 PRODUCT_PACKAGESPRODUCT_PACKAGES += fastbootd

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

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

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

快閃供應商 ramdisks

Android 12 以上版本支援透過新增的 Fastboot 指令,從裝置提取完整的 vendor_boot 映像檔,藉此刷新 ramdisk。這個指令會提示主機端 Fastboot 工具讀取廠商開機標頭、重新映射,並刷新新映像檔。

為了提取完整的 vendor_boot 映像檔,我們已將 fetch:vendor_boot 指令同時新增至 Quickboot 通訊協定和 Android 12 中此通訊協定的快速啟動實作。請注意,Fastbootd 確實執行了這項作業,但系統啟動載入程式本身不一定能實作這項功能。原始設備製造商 (OEM) 可以在通訊協定的系統啟動載入程式實作中加入 fetch:vendor_boot 指令。但是,如果系統啟動載入程式模式下無法辨識指令,在系統啟動載入程式模式下重新整理個別廠商 ramdisk 時,便無法使用供應商支援的選項。

系統啟動載入程式變更

getvar:max-fetch-sizefetch:name 指令會在 fastbootd 中實作。如要在系統啟動載入程式中支援刷新廠商 ramdisks,您必須實作這兩個指令。

快速系統啟動變更

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 版,則系統會執行以下操作:
      • 將供應商 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

在 Android 12 以上版本中,default 是為供應商 ramdisk 片段命名的保留名稱。雖然 Quickboot flash vendor_boot:default 語意保持不變,但「請勿」將 ramdisk 片段命名為 default

SELinux 變更

已在 fastbootd.te 中進行變更,以支援刷新供應商 ramdisks。