| RFC-0135:套件 ABI 修訂版本 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 將系統 ABI 修訂版本編碼到套件中。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2021-09-30 |
| 審查日期 (年-月-日) | 2021-11-05 |
摘要
設計將系統 ABI 修訂版本編碼至套件中。
提振精神
RFC-0002 介紹了 API 級別和 ABI 修訂版本的概念。API 級別是單調遞增的數字,方便使用者瞭解,對應於建構應用程式時可用的 API 集。ABI 修訂版本對應於 Fuchsia 系統介面公開的特定語意,應用程式預期平台會提供這些語意。API 級別對應至特定 ABI 修訂版本,但多個 API 級別可以參照同一個 ABI 修訂版本。這項功能可讓 Fuchsia 平台隨著時間演進,同時繼續支援舊版應用程式。
如要實作平台版本控管,套件必須編碼要鎖定的 ABI 級別,平台才能判斷套件是否與執行中的系統相容。
利害關係人
協助人員:abarth@google.com
審查者:
由於這項 RFC 涉及 Fuchsia Tools 和軟體交付,最終會影響元件架構選取要向應用程式顯示的元件系統介面,因此我們選擇了下列利害關係人。
- abarth@google.com (FEC 成員)
- computerdruid@google.com (SWD)
- geb@google.com (CF)
- mkember@google.com (FIDL)
- raggi@google.com (工具)
- wittrock@google.com (SWD)
已諮詢:
- lijiaming (PDK)
社交:
這項 RFC 經過軟體交付和 Fuchsia 工具團隊的設計審查。
術語
Fuchsia 套件是 Fuchsia 程式、元件和服務的檔案發布和整理單位。
meta.far 是套件中繼資料封存檔。其中包含面向使用者的檔案名稱與基礎內容位址 blob 的對應。封裝系統會使用這個 ID 下載套件內容,並建構命名空間階層。也包含使用者提供的自訂檔案。
設計
這項設計導入了「套件 ABI 修訂版本」的概念,也就是套件使用的 Fuchsia 平台介面目標 ABI 修訂版本。這個值會寫入檔案 meta/fuchsia.abi/abi-revision 的 meta.far 中,做為以小端序寫入的無正負號 64 位元整數。
所有套件產生工具都會更新,要求在建構套件時指定 API 級別或 ABI 修訂版本。指定 API 級別時,工具應編碼 SDK 版本記錄中找到的對應 ABI 修訂版本,或回報錯誤。同樣地,工具應強制執行指定 ABI 修訂版本是否受 SDK 支援,否則會發生錯誤。這樣應該就能避免使用舊版 SDK 建立元件,但指定僅存在於新版 SDK 的 ABI。這麼做最多只會導致元件無法執行。最糟的情況是,這可能會導致元件出現奇怪或危險的錯誤。
套件 ABI 修訂的用途
本提案僅涵蓋如何將 ABI 修訂版本編碼至套件中。套件 ABI 修訂版本的使用者將在未來的設計中定義。不過,以下列出幾個可能的應用實例,協助您瞭解這項功能的使用方式:
- RFC-0002 Platform 說明一種機制,元件管理服務可使用套件 ABI 修訂版本,在執行元件時選取要使用的平台介面。
- 系統組裝是從一組套件和其他編譯構件,組成 Fuchsia 系統映像檔的程序。然後,系統映像檔就能透過其他方式 (OTA、刷機、鋪路等) 傳送 Fuchsia。組譯器可以使用套件 ABI 修訂版本,在系統不支援必要套件 ABI 時,拒絕整合套件。
- 同樣地,花瓣或應用程式開發人員可以使用套件 ABI 修訂版本,瞭解複雜樹狀結構中的所有元件是否都能在目標 Fuchsia 版本上執行。
- 暫時性套件是隨選下載的套件,而非內建於系統映像檔。套件解析器可以利用套件 ABI 修訂版本,拒絕下載已知無法在系統上執行的套件。請注意,這可能不適用於系統更新。 詳情請參閱「系統更新注意事項」。
選取目標 API 級別或 ABI 修訂版本
這項提案的目的是在建構套件時,將 API 層級或 ABI 修訂版本設為必要引數,但這項功能在初期推出時為選用引數。因此,終端開發人員應為目標 API 級別或 ABI 修訂版本,設定建構規則的參數。這樣就能輕鬆指定新發行的歌曲。您甚至可以設定測試滾動器,實驗性地推進目標 API 級別,並查看是否有任何項目失敗,藉此設定新 API 級別的自動測試。如果這些失敗是未預期的,可能會回報給平台錯誤報告。
系統更新注意事項
如要讓 Fuchsia 裝置從一個版本更新至另一個版本,系統更新程式會解析稱為「更新套件」的特殊套件。這個套件說明新版 Fuchsia 執行所需的所有基本套件和其他構件。這些新套件並非用於目前的系統,而是會在裝置重新啟動至新系統時使用。
因此,如果我們決定使用套件 ABI 修訂版本拒絕下載套件,就必須小心避免中斷 OTA 程序。請參閱下列範例:
假設有兩個 Fuchsia 版本 A,其中一個僅支援 ABI-1,另一個則支援 ABI-2。C如果我們根據 ABI 篩選套件,更新套件的 C 就必須是 ABI-1,才能下載。不過,如要使用新的 ABI,C 版本的基礎套件必須是 ABI-2,但這些套件會遭到 A 版本的套件解析器拒絕。
如要避免這種情況,可以透過過渡版本導入新的 ABI 修訂版本。Fuchsia 的設計允許裝置略過多個版本,直接更新至最新版本。這是特殊版本,無法略過。這項功能可透過平台介面實現順暢的轉移作業。
重新執行先前的範例,但這次假設有 3 個依序發布的 Fuchsia 版本:
A:支援ABI-1,基本套件為ABI-1B:支援ABI-1和ABI-2,基本套件位於ABI-1。C:支援ABI-2,基本套件位於ABI-2。
如果我們將 B 標示為過渡版本,執行 A 的裝置會先更新至 B,然後再更新至 C。
您可以進一步將套件的定義與 ABI 修訂版本分離。由於我們不打算經常對套件版面配置進行不相容的回溯變更,因此可以為套件版面配置設定版本,然後說明特定 ABI 修訂版本支援哪些套件版面配置版本。這樣一來,我們就能安裝更多更新套件,而不必建立過渡版本。
避免 meta.far 中的命名空間衝突
meta.far 目前包含兩個套件中繼資料檔案:meta/package 和 meta/contents,以及任意使用者指定的檔案。也就是說,使用者檔案和我們在套件中導入的任何新中繼資料檔案,都有可能發生衝突。為避免這種情況,套件 ABI 修訂版本會寫入 meta/fuchsia.abi 目錄。這個目錄名稱遵循 Fuchsia 其他地方使用的慣例,例如平台 FIDL 命名空間。套件建構工具將進一步更新,禁止使用者在 meta/fuchsia.abi 中定義自訂檔案。
由於這是由平台控管的目錄,因此您可以使用這個位置儲存 ABI 相關檔案,不會與使用者檔案發生衝突。這可讓我們演進套件 ABI 修訂版本的概念。舉例來說,如果我們想在套件中支援多個 ABI 修訂版本,可以新增 meta/fuchsia.abi/abi-revision-set 來包含所有支援的修訂版本。待所有使用者都遷移至新檔案後,我們就可以捨棄 meta/fuchsia.abi/abi-revision。
儲存空間額外負荷
在最糟的情況下,將套件 ABI 修訂版本新增至中繼資料的額外負荷,會將 8KiB 未壓縮的資料新增至 meta.far,其中前 4KiB 來自 FAR 資料區塊,而後 4KiB 則來自 DIRNAMES 區段,因為該區段會導致第一個內容區塊推出至下一個 4KiB 對齊的偏移。不過,由於 blobfs 的區塊對齊為 8KiB,因此實際上不應造成重大影響。此外,使用預設壓縮器 zstd 壓縮效果也非常好。根據以下範例,這只會將 47 個位元組新增至 meta.far:
# Create an empty package.
% mkdir empty && cd empty
% pm init && pm build
% ls -l meta.far
-rw-r--r-- 1 etryzelaar primarygroup 12288 Oct 5 10:21 meta.far
% fx chunked-compress c meta.far meta.far.compressed
Wrote 447 bytes (97% compression)
# Then create a meta.far that contain's the abi-revision.
% cd .. && mkdir with-abi && cd with-abi
% pm init
% mkdir meta/fuchsia.abi
% python3 -c "
import struct;
abi_revision = int('0xC7003BF9', 16)
f = open('meta/fuchsia.abi/abi-revision', 'wb')
f.write(struct.pack('<Q', abi_revision))
"
% pm build
% ls -l meta.far
-rw-r--r-- 1 etryzelaar primarygroup 16384 Oct 5 10:22 meta.far
% fx chunked-compress c meta.far meta.far.compressed
Wrote 494 bytes (97% compression)
實作
所有套件建構工具都會擴充,支援在指令列上指定 API 級別或 ABI 修訂版本。
pm CLI
pm CLI 將會擴充,以便在套件初始化和建構期間指定 ABI。
叫用範例:
# Create a package with an API level. Under the covers this will look up the
# ABI revision from the SDK.
% pm init --api-level 5
# Create a package with an ABI revision. These commands are equivalent.
% pm init --abi-revision 0xC7003BF9
% pm init --abi-revision 3338681337
# Build a package with an ABI revision.
% pm build --abi-revision 0xC7003BF9
選項:
--api-level LEVEL:要編碼至套件的 API 級別。SDK 必須支援這個值。這個選項與--abi-revision旗標衝突。--abi-revision REVISION:要烘焙到套件中的 ABI 修訂版本。這可能是十進位或十六進位整數,必須由 SDK 支援。這個選項與--api-level旗標衝突。
一開始,--api-level 和 --abi-revision 標記為選用,方便花瓣和終端開發人員在一段時間內實作支援功能。一旦生態系統轉換為指定旗標,這項引數最終將成為必要引數。
效能
這個 RFC 在建構套件時會增加少量額外工作,並造成少許儲存空間負擔,因此對效能的影響應該微不足道。
人體工學
這項提案本身不會大幅改變 Fuchsia 的人體工學。不過,這項功能最終可讓產品開發人員為元件指定特定系統介面。這項做法應能提供穩定性,同時不會阻礙 Fuchsia 的發展。
回溯相容性
這項變更具有回溯相容性,因為這項設計會導入沒有任何消費者的檔案。不過,這項功能最終會讓系統淘汰舊版 ABI 修訂版本,並移除相關支援。
安全性考量
系統會剖析 meta/fuchsia.abi/abi-revision 檔案。不過,這種格式很容易剖析,而且應該很容易驗證剖析器是否正確。
詳情請參閱 RFC-0002 安全性注意事項。
隱私權注意事項
這項提案對隱私權沒有重大影響。
測試
封裝工具將會擴充,以驗證套件是否已產生預期的 ABI 設定。由於會有過渡期,因此套件解析器測試會延長,以驗證是否能與包含或不包含 meta/fuchsia.abi/abi-revision 檔案的套件搭配運作。
說明文件
封裝說明文件將更新,說明如何在套件中表示 ABI,以及使用者在建構套件時如何選取 API 級別或 ABI 修訂版本。
缺點、替代方案和未知事項
替代 ABI 修訂版本檔案格式
我們可以使用以下方式,而非將 ABI 修訂版本編碼為小端整數:
- 使用者可判讀的整數字串
- JSON
- 永久 FIDL
由於下列原因,系統選取了小端整數:
- 我們不希望人類使用這個值。而是應參照人類可理解的 API 層級。
- 這個值會以小端序整數的形式傳遞,因此可避免額外的轉換。
- 剖析方式很簡單。
包含一組 ABI 修訂版本的套件
RFC-0002 應用程式指出,套件可以包含多個元件,每個元件都以不同的 ABI 修訂版本為目標。為支援這項功能,套件 ABI 可以是所有元件 ABI 修訂版本的集合,而不是在套件中編碼單一 ABI 修訂版本。
不過,截至撰寫本文時,沒有任何用途需要包含以不同系統 ABI 為目標的元件套件。單一數字可簡化 ABI 支援的初始實作程序。如果這個情境變得重要,要擴充這項設計並不困難。
直接將 ABI 修訂版本編碼至 meta.far
meta.far 可以直接嵌入 ABI 修訂版本,方法如下:
- 將 ABI 新增至 FAR 索引區塊。
- 優點:
- 只會增加 8 個位元的額外負荷。
- 缺點:
- 索引區塊沒有任何保留位元組,因此將此項目新增至索引需要對 FAR 格式進行重大變更。如要進行這項變更,我們必須先實作支援讀取新 FAR 格式的功能 (但不使用該格式),然後建立過渡版本,最後再遷移至該格式。
- 消費者會更難閱讀 ABI 修訂內容。套件解析器不會直接向使用者公開 meta.far 做為檔案,因此需要新增 API 來公開這項資訊。
- 建立新的 ABI 修訂版本區塊類型。
- 優點:
- 新增的區塊類型應可回溯相容。
- 由於我們不需要建立 4096 位元組對齊的內容區塊,因此位元組的額外負荷應該會小得多。區塊會對齊 64 位元,且索引額外負荷項目大小為 24 個位元組,因此這個方法只會在未壓縮的 FAR 格式中新增 32 個位元組。
- 缺點:
- 我們尚未在 FAR 格式中新增任何區塊類型,因此如果 FAR 程式庫遇到新的區塊類型,可能會發生錯誤或出現非預期的行為。
- 我們必須更新所有 FAR 程式庫,才能瞭解新的區塊類型。從歷史來看,對 FAR 程式庫進行任何變更的成本都相當高。
- 消費者會更難閱讀 ABI 修訂內容。套件解析器不會直接向使用者公開 meta.far 做為檔案,因此需要新增 API 來公開這項資訊。
由於儲存空間的負擔極小 (尤其是經過壓縮後),我們認為定義新的區塊類型並不划算。
存放區中繼資料中的 ABI 修訂版本
我們可以在套件存放區的套件中繼資料中新增 ABI 修訂版本,而非直接將 ABI 編碼至套件。這有以下缺點:
- ABI 修訂版本是套件的內建屬性。可能難以確保 ABI 修訂內容正確地表示在 TUF 存放區或基本套件清單中。
- 封裝中繼資料仍會包含 ABI 修訂版本,因此封裝系統仍須負擔額外負荷。
即將推出的持續性 FIDL 套件中繼資料中的 ABI 修訂版本
軟體交付團隊正在撰寫 RFC,提議採用新的持續性 FIDL 封裝中繼資料。我們可以改為將 ABI 修訂版本儲存在這個中繼資料中,方法是將建議的結構定義更新為:
flexible union Contents {
1: ContentsV1 v1;
};
table ContentsV1 {
1: vector<fuchsia.io.Path>:MAX paths;
2: vector<fuchsia.pkg.BlobId>:MAX hashes;
3: vector<uint64>:MAX blob_sizes;
4: uint64 abi_revision;
};
優點:
- 將所有封裝中繼資料整合到單一 FIDL 檔案的優點是,我們可以運用 FIDL 工具,確保文件和驗證保持在最新狀態。使用多個檔案會導致說明文件和驗證程序更容易失去同步。
- 我們只會將少量位元組新增至未壓縮的 meta.far,而不是約 4 KiB。
使用 FIDL 的缺點:
- 我們無法保證系統會接受以持續性 FIDL 為基礎的 RFC,也無法保證實作作業需要多久時間。
- 雖然以持續性 FIDL 為基礎的方法會進行版本控管,但內部版本無法協助我們將封裝中繼資料遷移至其他檔案格式。舉例來說,如果我們決定從持續性 FIDL 切換為 JSON 檔案,使用新的 ABI 修訂版本,通知封裝系統尋找與先前不同的檔案格式,會比較容易。
既有技術和參考資料
Android
Android 應用程式會在應用程式資訊清單中指定 uses-sdk 元素,以指定目標 SDK 版本。
Windows
Windows 應用程式會指定應用程式資訊清單中列出的 SupportedOS GUID,以指定目標 OS 版本。
macOS
macOS 應用程式會透過在應用程式套件的 Info.plist 檔案中指定 LSMinimumSystemVersion,鎖定作業系統版本。
iOS
iOS 應用程式會透過在應用程式套件的 Info.plist 檔案中指定 MinimumOSVersion,鎖定作業系統版本。