虛擬 A/B 概述

Android 有兩種更新機制:A/B(無縫)更新和非 A/B 更新。為了降低代碼複雜度並增強更新過程,在 Android 11 中,這兩種機制通過虛擬 A/B 統一起來,以最小的存儲成本為所有設備帶來無縫更新。 Android 12 提供了虛擬 A/B 壓縮選項來壓縮快照分區。在 Android 11 和 Android 12 中,以下內容均適用:

  • 虛擬A / B更新是無縫像A / B更新。虛擬 A/B 更新最大限度地減少了設備離線和不可用的時間。
  • 虛擬A / B更新可以回滾。如果新操作系統啟動失敗,設備會自動回滾到之前的版本。
  • 虛擬A / B更新通過複製只由引導加載程序使用的分區使用最少的額外空間。其他更新的分區快照

背景和術語

本節定義了術語並描述了支持虛擬 A/B 的技術。

設備映射器

Device-mapper 是 Android 中經常使用的 Linux 虛擬塊層。與動態分區,分區等/system層疊裝置的堆疊:

  • 在堆棧的底層是物理超級分區(例如, /dev/block/by-name/super )。
  • 在中間的是一個dm-linear裝置,指定該塊的超級分區形式給定的分區。這表現為/dev/block/mapper/system_[a|b]的A / B設備上,或/dev/block/mapper/system的非A / B設備上。
  • 在頂部駐留在dm-verity的裝置,用於驗證的分區上創建。此,該上塊設備驗證dm-linear設備被正確地簽名。它顯示為/dev/block/mapper/system-verity ,並且是源/system的安裝點。

圖1顯示了下堆棧/system安裝點的樣子。

Partition stacking underneath system

圖1. /系統安裝點下堆棧

dm-快照

虛擬A / B依賴於dm-snapshot ,用於快照存儲設備的狀態的設備映射器模塊。當使用dm-snapshot ,也有打四的設備:

  • 基地設備是真實快照設備。在此頁面上,基本設備始終是動態分區,例如係統或供應商。
  • 寫入時複製(COW)設備,用於記錄改變到基部設備。它可以是任何大小,但必須足夠大以容納對基本設備的所有更改。
  • 快照裝置使用所創建的snapshot目標。對快照設備的寫入將寫入 COW 設備。從快照設備讀取從基本設備​​或 COW 設備讀取,具體取決於正在訪問的數據是否已被快照更改。
  • 原點裝置使用所創建的snapshot-origin目標。直接從基礎設備讀取到原始設備。寫入原始設備直接寫入基本設備,但原始數據通過寫入 COW 設備進行備份。

Device mapping for dm-snapshot

對於DM-快照圖2.設備映射

壓縮快照

在Android中12,由於對空間的要求/data分區可以是高,你可以使您的構建,解決的高空間需求壓縮的快照/data分區。

虛擬 A/B 壓縮快照建立在 Android 12 中提供的兩個新組件之上:

  • dm-user ,類似於FUSE內核模塊,它允許用戶空間來實現塊設備。
  • snapuserd ,一個用戶空間守護進程來實現一個新的快照格式。

這些組件啟用壓縮。 :為落實壓縮的快照功能將在接下來的章節中給出的其他必要的更改COW格式壓縮的快照DM-用戶Snapuserd

壓縮快照的 COW 格式

在 Android 12 中,壓縮快照使用新的 COW 格式。與用於未壓縮快照的內核內置格式類似,壓縮快照的 COW 格式具有元數據和數據的交替部分。原始格式的元數據僅允許用於“替換”操作:與塊Y的快照內容的基礎映像中替換塊X。壓縮快照 COW 格式更具表現力,支持三種操作:

  • 複製-塊X在基座裝置應與塊中的Y基裝置代替。
  • 替換-塊X在基座裝置應與塊Y的快照內容來代替。這些塊中的每一個都經過 gz 壓縮。
  • -塊X的基本設備應全部用0來代替。

全OTA更新包括更換,只歸零操作。增量OTA更新還可具有複製操作。

Android 12 中的 dm 用戶

對DM-用戶內核模塊使userspace來實現設備映射器塊的裝置。甲DM-user表條目創建下雜設備/dev/dm-user/<control-name> 。一個userspace程序可查詢設備接收從內核讀取和寫入請求。每個請求都有一個關聯的緩衝區供用戶空間填充(讀取)或傳播(寫入)。

dm-user內核模塊提供了新的用戶可見的界面到不是上游kernel.org代碼庫的一部分的內核。直到它,谷歌保留修改權dm-user界面在Android中。

快照用戶

所述snapuserd用戶空間分量dm-user器具虛擬A / B壓縮。

在 Virtual A/B 的未壓縮版本中(在 Android 11 及更低版本中,或在沒有壓縮快照選項的 Android 12 中),COW 設備是原始文件。當啟用壓縮時,COW函數來代替作為dm-user設備,其被連接到所述的一個實例snapuserd守護進程。

內核不使用新的 COW 格式。所以snapuserd組件轉換了Android COW格式和內核的內置格式之間的請求:

Snapuserd component translating requests between Android COW format and kernel built-in format

snapuserd的圖3.流程圖Android和內核COW格式之間轉換

這種轉換和解壓永遠不會發生在磁盤上。該snapuserd發生在內核組件攔截COW讀取和寫入,並實現它們使用Android COW格式。

虛擬 A/B 壓縮流程

這些部分提供了有關虛擬 A/B 壓縮中使用的過程的詳細信息:讀取元數據、合併和進行初始化轉換。

讀取元數據

元數據由一個構造snapuserd守護程序。元數據主要是 2 個 ID 的映射,每個 ID 為 8 個字節,代表要合併的扇區。在dm-snapshot這就是所謂的disk_exception

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

當舊數據塊被新數據塊替換時,將使用磁盤異常。

Snapuserd守護程序讀取通過COW庫內部COW文件,並構造所述元數據的每個中存在的COW文件中的COW操作。

元數據讀取從發起dm-snapshot在內核中時, dm- snapshot創建設備。

下圖提供了元數據構建的 IO 路徑的時序圖。

Sequence diagram, IO path for metadata construction

圖4.在元數據建設IO路徑序列流

合併

一旦啟動過程完成後,更新引擎標記的插槽啟動成功,並通過開關啟動合併dm-snapshot目標到dm-snapshot-merge目標。

dm-snapshot遍歷元數據,並啟動用於每個磁盤例外合併IO。合併 IO 路徑的高級概述如下所示。

Merge IO path

圖5.合併IO路徑概述

如果設備在合併過程中重新啟動,則合併會在下次重新啟動時恢復,合併完成。

初始化轉換

當壓縮快照啟動,第一階段的init必須開始snapuserd掛載的分區。這就提出了一個問題:當sepolicy被加載和執行, snapuserd被放錯了上下文,它的讀請求失敗,與SELinux否定。

為了解決這個問題, snapuserd過渡在鎖步與init ,如下所示:

  1. 第一階段init啟動snapuserd從ramdisk上,並在環境變量中保存了一個開放的文件描述符給它。
  2. 第一級init根文件系統切換到系統分區,然後執行的系統複製init
  3. 的系統複製init讀取組合sepolicy成一個字符串。
  4. Init所調用mlock()上的所有ext4的支持頁面。然後,它取消對快照設備的所有設備映射表,並停止snapuserd 。此後禁止從分區讀取,因為這樣做會導致死鎖。
  5. 使用開放式描述符的RAMDISK拷貝snapuserdinit重新推出具有正確的SELinux的守護進程。快照設備的設備映射表被重新激活。
  6. INIT所調用munlockall() -它是安全的再次執行IO。

空間使用

下表提供了使用 Pixel 的操作系統和 OTA 大小的不同 OTA 機制的空間使用情況比較。

尺寸影響非 A/B甲/乙虛擬 A/B虛擬 A/B(壓縮)
原廠圖片4.5GB超級(3.8G圖像+ 700M預留)1 9GB super(3.8G+700M預留,兩個槽位) 4.5GB超級(3.8G鏡像+700M預留) 4.5GB超級(3.8G鏡像+700M預留)
其他靜態分區/緩存沒有任何沒有任何沒有任何
附加存儲在OTA(空間施加OTA後返回) /data 上 1.4GB 0 3.8GB 2 /數據2.1GB 2 /數據
應用 OTA 所需的總存儲空間5.9GB 3(超和數據) 9GB(超級) 8.3GB 3(超和數據) 6.6GB 3(超和數據)

1表示基於像素映射假定佈局。

2假設新的系統映像的大小與原始相同。

3空間的要求是短暫的,直到重新啟動。

實現虛擬A / B,或使用壓縮的快照功能,請參閱實施虛擬A / B