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 工具和軟體提交作業,並最終影響元件架構如何選取要呈現給應用程式的元件系統介面。
- 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 已通過 Software Delivery 和 Fuchsia Tools 團隊的設計審查。
術語
Fuchsia package 是用於發布及整理 Fuchsia 程式、元件和服務檔案的分發單位。
meta.far 是套件中繼資料封存檔案。其中包含使用者端檔案名稱與底層內容位址 blob 的對應項目。封裝系統會使用這個值下載套件內容,並建構命名空間階層。並包含使用者提供的自訂檔案。
設計
這項設計引入了「套件 ABI 修訂版本」的概念,這是套件所用 Fuchsia 平台介面的目標 ABI 修訂版本。這個值會以無號小端序 64 位元整數的形式寫入檔案 meta/fuchsia.abi/abi-revision
中的 meta.far
。
所有套件產生工具都會更新,要求在建構套件時指定 API 級別或 ABI 修訂版本。指定 API 級別後,工具應編碼 SDK 版本記錄中對應的 ABI 修訂版本,或傳回錯誤。同樣地,工具應強制執行 SDK 支援指定的 ABI 修訂版本,否則會傳回錯誤。這樣一來,您就不會因為使用較舊的 SDK 建立元件,但指定僅存在於較新 SDK 中的 ABI,而面臨風險。這麼做頂多會導致元件無法執行。最糟糕的情況是,這可能會導致元件出現奇怪或危險的錯誤。
套件 ABI 修訂版本的用途
本提案僅涵蓋如何將 ABI 修訂版本編碼至套件。套件 ABI 修訂版本的使用者將在日後的設計中定義。不過,以下是一些可能的應用實例,可說明這項功能的用途:
- RFC-0002 平台說明瞭一個機制,元件管理服務可使用套件 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
,以及 C
,後者支援 ABI-2
。如果我們根據 ABI 篩選套件,C
的更新套件就必須是 ABI-1
,才能下載。不過,C
版本的基礎套件必須是 ABI-2
,才能使用新的 ABI,但這些套件會遭到版本 A
套件解析工具拒絕。
避免這種情況的其中一種做法,就是透過踏步式發布版本引入新的 ABI 修訂版本。Fuchsia 的設計可讓裝置跳過多個版本,以便更新至最新版本。踏板版本是無法略過的特殊版本。這項功能旨在透過平台介面提供流暢的轉換體驗。
重做先前的範例,改為使用 3 個連續的 Fuchsia 版本:
A
:支援ABI-1
,基礎套件位於ABI-1
B
:支援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 資料區塊,如果 DIRNAMES 區段導致第一個內容區塊被推送至下一個 4KiB 對齊偏移量,則會加入第二個 4KiB。不過,在實際操作中,這應該不會造成太大影響,因為 blobfs 有 8KiB 的區塊對齊。此外,它還能搭配預設的壓縮器 zstd 達到極佳的壓縮效果。根據以下範例,這只會為 meta.far 增加 47 個位元組:
# 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
之所以選用 little endian 整數,是因為:
- 我們不希望人類使用這個值。而是應參照人類可理解的 API 級別。
- 這個值會以小端序整數的形式傳遞,因此可避免額外轉換。
- 剖析方式也相當簡單。
包含一組 ABI 修訂版本的套件
RFC-0002 Applications 指出,套件可包含多個元件,每個元件都會指定不同的 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,也無法保證實作這項 RFC 需要多久的時間。
- 雖然以持續性 Fidl 為基礎的方法會加上版本號碼,但內部版本無法協助我們將封裝中繼資料遷移至其他檔案格式。舉例來說,如果我們決定從持續性 FIDL 切換至 JSON 檔案,使用新的 ABI 修訂版本,可更輕鬆地通知封裝系統尋找與先前不同的檔案格式。
既有技術與參考資料
Android
Android 應用程式會在應用程式資訊清單中指定 uses-sdk 元素,以指定 SDK 版本。
Windows
Windows 應用程式會指定應用程式資訊清單中列出的 SupportedOS GUID,以指定 OS 版本。
macOS
macOS 應用程式會在應用程式套件的 Info.plist
檔案中指定 LSMinimumSystemVersion,藉此指定 OS 版本。
iOS
iOS 應用程式會在應用程式套件的 Info.plist
檔案中指定 MinimumOSVersion,藉此指定目標作業系統版本。