Virtual AB系统

概览

Virtual AB系统

(1)无缝升级:virtual AB和AB系统一样,支持无缝升级

(2)回滚:Virtual AB支持系统回滚。当系统升级失败的时候,设备会自动回滚到旧的系统版本。

(3)省空间:在Virtual AB中,super分区采用dm-snapshot技术来进行升级,不需要分AB系统,所以virtual AB系统比AB系统节省了很多空间。

背景

Device-mapper技术

image

System分区的dm设备挂载栈如图上所示:

(1)最底层是物理分区:super分区

(2)第二层是用dm-linear技术实现的动态逻辑分区:为/dev/block/mapper/system_a分区

(3)第三层是用dm-verity技术实现的校验分区:为/dev/block/mapper/system-verity分区

(4)最后system分区挂载在/dev/block/mapper/system-verity分区上面

Dm-snapshot技术概览

image

Dm-snapshot分区由四个设备组成:

(1)通常system分区被作为base设备

(2)COW设备用来保存base设备所改动的文件。

(3)Dm-snapshot设备由snapshot目标创建。往dm-snapshot设备写文件,会写到COW设备中。从dm-snapshot设备读文件,则会从base设备和COW设备中读文件,如果文件通过dm-snapshot改变过,则从COW设备中读;否则从base设备中读。

(4)dm-snapshot-origin设备由snapshot-origin目标创建。读写文件都是从base设备中进行读写。

BootControl服务

Misc分区中相关的数据结构。

(1)bootloader_message_ab数据结构

struct bootloader_message_ab {
    struct bootloader_message message;
    char slot_suffix[32];  // 为bootloader_control数据结构,相关的信息都存放于此
    char update_channel[128];
    char reserved[1888];
};

(2)bootloader_control 数据结构

struct bootloader_control {
    // NUL terminated active slot suffix.
    char slot_suffix[4];  // 存放_a或者_b
    // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
    uint32_t magic;  // 为0x42414342
    // Version of struct being used (see BOOT_CTRL_VERSION).
    uint8_t version;  // 为1
    // Number of slots being managed.
    uint8_t nb_slot : 3;  // slot的数目,一般为2(AB)
    // Number of times left attempting to boot recovery.
    uint8_t recovery_tries_remaining : 3;
    // Status of any pending snapshot merge of dynamic partitions.
    uint8_t merge_status : 3;
    // Ensure 4-bytes alignment for slot_info field.
    uint8_t reserved0[1];
    // Per-slot information.  Up to 4 slots.
    struct slot_metadata slot_info[4];  // 最大支持4个slot
    // Reserved for further use.
    uint8_t reserved1[8];
    // CRC32 of all 28 bytes preceding this field (little endian
    // format).
    uint32_t crc32_le;
} __attribute__((packed));

(3)slot_metadata数据结构

struct slot_metadata {
    // Slot priority with 15 meaning highest priority, 1 lowest
    // priority and 0 the slot is unbootable.
    uint8_t priority : 4; // slot的优先级,优先级高的先启动,最高为15,最低为1。为0时不给启动
    // Number of times left attempting to boot this slot.
    uint8_t tries_remaining : 3; // 该slot能重启的次数
    // 1 if this slot has booted successfully, 0 otherwise.
    uint8_t successful_boot : 1; // 当该slot成功启动的时候,该位置1
    // 1 if this slot is corrupted from a dm-verity corruption, 0
    // otherwise.
    uint8_t verity_corrupted : 1; // 目前无人设此值1
    // Reserved for further use.
    uint8_t reserved : 7;
} __attribute__((packed));

Virtual AB的分区概览图

image

​ 除了super分区,其他分区如果需要升级,都需要分为AB分区。因为super分区不用分AB,而其他分区又比较小,所以virtual AB比AB系统要节省很多空间。

Snapshot和合并流程

升级前的分区概览

image

OTA升级过程中

image

当update_engine开始写一个新的system分区的时候,它会创建以下设备:

(1)基于system_a设备创建system_b_base设备(dm-5设备)

(2)在/data/gsi/ota/目录下创建system_b-cow-img.img.0000文件,然后通过/dev/block/loop0设备进行挂载。然后创建dm-6设备将其映射到system_cow上

(3)创建dm-7(dm-snapshot)设备,将起映射为system_b

(4)打开dm-snapshot设备,将OTA升级包中的system.img写进去,此时写的内容,就写到了/data/gsi/ota/system_b-cow-img.img.0000文件中。

(5)升级成功之后,调用boot_ctrl中的SetActiveBootSlot函数:将_a(目前slot)的priority值设小(如果最大就减1)。然后将_b(要升级的slot) 的priority值设为15(最大),以及tries_remaining的值设为6(升级失败,最多可以重启6次)。

//在升级过程中创建设备:
[INFO:dynamic_partition_control_android.cc(319)] Loaded metadata from slot B in /dev/block/by-name/super
 update_engine: Successfully unmapped snapshot system_b
vold    : Disk at 253:5 changed
 update_engine: [libfs_mgr]Created logical partition system_b-base on device /dev/block/dm-5
vold    : Disk at 7:1 changed
gsid    : Created loop device /dev/block/loop1 for file /data/gsi/ota/system_b-cow-img.img.0000
 update_engine: Mapped system_b-cow-img to /dev/block/loop1
update_engine: Calling GetMappedImageDevice with local image manager; device /dev/block/loop1may not be available in first stage init! 
vold    : Disk at 253:6 changed
update_engine: Mapped COW device for system_b at /dev/block/dm-6
vold    : Disk at 253:7 changed
update_engine: Mapped system_b as snapshot device at /dev/block/dm-7
[INFO:dynamic_partition_control_android.cc(173)] Succesfully mapped system_b to device mapper (force_writable = 1); device path at /dev/block/dm-7
//升级成功之后,调用boot_ctrl中的SetActiveBootSlot函数:
[INFO:postinstall_runner_action.cc(376)] All post-install commands succeeded

OTA升级完成后,重启,uboot端slot切换流程。

(1)遍历所有slot,如果该slot的tries_remaining为0则跳过(不从该slot启动,当_b系统无法启动,则在这里切换回_a系统)。然后选择priority最高的slot进行启动(升级后,_b最高)

(2)如果当前slot的successful_boot为0(OTA升级重启成功后,会将此值设为1),则tries_remaining的值减1

(3)将slot_suffix的值改为_b

OTA升级完成后,重启过程中

image

(1)创建dm-0设备,作为system_b_base设备(映射super分区中的system分区)

(2)创建dm-1设备,作为system_b-cow-img设备(映射data分区中的system_b-cow-img.img.0000文件)

(3)创建dm-2设备,映射为system_cow设备

(4)创建dm-3设备,映射为dm-snapshot设备(system_b分区)

(5)将system分区挂载在dm-3上(dm-snapshot设备)

(6)然后系统启动读system分区的时候,如果读到的文件,在system_cow中记录到有改变,则直接读system_cow中的文件。

// 在first stage init过程中创建dm设备:
init: Creating logical partitions with snapshots as needed
random: init: uninitialized urandom read (16 bytes read)
init: [libfs_mgr]Created logical partition system_b-base on device /dev/block/dm-0
random: init: uninitialized urandom read (16 bytes read)
init: [libfs_mgr]Created logical partition system_b-cow-img on device /dev/block/dm-1
init: Mapped system_b-cow-img to 253:1
init: Mapped COW device for system_b at /dev/block/dm-2
init: Mapped system_b as snapshot device at /dev/block/dm-3

重启完成后,开始snapshot-merge

image

(1)重启成功后,调用BootControl的MarkBootSuccessful函数,将successful_boot和tries_remaining设为1。

(2)将dm-snapshot设备设为merge状态,将cow设备和base设备的内容进行合并。

(3)umaped相关的设备

(4)合并成功之后,删除/data/gsi/ota目录下的img文件以及/metadata/ota目录下的相关文件。

// 1. 启动完成之后,调用BootControl的MarkBootSuccessful函数
[INFO:cleanup_previous_update_action.cc(137)] Boot completed, waiting on markBootSuccessful()
// 2. 进行合并,大概30秒左右
17:34:51.739365 [INFO:cleanup_previous_update_action.cc(338)] Attempting to initiate merge.
设置dm-snapshot为merge:
update_engine: Successfully switched snapshot device to a merge target: system_b
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 8%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 20%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 27%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 33%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 40%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 48%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 55%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 63%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 70%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 78%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 85%.
[INFO:cleanup_previous_update_action.cc(302)] Waiting for merge to complete: 93%.
// 3. unmap设备,然后清除data目录下的img文件
update_engine: Removing all update state. 
// 4. merge完成
	17:35:21.018875 [INFO:cleanup_previous_update_action.cc(262)] Merge finished with state MergeCompleted.

Snapshot-merge完成后

image

异常处理

Update_verifier程序

Update_verifier程序:如果没有配置checkpoint,则会调用boot_ctrl的module->markBootSuccessful,导致android如果升级失败,会无法回退。

解决办法:配置checkpoint。

posted @ 2021-04-20 22:02  pyjetson  阅读(7866)  评论(1)    收藏  举报