RFC-0135:套件 ABI 修訂版本

RFC-0135:套件 ABI 修訂版本
狀態已接受
區域
  • 軟體推送
說明

將系統 ABI 修訂版本編碼為套件。

問題
  • 85820
變更
  • 588486
作者
審查人員
提交日期 (年/月)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 成員)
  • PCdruid@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「套件」是用於發布及整理 Fuchsia 程式、元件和服務檔案的發布單位。

meta.far 是套件中繼資料封存。其中包含使用者端檔案名稱與對應 blob 的基礎內容之間的對應關係。封裝系統會使用這項資訊下載套件內容,並建構命名空間階層。以及使用者提供的自訂檔案。

設計

此設計導入「套件 ABI 修訂版本」的概念,是套件使用的 Fuchsia 平台介面目標 ABI 修訂版本。這個值會以無正負號的 64 位元整數寫入至 meta/fuchsia.abi/abi-revision 檔案的 meta.far 中。

所有套件產生工具都會更新,要求在建構套件時指定 API 級別或 ABI 修訂版本。指定 API 級別後,工具應對 SDK 版本記錄中找到的對應 ABI 修訂版本進行編碼,或發生錯誤。同樣地,此工具也應強制執行 SDK 支援指定的 ABI 修訂版本,否則就會發生錯誤。這應該避免使用舊版 SDK 建立元件的風險,但指定 ABI 只能在較新的 SDK 中出現。最佳做法將導致元件無法執行。最糟的是,這可能會導致元件出現異常或危險的錯誤。

套件 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-2ABI-1C。如果根據 ABI 篩選套件,C 的更新套件必須為 ABI-1 才能下載。不過,C 版本基本套件必須是 ABI-2 才能使用新的 ABI,但版本 A 套件解析器會拒絕這些處理。

如要避免這種情況,其中一個方法是透過逐步發布流程推出新的 ABI 修訂版本。Fuchsia 旨在讓裝置略過多個版本,藉此更新至最新版本。漸進式發布是無法略過的特殊版本,旨在透過平台介面流暢地進行轉換。

重做先前的範例,改為執行 3 個後續的 Fuchsia 版本:

  • A:支援 ABI-1,基本套件為 ABI-1
  • B:支援 ABI-1ABI-2,這是 ABI-1 的基本套件。
  • C:支援 ABI-2,基本套件為 ABI-2

如果我們將 B 標示為步數版本,執行 A 的裝置會先更新至 B,然後更新至 C

只要分離 ABI 修訂版本定義套件的方式,即可進一步採用這個概念。由於我們不希望經常對套件版面配置進行回溯不相容的變更,因此可以針對套件版面配置建立版本,然後指出特定 ABI 修訂版本支援的套件版面配置版本。這可以讓我們安裝更多樣的更新套件,而不需要建立逐步發布版本。

避免中繼.far 中的命名空間衝突

meta.far 目前包含兩個套件中繼資料檔案 (meta/packagemeta/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 未壓縮到的中繼.far 中,其中第一個 4KiB 來自 FAR 資料區塊;如果 DIRNAMES 區段會導致第一個內容區塊被推送到下一個 4KiB 偏移,則第二個內容區塊。然而,這就應該不會造成太大的影響,因為 blobfs 具有 8KiB 區塊對齊方式。此外,它使用預設壓縮器 zstd 來非常壓縮。如以下範例所示,這只會將 47 個位元組新增至中繼.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 修訂版本。

下午 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 的發展能力。

回溯相容性

這項變更可回溯相容,因為此設計導入了不含取用端的新檔案。然而,這項功能最終會使系統淘汰,最終停止支援舊版 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 修訂版本編碼為中繼.far

Meta.far 可以透過下列任一方式直接嵌入 ABI 修訂版本:

  • 將 ABI 新增至 FAR 索引區塊
    • 優點:
    • 只會增加 8 個位元組的負荷。
    • 缺點:
    • 索引區塊沒有任何保留的位元組,因此將這個區塊加入索引時,必須對 FAR 格式進行破壞性變更。為進行這項變更,我們必須先實作 FAR 支援功能,以便在不使用這種格式的情況下讀取新 FAR 格式,然後建立逐步石頭版本,最後再遷移至該格式。
    • 讓消費者更難閱讀 ABI 修訂版本。套件解析器不會以檔案的形式直接將中繼.far 公開給使用者,因此您必須新增 API 來公開這項資訊。
  • 建立新的 ABI 修訂版本區塊類型。
    • 優點:
    • 必須具有回溯相容性以新增區塊類型。
    • 由於我們不需要建立 4096 位元組對齊的內容區塊,因此以位元組為單位的負擔應該會小很多。區塊會對齊 64 位元,且索引負擔項目大小為 24 個位元組,因此這個方法應該只將 32 個位元組新增至未壓縮的 FAR 格式中。
    • 缺點:
    • 我們尚未在 FAR 格式中新增區塊類型,因此 FAR 程式庫可能會在遇到新的區塊類型時,發生錯誤或無法正常運作。
    • 我們必須更新所有 FAR 程式庫,才能瞭解新的區塊類型。以往對 FAR 程式庫的任何變更都非常昂貴。
    • 讓消費者更難閱讀 ABI 修訂版本。套件解析器不會以檔案的形式直接將中繼.far 公開給使用者,因此您必須新增 API 來公開這項資訊。

由於儲存空間的負擔極少 (特別是在壓縮時),我們不認為藉由定義新的區塊類型可以節省空間。

存放區中繼資料的 ABI 修訂版本

我們可以改為將 ABI 修訂版本新增至套件存放區中的套件中繼資料,而不是直接將 ABI 編碼成套件。這有以下缺點:

  • ABI 修訂版本是套件內建的屬性。難以確保 ABI 修訂版本在 TUF 存放區或基礎套件清單中正確表示。
  • 封裝中繼資料仍會包含 ABI 修訂版本,因此封裝系統仍須負擔負擔。

即將發布的永久 FIDL 套件中繼資料中的 ABI 修訂版本

Software Delivery 編寫的 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 工具,將說明文件和驗證保持在最新狀態。使用多個檔案會使我們的說明文件和驗證流程更容易偏移。
  • 我們只會在未壓縮的中繼.far 中加入少量位元組,而不是 ~4KiB。

使用 FIDL 的缺點:

  • 我們無法保證會接受以永久 FIDL 為基礎的 RFC,以及實作所需時間。
  • 雖然永久 FIDL 型方法已建立版本,但內部版本無法協助我們將封裝中繼資料遷移至其他檔案格式。例如,如果我們決定從永久 FIDL 改為 JSON 檔案,使用新的 ABI 修訂版本告知封裝系統尋找與以往不同的檔案格式。

先前的圖片和參考資料

Android

Android 應用程式會在應用程式資訊清單中指定 uses-sdk 元素,以鎖定 SDK 版本為目標。

Windows

您可以指定應用程式資訊清單中列出的 SupportedOS GUID,藉此指定 OS 版本。

macOS

macOS 應用程式會在應用程式套件的 Info.plist 檔案中指定 LSMinimumSystemVersion,以指定 OS 版本。

iOS

iOS 應用程式是在應用程式套件的 Info.plist 檔案中指定 MinimumOSVersion,以指定 OS 版本。