将 Fastboot 移至用户空间

Android 10 通过将 fastboot 实现从引导加载程序转移至用户空间,添加了对可调整大小的分区的支持。经过重定位之后,便可将代码移动和刷写到可维护且可测试的公共位置,仅由硬件抽象层 (HAL) 来实现 fastboot 的供应商专属部分。

统一 fastboot 和 recovery

由于用户空间 fastboot 和 recovery 类似,因此您可以将它们合并为一个分区/二进制文件。这样做的优势包括从整体上减少所占用的空间以及使用的分区数,并使 fastboot 和 recovery 能够共享其内核和库。

要支持 fastbootd,引导加载程序必须实现一个新的启动控制块 (BCB) 命令:boot-fastboot。要进入 fastbootd 模式,引导加载程序应将 boot-fastboot 写入 BCB 消息的命令字段,并保持 BCB 的 recovery 字段不变(以重启中断的恢复任务)。statusstagereserved 字段也保持不变。引导加载程序应该会在 BCB 命令中看到 boot-fastboot 时加载并启动到恢复映像。然后,recovery 会解析 BCB 消息并切换到 fastbootd 模式。

adb 命令

本部分介绍了集成 fastbootd 所需的另一个 adb 命令。该命令具有不同的行为,具体取决于是 system 还是 recovery 在执行该命令。

命令 说明
reboot fastboot
  • 重新启动到 fastbootd (system)。
  • 直接进入 fastbootd,而不重新启动 (recovery)。

新 fastboot 命令

本部分介绍了集成 fastbootd 所需的其他 fastboot 命令,包括用于刷写和管理逻辑分区的新命令。某些命令具有不同的行为,具体取决于是引导加载程序还是 fastbootd 在执行这些命令。

命令 说明
reboot recovery
  • 重新启动到 recovery(引导加载程序)。
  • 直接进入 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> 合并对超级分区元数据的更改。如果无法进行合并(例如,设备上的格式版本不受支持),则此命令将失败。可选的“擦除”参数会覆盖设备的元数据,而不是执行合并。

fastbootd 继续支持以下预先存在的 fastboot 命令。

命令 说明
flash <partition> [ <filename> ] 将文件写入刷写分区。设备必须处于解锁状态。
erase <partition> 擦除分区(不一定是安全擦除)。设备必须处于解锁状态。
getvar <variable> | all 显示引导加载程序变量或所有变量。如果变量不存在,则返回错误。
set_active <slot>

将指定的 A/B 启动槽设置为 active。下次尝试启动时,system 将从指定的槽启动。

对于 A/B 支持,槽是指可以单独启动的重复分区集。槽的名称为 ab 等,通过向分区名称添加后缀 _a_b 等加以区分。

reboot 正常重新启动设备。
reboot-bootloader(或 reboot bootloader 将设备重新启动到引导加载程序。

对引导加载程序的修改

引导加载程序继续支持刷写引导加载程序、无线装置和启动/恢复分区,之后设备将启动到 fastboot(用户空间)并刷写所有其他分区。引导加载程序应支持以下命令。

命令 说明
download 下载映像以进行刷写。
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ 刷写恢复/启动分区和引导加载程序。
reboot 重新启动设备。
reboot fastboot 重新启动到 fastboot。
reboot recovery 重新启动到 recovery。
getvar 获取刷写恢复/启动映像所需的引导加载程序变量(例如,current-slotmax-download-size)。
oem 由原始设备制造商 (OEM) 定义的命令。

引导加载程序不得允许刷写动态分区,并且必须返回错误:Partition should be flashed in fastbootd。对于改装的动态分区设备,fastboot 工具支持强制模式,以便在引导加载程序模式下直接刷写动态分区。引导加载程序可以支持此操作。例如,如果 system 是改装设备上的动态分区,则 fastboot --force flash system 允许引导加载程序刷写分区,而不是 fastbootd。此强制模式旨在灵活进行出厂刷写,不建议开发者使用。

Fastboot OEM HAL

要完全替换引导加载程序 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 oemCmdArgs 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 添加到 device.mk 中的 PRODUCT_PACKAGESPRODUCT_PACKAGES += fastbootd

  2. 确保将 fastboot HAL、引导控制 HAL 和运行状况 HAL 打包为恢复映像的一部分。

  3. 添加 fastbootd 所需的任何设备专属 sepolicy 权限。例如,fastbootd 需要对设备专属分区进行写入访问,才能刷写该分区。此外,fastboot HAL 实现还可能需要设备专属权限。

验证用户空间 fastboot

供应商测试套件 (VTS) 包括用于验证用户空间 fastboot 的测试。