虛擬 A/B 是 Android 的主要更新機制。虛擬 A/B 版本是建立在舊版 A/B 更新 (請參閱「A/B 系統更新」) 和非 A/B 版本 (已在 15 版淘汰) 之上,以減少更新的空間開銷。
虛擬 A/B 實際上沒有額外的動態分區插槽,請參閱「動態分區」。相反地,系統會將差異寫入快照,然後在確認啟動成功後,將差異合併至基礎分區。虛擬 A/B 會使用 Android 專屬的快照格式。請參閱壓縮快照的 COW 格式,可壓縮快照並盡量減少磁碟空間使用量。在完整 OTA 中,壓縮後的快照大小會減少約 45%,而增量 OTA 的快照大小會減少約 55%。
Android 12 提供虛擬 A/B 壓縮選項,可壓縮快照分割區。虛擬 A/B 測試提供下列功能:
- 虛擬 A/B 更新與 A/B 更新一樣無縫 (更新會在裝置運作時完全在背景進行)。虛擬 A/B 更新可縮短裝置離線和無法使用的時間。
- 虛擬 A/B 版本更新可回溯。如果新作業系統無法啟動,裝置會自動回復至先前的版本。
- 虛擬 A/B 更新只會複製系統啟動載入程式使用的分區,因此只會使用最少的額外空間。其他可更新的分區則會快照。
背景與術語
本節將定義相關術語,並說明支援虛擬 A/B 測試的技術。在 OTA 安裝期間,新的作業系統資料會寫入實體分割區的新槽,或 Android 專屬的 COW 裝置。裝置重新啟動後,動態分區資料會透過 dm-user 和 snapuserd 守護程序,重新合併至基礎裝置。這個程序完全在使用者空間中進行。
裝置對應器
Device-mapper 是 Android 中經常使用的 Linux 虛擬區塊層。使用動態分區時,/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 作業和新作業系統資料的獨立緩衝區。與僅允許替換作業 (將快照中的區塊 Y 內容取代為基礎映像檔中的區塊 X) 的核心快照格式相比,Android 壓縮快照 COW 格式更具表達力,且支援下列作業:
- 複製:應將基礎裝置中的區塊 X 替換為基礎裝置中的區塊 Y。
- Replace:基礎裝置中的區塊 X 應替換為快照中的區塊 Y 內容。每個區塊都經過 gz 壓縮。
- Zero:應將基礎裝置中的 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
的使用者空間元件會實作虛擬 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 以上版本的裝置,snapuserd
使用者空間元件會執行虛擬 A/B 壓縮中的快照和快照合併程序。如果裝置升級至 Android 13 以上版本,則必須啟用這項功能。詳情請參閱「使用者空間合併」。
以下說明虛擬 A/B 壓縮程序:
- 此架構會將
/system
分割區掛載至dm-verity
裝置,而該裝置會堆疊在dm-user
裝置上。也就是說,來自根目錄檔案系統的每個 I/O 都會路由至dm-user
。 dm-user
會將 I/O 轉送至處理 I/O 要求的使用者空間snapuserd
守護程式。- 合併作業完成後,架構會在
dm-linear
(system_base
) 上方收合dm-verity
,並移除dm-user
。
圖 3. 虛擬 A/B 壓縮程序
快照合併程序可能會中斷。如果裝置在合併程序期間重新啟動,合併程序會在重新啟動後繼續。
初始轉場效果
使用壓縮快照啟動時,第一階段初始化程序必須啟動 snapuserd
來掛載分區。這會造成問題:當 sepolicy
載入及強制執行時,snapuserd
會放入錯誤的內容,其讀取要求會失敗,並遭到 selinux 拒絕。
為解決這個問題,snapuserd
會與 init
同步轉換,如下所示:
- 第一階段的
init
會從 RAM 磁碟啟動snapuserd
,並將開放式檔案描述元儲存至環境變數。 - 第一階段的
init
會將根檔案系統切換至系統分區,然後執行init
的系統副本。 init
的系統副本會將合併的 sepolicy 讀取至字串。Init
會在所有 ext4 支援的頁面上叫用mlock()
。接著,它會停用快照裝置的所有裝置對應表,並停止snapuserd
。此後,系統會禁止讀取分區,因為這會導致死結。- 使用
snapuserd
的 RAM 磁碟副本的開放描述元,init
會以正確的 selinux 上下文重新啟動守護程式。系統會重新啟用快照裝置的裝置-mapper 資料表。 - 初始化會叫用
munlockall()
,因此可以安全地再次執行 I/O。
空間使用情形
下表比較了使用 Pixel 作業系統和 OTA 大小的不同 OTA 機制所需的空間。
大小影響 | 非 A/B | A/B | 虛擬 A/B | 虛擬 A/B (壓縮) |
---|---|---|---|---|
原始工廠映像檔 | 4.5GB 超級 (3.8GB 映像檔 + 700MB 保留空間)1 | 9 GB 超大 (保留 3.8 GB + 700 MB,適用於兩個插槽) | 4.5GB 超級 (3.8G 映像檔 + 700M 保留空間) | 4.5GB 超級 (3.8G 映像檔 + 700M 保留空間) |
其他靜態區隔 | /cache | 無 | 無 | 無 |
OTA 期間的額外儲存空間 (套用 OTA 後返回的空間) | /data 上的 1.4 GB | 0 | 3.8 GB2 位於 /data | 2.1 GB2 位於 /data |
套用 OTA 所需的總儲存空間 | 5.9 GB3 (超級和資料) | 9 GB (超大) | 8.3 GB3 (超級和資料) | 6.6 GB3 (超級和資料) |
1 表示根據 Pixel 對應方式推測的版面配置。
2假設新系統映像檔的大小與原始映像檔相同。
3 空間需求會在重新啟動前暫時性增加。
Android 11 虛擬 A/B
虛擬 A/B 的 Android 11 使用核心 COW 格式寫入動態分區。由於核心 COW 格式不支援壓縮,因此這個功能最終已淘汰。
Android 12 虛擬 A/B
在 Android 12 中,系統支援 Android 專屬 COW 格式的壓縮方式。這個版本的 Virtual A/B 需要將 Android 專屬 COW 轉譯為核心 COW 格式。最終,Android 13 取代了這個功能,移除了對核心 COW 格式和 dm-snapshot
的依賴。
如要實作虛擬 A/B 版本,或使用壓縮快照功能,請參閱「實作虛擬 A/B 版本」