在 Android 12 中实现 bootconfig

在 Android 12 中,bootconfig 功能取代了 Android 11 及更低版本中使用的 androidboot.* 内核 cmdline 选项。bootconfig 功能是一种机制,用于将配置详情从构建和启动加载程序传递到 Android 12。

此功能提供了一种将 Android 用户空间的配置参数与内核的配置参数分离的方法。将冗长的 androidboot.* 内核参数移动到 bootconfig 文件中,从而在内核 cmdline 中创建了空间,并使其可用于未来的扩展。

内核和 Android 用户空间都必须支持 bootconfig

  • 首个具有此支持的发布版本:Android 12
  • 首个具有此支持的内核版本:12-5.4.xx 内核

设备实现 bootconfig 功能,这些设备使用 12-5.10.xx 内核版本启动。如果您要升级设备,则无需实现此功能。

示例和源代码

当您查看本节中的示例和源代码时,请注意 bootconfig 代码的格式与 Android 11 及更低版本中使用的内核 cmdline 格式只有细微差别。但是,以下差异对您的使用非常重要

  • 参数必须用换行转义符 \n 分隔,而不是空格。

启动加载程序示例

有关启动加载程序示例,请参阅 Cuttlefish U-boot 参考启动加载程序实现。下面列出了参考中的两个提交。第一个提交将启动标头版本支持更新到最新版本。在该示例中,第一个提交将版本支持更新(或升级)到下一个版本 v4。第二个提交执行两项操作;它添加了 bootconfig 处理,并演示了在运行时添加参数

构建示例

有关显示 mkbootimg 更改以使用供应商启动标头 v4 构建 vendor_boot.img 的构建示例,请参阅 bootconfig 的 mkbootimg 更改。请参阅 Cuttlefish 更改以执行以下操作

实现

合作伙伴必须在其启动加载程序中添加支持,并将他们的构建时 androidboot.* 参数从内核 cmdline 移动到 bootconfig 文件。实现此变更的最佳方法是以增量方式进行;请参阅增量实现和验证部分,以了解有关遵循增量流程的信息。

如果您有更改在 /proc/cmdline 文件中搜索 androidboot.* 参数,请将它们指向 /proc/bootconfig 文件。 ro.boot.* 属性是使用新的 bootconfig 值设置的,因此您无需为使用这些属性的代码进行更改。

构建更改

首先,将您的启动标头版本升级到版本 4

- BOARD_BOOT_HEADER_VERSION := 3

+ BOARD_BOOT_HEADER_VERSION := 4

添加 bootconfig 内核 cmdline 参数。这会使内核查找 bootconfig 部分

BOARD_KERNEL_CMDLINE += bootconfig

bootconfig 参数是从 BOARD_BOOTCONFIG 变量中的参数创建的,这与内核 cmdline 从 BOARD\_KERNEL\_CMDLINE 创建的方式非常相似。

任何 androidboot.* 参数都可以按原样移动,类似于以下内容

- BOARD_KERNEL_CMDLINE += androidboot..selinux=enforcing

+ BOARD_BOOTCONFIG += androidboot..selinux=enforcing

引导加载程序更改

引导加载程序在跳转到内核之前设置 initramfs内核引导配置 搜索引导配置部分,并查找它是否位于 initramfs 的末尾,并带有预期的尾部。

引导加载程序从供应商引导镜像标头获取 vendor_boot.img 布局信息。

Diagram of bootconfig memory allocation layout

图 1. Android 12 引导配置内存分配

引导加载程序在内存中创建引导配置部分。引导配置部分包含以下内存分配:

  • 参数
  • 4 字节大小 parameters size
  • 4 字节大小 parameters checksum
  • 12 字节引导配置魔术字符串 (#BOOTCONFIG\n)

参数来自两个来源:构建时已知的参数和构建时未知的参数。必须添加未知参数。

构建时已知的参数被打包到 vendor_boot 镜像末尾的引导配置部分中。该部分的大小(以字节为单位)存储在供应商引导标头字段 vendor_bootconfig_size 中。

构建时未知的参数仅在引导加载程序中的运行时才知道。这些参数必须在应用引导配置尾部之前添加到引导配置参数部分的末尾。

如果需要在应用引导配置尾部之后添加任何参数,请覆盖尾部并重新应用它。

增量实施和验证

通过按照本节中给出的过程逐步实施引导配置功能。在添加引导配置参数时,保持内核 cmdline 参数不变。

以下是增量实施的步骤,以及验证

  1. 进行 引导加载程序和构建更改,然后执行以下操作
    1. 使用 BOARD_BOOTCONFIG 变量添加新的引导配置参数。
    2. 保持内核 cmdline 参数不变,以便设备可以继续正常启动。这使得调试和验证更加容易。
  2. 验证 您的工作,方法是检查 /proc/bootconfig 的内容。验证您在设备启动后是否看到新添加的参数。
  3. 移动 内核 cmdline 中的 androidboot.* 参数到引导配置,使用 BOARD_BOOTCONFIG 变量和引导加载程序。
  4. 验证 每个参数是否存在于 /proc/bootconfig 中,并且 它们不在 /proc/cmdline 中。如果可以验证这一点,则您的实施已成功。

OTA 升级和降级注意事项

当您管理 Android 不同版本或不同内核版本之间的 OTA 升级和降级时,应格外小心。

Android 12 是第一个支持引导配置的版本。如果降级到之前的任何版本,则必须使用内核 cmdline 参数而不是引导配置。

内核版本 12-5.4 及更高版本支持引导配置。如果降级到之前的任何版本(包括 11-5.4),则必须使用内核 cmdline 参数。

从 Android 11 及更低版本升级到 Android 12 及更高版本可以继续使用内核 cmdline 参数。内核版本升级也是如此。

故障排除

当您执行验证步骤时,如果您在 /proc/bootconfig 中没有看到预期的参数,请检查 logcat 中的内核日志。如果内核支持引导配置,则始终存在引导配置的日志条目。

示例日志输出

$ adb logcat | grep bootconfig
02-24 17:00:07.610     0     0 I Load bootconfig: 128 bytes 9 nodes

如果您看到返回错误日志,则加载引导配置时出现问题。要查看不同的错误类型,请查看 init/main.c