原文:https://source.android.com/devices/tech/ota/device_code
恢复系统包括一些用于插入设备专属代码的钩子,以便 OTA 更新还可以更新设备中除 Android 系统以外的其他部分(例如,基带或无线电处理器)。
下面的部分和示例对 yoyodyne 供应商生产的 tardis 设备进行了自定义。
分区映射
自 Android 2.3 版本起,该平台就开始支持 eMMc 闪存设备以及在这些设备上运行的 ext4 文件系统。此外,该平台还支持内存技术设备 (MTD) 闪存设备以及较旧版本的 yaffs2 文件系统。
分区映射文件由 TARGET_RECOVERY_FSTAB 指定;recovery 二进制文件和软件包编译工具均使用该文件。您可以在 BoardConfig.mk 中的 TARGET_RECOVERY_FSTAB 中指定映射文件的名称。
分区映射文件示例可能如下所示:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
除 /sdcard
(可选)之外,本示例中的所有装载点都必须进行定义(设备也可以添加额外的分区)。支持的文件系统类型有下列 5 种:
-
yaffs2
-
yaffs2 文件系统位于 MTD 闪存设备的顶部。MTD 分区的名称必须是“device”,且该名称必须显示在
/proc/mtd
中。 mtd
-
原始 MTD 分区,用于可引导分区(例如 boot 和 recovery)。MTD 实际上并未装载,但是装载点会被用作定位分区的键。
/proc/mtd
中 MTD 分区的名称必须是“device”。 ext4
- ext4 文件系统位于 eMMc 闪存设备的顶部。块设备的路径必须是“device”。 emmc
- 原始 eMMc 块设备,用于可引导分区(例如 boot 和 recovery)。与 mtd 类型相似,eMMc 从未实际装载,但装载点字符串会被用于定位表中的设备。 vfat
-
FAT 文件系统位于块设备的顶部,通常用于外部存储设备(如 SD 卡)。该设备是块设备;device2 是系统装载主设备失败时尝试装载的第二个块设备(旨在与可能(或可能没有)使用分区表进行格式化的 SD 卡兼容)。
所有分区都必须装载到根目录下(即装载点值必须以斜线开头,且不含其他斜线)。此限制仅适用于在 recovery 中装载文件系统;主系统可随意将其装载在任何位置。目录
/boot
、/recovery
和/misc
应为原始类型(mtd 或 emmc),而目录/system
、/data
、/cache
和/sdcard
(如果有)则应为文件系统类型(yaffs2、ext4 或 vfat)。
从 Android 3.0 开始,recovery.fstab 文件就新添了额外的可选字段,即“options”。目前,唯一定义的选项是“length”,它可以让您明确指定分区的长度。对分区重新进行格式化(例如,在执行数据清除/恢复出厂设置操作过程中对用户数据分区进行格式化,或在安装完整 OTA 更新包的过程中对系统分区进行格式化)时会使用此长度。如果长度值为负数,则将长度值与真正的分区大小相加,即可得出要格式化的大小。例如,设置“length=-16384”即表示在对该分区重新进行格式化时,该分区的最后 16k 将不会被覆盖。该选项支持加密 userdata 分区(在这里,加密元数据会存储在不得被覆盖的分区的末尾部分)等功能。
注意:device2 和 options 字段均为可选字段,在解析时会产生歧义。如果该行第 4 个字段中的条目以“/”字符开头,则被视为device2 条目;如果该条目不是以“/”字符开头,则被视为 options 字段。
启动动画
设备制造商可以自定义在启动 Android 设备时显示的动画。为此,请构建一个根据 bootanimation 格式中的规范组织和定位的 .zip 文件。
对于 Android Things 设备,您可以在 Android Things 控制台中上传压缩文件,以便在所选产品中包含图片。
注意:这些图片必须符合 Android 品牌指南。
恢复界面
要支持配备不同可用硬件(物理按钮、LED、屏幕等)的设备,您可以自定义恢复界面以显示状态,并访问每台设备的手动操作隐藏功能。
您的目标是编译一个包含一些 C++ 对象的小型静态库,以提供设备专属功能。默认情况下会使用bootable/recovery/default_device.cpp
文件,该文件正好可在为设备编写此文件的版本时供您复制。
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
Headers 和 Item 函数
Device 类需要相关函数来返回隐藏恢复菜单中出现的标头和项。Headers 介绍了如何操作菜单(例如,用于更改/选择突出显示项的控制功能)。
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
注意:长行会被截断(而非换行),因此请留意您设备的屏幕宽度。
自定义 CheckKey
接下来,请定义您设备的 RecoveryUI 实现。本例假设 tardis 设备配有屏幕,因此,您可以沿用内置 ScreenRecoveryUIimplementation(请参阅有关无屏幕设备的说明)。可通过 ScreenRecoveryUI 自定义的唯一函数是CheckKey()
,该函数会执行初始异步键处理操作:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
KEY 常量
KEY_* 常量在 linux/input.h
中定义。无论后续恢复流程执行什么操作,都会调用 CheckKey()
:菜单切换为关闭状态时、菜单处于打开状态时、软件包安装期间以及用户数据清除期间等。它会返回下列 4 个常量中的一个:
- TOGGLE. 切换菜单的显示状态以及(或)开启/关闭文本日志
- REBOOT. 立即重新启动设备
- IGNORE. 忽略此按键
- ENQUEUE. 向队列中添加此按键以同步使用(即在启用显示时供恢复菜单系统使用)
每次在 key-down 事件后执行同一按键的 key-up 事件时都会调用 CheckKey()
(事件 A-down B-down B-up A-up 序列只会调用 CheckKey(B)
)。CheckKey()
可以调用 IsKeyPressed()
,以确定是否有其他键被按下(在上述键事件的序列中,如果 CheckKey(B)
调用了 IsKeyPressed(A)
,则会返回 true)。
CheckKey()
可以在其类中保持状态,这有助于检测键的序列。本示例展示的是一个稍微复杂的设置:按住电源键并按下音量提高键可切换显示状态,连续按五次电源按钮可立即重新启动设备(无需使用其他键):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
ScreenRecoveryUI
如果您将自己的图片(错误图标、安装动画、进度条)与 ScreenRecoveryUI 搭配使用,则可以设置变量 animation_fps
来控制动画的速度(以每秒帧数 (FPS) 为单位)。
注意:通过最新的 interlace-frames.py
脚本,您可以将 animation_fps
信息存储到图片中。在早期版本的 Android 中,您必须自行设置 animation_fps
。
要设置变量 animation_fps
,请替换子类中的