将 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。