User Data Checkpoint(UDC)


背景

​ 由于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 的 <fs_mgr_flags> 部分。

​ 对于其他文件系统,UDC会使用dm-bow,必须在内核配置中启用 dm-bow。对于在 /data 装载的设备,请将 checkpoint=block 标记添加到 fstab 的 <fs_mgr_flags> 部分。

源码解析

1. Checkpoint模块

init: Calling: /system/bin/vdc checkpoint needsCheckpoint -> vold->needsCheckpoint(&enabled) -> cp_needsCheckpoint

1.1 cp_needsCheckpoint

bool cp_needsCheckpoint() {
    std::lock_guard<std::mutex> lock(isCheckpointingLock);

    // 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<IBootControl> module = IBootControl::getService();

    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的流程

  1. mount_all阶段挂载data分区时

    • 调用cp_needsCheckpoint函数:如果是OTA升级阶段或者是第一次刷固件的时候(调用boot_ctrl判断当前slot是否已经Marked Successful了,如果没有,表明此时处于OTA升级阶段或者是第一次刷固件的时候,需要进行checkpoint),则返回true;正常情况就是false
    • 如果上面返回true,则调用UpdateCheckpointPartition函数:mount data分区的时候加上checkpoint=disable选项。然后如果OTA升级失败了,就可以恢复到这个点上了。
  2. ActivityManager finishBoot阶段

    • 调用cp_commitChanges函数:调用boot_ctrlmarkBootSuccessful函数,以及用checkpoint=enable选项,重新挂载data分区(f2fs文件系统就会自动将对data分区的改动写入data分区中,表明OTA升级成功)。
    ActivityManager: About to commit checkpoint
    

如果在mount_allfinishboot期间,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配置

  1. device/softwinner/ceres-common/init.sun50iw10p1.rc文件的on fs中添加
mount_all /vendor/etc/fstab.sun50iw10p1 --early
  1. device/softwinner/ceres-common/init.sun50iw10p1.rc文件的on late-fs中添加
mount_all /vendor/etc/fstab.sun50iw10p1 --late
  1. device/softwinner/ceres-b3/fstab.sun50iw10p1文件的data分区中添加latemountcheckpoint=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
  1. 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
  1. device/softwinner/ceres-b3/BoardConfig.mk文件中添加:
BOARD_USES_METADATA_PARTITION := true

验证

要测试您的 UDC 实现,请运行 VTS 测试的 VtsKernelCheckpointTest 测试集。

参考

1. f2fs: checkpoint disabling
https://lwn.net/Articles/763072/


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM