虛擬 A/B 是 Android 的主要更新機制。虛擬 A/B 是以舊版 A/B 更新為基礎 (請參閱「A/B 系統更新」),並在 15 中淘汰非 A/B 更新,以減少更新的空間負擔。
虛擬 A/B 測試實際上沒有動態分區的額外位置,請參閱動態分區。而是將差異寫入快照,然後在確認開機成功後,合併至基本分割區。虛擬 A/B 測試會使用 Android 專屬的快照格式。請參閱「壓縮快照的 COW 格式」,瞭解如何壓縮快照並盡量減少磁碟空間用量。完整 OTA 的快照大小會壓縮約 45%,增量 OTA 快照大小則會壓縮約 55%。
Android 12 提供虛擬 A/B 壓縮選項,可壓縮快照分割區。虛擬 A/B 測試提供下列功能
- 虛擬 A/B 更新與 A/B 更新一樣順暢 (更新完全在背景進行,裝置運作不受影響)。虛擬 A/B 更新可盡量縮短裝置離線和無法使用的時間。
- 虛擬 A/B 測試更新可以回溯。如果新版 OS 無法啟動,裝置會自動還原為先前的版本。
- 虛擬 A/B 更新只會複製啟動載入程式使用的磁碟分割區,因此佔用的額外空間最少。其他可更新的分區則會建立快照。
背景與術語
本節定義術語,並說明支援虛擬 A/B 測試的技術。在 OTA 安裝期間,新的作業系統資料會寫入實體分割區的新位置,或是 Android 專用的 COW 裝置。裝置重新啟動後,系統會透過 dm-user 和 snapuserd 精靈,將動態分割區資料合併回基本裝置。這項程序完全在使用者空間中進行。
Device-mapper
裝置對應程式是 Linux 虛擬區塊層,Android 經常使用此層。有了動態分區,/system
等分區就會成為分層裝置堆疊:
- 堆疊底部是實體超級分割區 (例如
/dev/block/by-name/super
)。 - 中間是
dm-linear
裝置,指定超級分割區中的哪些區塊會形成指定的動態分割區。在 A/B 裝置上會顯示為/dev/block/mapper/system_[a|b]
,在非 A/B 裝置上則會顯示為/dev/block/mapper/system
。 - 頂端是為已驗證分割區建立的
dm-verity
裝置。 這個裝置會驗證dm-linear
裝置上的區塊是否已正確簽署。顯示為/dev/block/mapper/system-verity
,是/system
掛接點的來源。
圖 1 顯示掛接點下的堆疊外觀。/system
圖 1. 堆疊在 /system 掛接點下方
壓縮快照
在 Android 12 以上版本中,由於 /data
分區的空間需求可能很高,因此您可以在建構作業中啟用壓縮快照,以解決 /data
分區空間需求較高的問題。
虛擬 A/B 壓縮快照是以 Android 12 以上版本提供的下列元件為基礎建構而成:
這些元件可啟用壓縮功能。如要實作壓縮快照功能,還需要進行其他變更,詳情請參閱下列章節:壓縮快照的 COW 格式、dm-user 和 snapuserd。
壓縮快照的 COW 格式
在 Android 12 以上版本中,壓縮快照會使用 Android 專用的 COW 格式。COW 格式包含 OTA 的中繼資料,以及含有 COW 作業和新作業系統資料的獨立緩衝區。相較於僅允許「取代」作業 (將基本映像檔中的區塊 X 取代為快照中的區塊 Y) 的核心快照格式,Android 壓縮快照 COW 格式更具表現力,且支援下列作業:
- 複製:將基本裝置中的區塊 X 換成區塊 Y。
- 取代:基礎裝置中的區塊 X 應替換為快照中的區塊 Y 內容。每個區塊都經過 gz 壓縮。
- 零:基本裝置中的 X 區塊應全數以零取代。
- XOR:COW 裝置會儲存區塊 X 和區塊 Y 之間的 XOR 壓縮位元組。(適用於 Android 13 以上版本)。
完整 OTA 更新只包含「取代」和「零」作業。增量 OTA 更新可能還包含複製作業。
磁碟上的完整快照版面配置如下所示:
圖 2. 磁碟上的 Android COW 格式
dm-user
dm-user 核心模組可讓 userspace
實作裝置對應程式區塊裝置。dm-user 資料表項目會在「/dev/dm-user/<control-name>
」下建立雜項裝置。userspace
程序可以輪詢裝置,接收來自核心的讀取和寫入要求。每個要求都有相關聯的緩衝區,供使用者空間填入 (讀取) 或傳播 (寫入) 資料。
dm-user
核心模組提供新的使用者可見核心介面,不屬於上游 kernel.org 程式碼集。在此之前,Google 保留修改 Android dm-user
介面的權利。
snapuserd
snapuserd
使用者空間元件會dm-user
實作 Virtual A/B 壓縮功能。Snapuserd 是負責寫入及讀取 Android COW 裝置的使用者空間精靈。所有快照 I/O 都必須透過這項服務。
在 OTA 安裝期間,snapuserd 會將新的作業系統資料寫入快照 (並進行壓縮)。這裡也會處理中繼資料的剖析作業,以及新區塊資料的解壓縮作業。
XOR 壓縮
如果裝置搭載 Android 13 以上版本,預設會啟用 XOR 壓縮功能,讓使用者空間快照在舊區塊和新區塊之間儲存 XOR 壓縮位元組。在虛擬 A/B 更新中,如果只有區塊中的幾個位元組發生變化,XOR 壓縮儲存空間配置使用的空間會比預設儲存空間配置少,因為快照不會儲存完整的 4K 位元組。由於 XOR 資料包含許多零,且比原始區塊資料更容易壓縮,因此快照大小可以縮減。在 Pixel 裝置上,XOR 壓縮可將快照大小縮減 25% 至 40%。
如果裝置升級至 Android 13 以上版本,必須啟用 XOR 壓縮。詳情請參閱 XOR 壓縮。
快照合併
如果是搭載 Android 13 以上版本的裝置,虛擬 A/B 壓縮的快照和快照合併程序會由 snapuserd
使用者空間元件執行。如果裝置升級至 Android 13 以上版本,必須啟用這項功能。詳情請參閱「使用者空間合併」。
以下說明 Virtual A/B 壓縮程序:
- 架構會從
dm-verity
裝置卸載/system
分割區,該裝置會堆疊在dm-user
裝置上方。也就是說,根檔案系統的所有 I/O 都會轉送至dm-user
。 dm-user
將 I/O 轉送至使用者空間snapuserd
精靈,該精靈會處理 I/O 要求。- 合併作業完成後,架構會摺疊
dm-verity
在dm-linear
(system_base
) 頂端,並移除dm-user
。
圖 3. 虛擬 A/B 壓縮程序
快照合併程序可能會中斷。如果裝置在合併程序期間重新啟動,合併程序會在重新啟動後繼續執行。
初始化轉場效果
使用壓縮快照啟動時,第一階段 init 必須開始掛接分割區。snapuserd
這會造成問題:載入並強制執行 sepolicy
時,snapuserd
會進入錯誤的環境,導致讀取要求失敗,並遭到 SELinux 拒絕。
為解決這個問題,snapuserd
會與 init
同步轉換,如下所示:
- 第一階段
init
會從 ramdisk 啟動snapuserd
,並將開啟的檔案描述元儲存至環境變數。 - 第一階段的
init
會將根檔案系統切換至系統分割區,然後執行init
的系統副本。 - 系統副本的
init
會將合併的 sepolicy 讀取到字串中。 - 會對所有 ext4 支援的頁面呼叫
mlock()
。Init
接著,系統會停用快照裝置的所有裝置對應表,並停止snapuserd
。之後就禁止從分割區讀取資料,否則會造成死結。 - 使用開放描述元重新啟動精靈的 ramdisk 副本
snapuserd
,init
會使用正確的 SELinux 內容。系統會重新啟用快照裝置的裝置對應表。 - Init 會叫用
munlockall()
,因此可以再次執行 IO。
空間用量
下表比較了使用 Pixel OS 和 OTA 大小時,不同 OTA 機制的空間用量。
大小影響 | 非 A/B | A/B | 虛擬 A/B 測試 | 虛擬 A/B (壓縮) |
---|---|---|---|---|
Original Factory Image | 4.5 GB 超大容量 (3.8 GB 圖片 + 700 MB 保留空間)1 | 9GB 超級 (3.8G + 700M 保留,適用於兩個插槽) | 4.5 GB 超級 (3.8 GB 圖片 + 700 MB 保留) | 4.5 GB 超級 (3.8 GB 圖片 + 700 MB 保留) |
其他靜態分割區 | /cache | 無 | 無 | 無 |
OTA 期間的額外儲存空間 (套用 OTA 後會釋出空間) | /data 上的 1.4 GB | 0 | /data 上 3.8 GB2 | /data 上 2.1 GB2 |
套用 OTA 時所需的總儲存空間 | 5.9 GB3 (超級和資料) | 9 GB (超級) | 8.3 GB3 (超級和資料) | 6.6 GB3 (超級和資料) |
1:根據 Pixel 對應顯示的預設版面配置。
2假設新系統映像檔與原始映像檔大小相同。
3重新啟動前,空間需求為暫時性。
Android 11 虛擬 A/B
Android 11 的虛擬 A/B 測試功能使用 Kernel COW 格式寫入動態分割區。由於 Kernel COW 格式不支援壓縮,因此最終遭到淘汰。
Android 12 虛擬 A/B
在 Android 12 中,壓縮功能以 Android 專屬 COW 格式提供。這個版本的虛擬 A/B 測試需要將 Android 專屬的 COW 轉換為 Kernel COW 格式。Android 13 最終取代了這項功能,不再依賴 Kernel COW 格式,也移除了 dm-snapshot
。
如要導入虛擬 A/B 測試或使用壓縮快照功能,請參閱「導入虛擬 A/B 測試」一文。