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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM