Fastboot 是引导加载程序模块和模式的名称。Android 10 及更高版本通过将 fastboot 实现从引导加载程序重新定位到用户空间,来支持可调整大小的分区。这种重新定位使得可以将刷写代码移至可维护且可测试的通用位置,而只有 fastboot 的供应商特定部分通过硬件抽象层 (HAL) 实现。此外,Android 12 及更高版本支持通过添加的 fastboot 命令刷写 ramdisk。
统一 fastboot 和恢复
由于用户空间 fastboot 和恢复类似,您可以将它们合并到一个分区或二进制文件中。这样具有诸多优点,例如,占用空间更少、总分区数更少,并且 fastboot 和恢复可以共享其内核和库。
Fastbootd 是用户空间守护程序和模式的名称。为了支持 fastbootd,引导加载程序必须实现新的引导控制块 (BCB) 命令 boot-fastboot。为了进入 fastbootd 模式,引导加载程序必须将 boot-fastboot 写入 BCB 消息的命令字段,并保持 BCB 的 recovery 字段不变(以便重启任何中断的恢复任务)。status、stage 和 reserved 字段也保持不变。引导加载程序会在 BCB 命令字段中看到 boot-fastboot 时加载并启动到恢复映像。然后,恢复会解析 BCB 消息并切换到 fastbootd 模式。
ADB 命令
本部分介绍了用于集成 fastbootd 的 adb 命令。该命令具有不同的结果,具体取决于它是由系统还是恢复执行的。
| 命令 | 说明 |
|---|---|
reboot fastboot |
|
Fastboot 命令
本部分介绍了用于集成 fastbootd 的 fastboot 命令,包括用于刷写和管理逻辑分区的新命令。某些命令具有不同的结果,具体取决于它们是由引导加载程序还是 fastbootd 执行的。
| 命令 | 说明 |
|---|---|
reboot recovery |
|
reboot fastboot |
重启进入 fastbootd。 |
getvar is-userspace |
|
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 启动槽设置为 对于 A/B 支持,槽是分区的重复集合,可以独立启动。槽的命名方式为 |
reboot |
正常重启设备。 |
reboot-bootloader(或 reboot bootloader) |
将设备重启到启动加载程序。 |
fastboot fetch vendor_boot <out.img> |
Android 12 及更高版本中使用此命令来支持刷写供应商 ramdisk。 获取整个分区大小和 chunk 大小。获取每个 chunk 的数据,然后将数据拼接在一起形成 有关详情,请参阅 |
fastboot flash vendor_boot:default <vendor-ramdisk.img> |
Android 12 及更高版本中使用此命令来支持刷写供应商 ramdisk。 这是 flash 命令的特殊变体。它执行 有关详情,请参阅 |
fastboot flash vendor_boot:<foo> <vendor-ramdisk.img> |
Android 12 及更高版本中使用此命令来支持刷写供应商 ramdisk。 提取 有关详情,请参阅 |
Fastboot 和启动加载程序
启动加载程序刷写 bootloader、radio 和 boot/recovery 分区,之后设备启动进入 fastboot(用户空间)并刷写所有其他分区。启动加载程序应支持以下命令。
| 命令 | 说明 |
|---|---|
download |
下载要刷写的镜像。 |
flash recovery <image>/ flash boot <image>/ flash bootloader <image>/ |
刷写 recovery/boot 分区和启动加载程序。 |
reboot |
重启设备。 |
reboot fastboot |
重启到 fastboot。 |
reboot recovery |
重启到 recovery。 |
getvar |
获取刷写 recovery/boot 镜像所需的启动加载程序变量(例如,current-slot 和 max-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 命令。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
在
device.mk中的PRODUCT_PACKAGES中添加fastbootd:PRODUCT_PACKAGES += fastbootd。确保将 fastboot HAL、启动控制 HAL 和健康 HAL 打包为 recovery 镜像的一部分。
添加
fastbootd所需的任何设备特定的 SELinux 权限。例如,fastbootd需要对设备特定分区的写入权限才能刷写该分区。此外,fastboot HAL 实现也可能需要设备特定的权限。
要验证用户空间 fastboot,请运行供应商测试套件 (VTS)。
刷写供应商 ramdisk
Android 12 及更高版本提供了通过添加 fastboot 命令来刷写 ramdisk 的支持,该命令从设备中提取完整的 vendor_boot 镜像。该命令提示主机端 fastboot 工具读取供应商启动标头、重新镜像并刷写新镜像。
为了提取完整的 vendor_boot 镜像,在 Android 12 的 fastboot 协议和 fastbootd 实现的协议中都添加了命令 fetch:vendor_boot。请注意,fastbootd确实实现了此命令,但启动加载程序本身可能没有。OEM 可以将 fetch:vendor_boot 命令添加到其启动加载程序协议的实现中。但是,如果在启动加载程序模式下无法识别该命令,则在启动加载程序模式下刷写单个供应商 ramdisk 不是供应商支持的选项。
启动加载程序更改
命令 getvar:max-fetch-size 和 fetch:name 在 fastbootd 中实现。要支持在启动加载程序中刷写供应商 ramdisk,您必须实现这两个命令。
Fastbootd 更改
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)。
当 offset 或 partition_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以确定 chunk 大小。 - 调用
getvar partition-size:vendor_boot[_a]以确定整个分区的大小。 - 为每个 chunk 调用
fastboot fetch vendor_boot[_a]:offset:size。(chunk 大小大于vendor_boot大小,因此通常只有一个 chunk。) - 将数据拼接在一起,形成
out.img。
- 调用
fastboot flash vendor_boot:default vendor-ramdisk.img这是 flash 命令的特殊变体。它提取
vendor_boot镜像,如同调用了fastboot fetch一样。fastboot flash vendor_boot:foo vendor-ramdisk.img提取
vendor_boot image,如同调用了fastboot fetch一样。- 如果供应商启动标头是版本 3,则返回错误。
如果供应商启动标头是版本 4,它会执行以下操作
- 查找名称为
ramdisk_<var><foo></var>的供应商 ramdisk 片段。如果未找到,或者存在多个匹配项,则返回错误。 - 将供应商 ramdisk 片段替换为给定的镜像。
- 重新计算供应商 ramdisk 表中每个大小和偏移量。
- 刷写新的
vendor_boot镜像。
- 查找名称为
如果未指定 <foo>,它会尝试查找
ramdisk_。
mkbootimg
名称 default 保留在 Android 12 及更高版本中用于命名供应商 ramdisk 片段。虽然 fastboot flash vendor_boot:default 语义保持不变,但您绝不能将 ramdisk 片段命名为 default。
SELinux 更改
在 fastbootd.te 中进行了更改,以支持刷写供应商 ramdisk。