User Data Checkpoint(UDC)

目录背景实现机制源码解析1. Checkpoint模块1.1 cp_needsCheckpointcheckpointing的流程mount_all阶段挂载data分区时ActivityManager finishBoot阶段管理 keymaster 密钥监控运行状况checkpoint配置验证参考
背景
由于AB升级的回滚机制只支持到early_boot阶段,如果OTA升级的过程中,data分区被修改了,并且OTA升级失败了,则data分区是无法回滚到之前的状态的。UDC功能是为了解决OTA升级失败后,当data分区被修改后,不支持回滚data分区的问题。UDC同时支持绑定key版本以及防止key回滚的功能。
实现机制
对于f2fs,UDC添加checkpoint功能到4.20版本的内核中,其他版本的内核也可以移植该功能过去。所以,f2fs系统是默认支持checkpoint功能的。对于在 /data 装载的设备,请将 checkpoint=fs 标记添加到 fstab 的
对于其他文件系统,UDC会使用dm-bow,必须在内核配置中启用 dm-bow。对于在 /data 装载的设备,请将 checkpoint=block 标记添加到 fstab 的
源码解析
1. Checkpoint模块
init: Calling: /system/bin/vdc checkpoint needsCheckpoint -> vold->needsCheckpoint(&enabled) -> cp_needsCheckpoint
1.1 cp_needsCheckpoint
bool cp_needsCheckpoint() {
std::lock_guard
// Make sure we only return true during boot. See b/138952436 for discussion
// 已经checkpoint过了,就直接返回了
if (needsCheckpointWasCalled) return isCheckpointing;
needsCheckpointWasCalled = true;
bool ret;
std::string content;
sp
if (isCheckpointing) return isCheckpointing;
// 正常情况isSlotMarkedSuccessful返回为true,不走进去
if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
// OTA阶段为false,走这里;返回true
isCheckpointing = true;
return true;
}// const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
// 找不到文件,返回false
ret = android::base::ReadFileToString(kMetadataCPFile, &content);
if (ret) {
ret = content != "0";
isCheckpointing = ret;
return ret;
}
return false; // 正常情况返回false
}
checkpointing的流程
mount_all阶段挂载data分区时
调用cp_needsCheckpoint函数:如果是OTA升级阶段或者是第一次刷固件的时候(调用boot_ctrl判断当前slot是否已经Marked Successful了,如果没有,表明此时处于OTA升级阶段或者是第一次刷固件的时候,需要进行checkpoint),则返回true;正常情况就是false
如果上面返回true,则调用UpdateCheckpointPartition函数:mount data分区的时候加上checkpoint=disable选项。然后如果OTA升级失败了,就可以恢复到这个点上了。
ActivityManager finishBoot阶段
调用cp_commitChanges函数:调用boot_ctrl的markBootSuccessful函数,以及用checkpoint=enable选项,重新挂载data分区(f2fs文件系统就会自动将对data分区的改动写入data分区中,表明OTA升级成功)。
ActivityManager: About to commit checkpoint
如果在mount_all到finishboot期间,OTA升级失败并重启了,则写入到data分区的数据重启之后全部无效。这就达到了data分区回滚的目的了。
管理 keymaster 密钥
Keymaster 密钥用于设备加密或其他目的。为管理这些密钥,Android 特地推迟到提交检查点之后才调用密钥删除命令。
监控运行状况
该线程在开机的post-fs-data:vdc checkpoint prepareCheckpoint阶段运行,要在start checkpoint之后才会运行该线程。运行状况守护进程会检查是否有足够的磁盘空间来创建检查点。运行状况守护进程位于 Checkpoint.cpp 中的 cp_healthDaemon 内。
默认表现:当data分区的可用空间小于100M的时候,它就会提交检查点(cp_commitChanges提交对data分区的修改)或者重启设备(放弃对data分区的修改)。
运行状况守护进程具有以下可配置的行为:
ro.sys.cp_msleeptime:控制设备检查磁盘使用情况的频率。(隔多久去检查磁盘的可用空间,默认为1秒钟)
ro.sys.cp_min_free_bytes:控制运行状况守护进程查找的最小值。(可用空间的最小值,默认为100M)
ro.sys.cp_commit_on_full:控制运行状况守护进程在磁盘已满时,是重新启动设备还是提交检查点并继续运行。
checkpoint配置
在device/softwinner/ceres-common/init.sun50iw10p1.rc文件的on fs中添加
mount_all /vendor/etc/fstab.sun50iw10p1 --early
在device/softwinner/ceres-common/init.sun50iw10p1.rc文件的on late-fs中添加
mount_all /vendor/etc/fstab.sun50iw10p1 --late
在device/softwinner/ceres-b3/fstab.sun50iw10p1文件的data分区中添加latemount和checkpoint=fs
/dev/block/by-name/UDISK /data f2fs noatime,nosuid,nodev,discard wait,check,formattable,quota,reservedsize=33554432,fileencryption=aes-256-xts:aes-256-cts,latemount,checkpoint=fs
在device/softwinner/ceres-b3/fstab.sun50iw10p1文件的metadata分区中添加first_stage_mount。
/dev/block/by-name/metadata /metadata ext4 nodev,noatime,nosuid,errors=panic wait,first_stage_mount,formattable,check
在device/softwinner/ceres-b3/BoardConfig.mk文件中添加:
BOARD_USES_METADATA_PARTITION := true
验证
要测试您的 UDC 实现,请运行 VTS 测试的 VtsKernelCheckpointTest 测试集。
参考
1. f2fs: checkpoint disabling
https://lwn.net/Articles/763072/