RFC-0002:Fuchsia 平台版本管理

RFC-0002:Fuchsia 平台版本管理
狀態已接受
區域
  • 一般
說明

使用版本管理功能,讓平台持續發展,同時提供相容性。

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2020-04-30
審查日期 (年-月-日)2020-05-23

摘要

本文將向 Fuchsia 平台提出「API 級別」和「ABI 修訂版本」的概念。終端開發人員會根據目標 API 級別建構應用程式,這會決定應用程式可見的宣告。目標 API 級別也會以目標 ABI 修訂版本的形式嵌入編譯後的應用程式,指出應用程式預期平台提供的語意。Fuchsia 平台通常支援多個 ABI 修訂版本,因此平台可以執行舊版應用程式,同時提供平台演進的路徑。

提振精神

目前 Fuchsia 平台是透過一系列軟轉換演進。如要變更部分 Fuchsia 系統介面,平台會先導入新介面。應用程式隨後會遷移至新介面。所有應用程式遷移至新介面後,平台就會移除舊介面。

採用這種做法時,平台只能以最慢的應用程式速度演進。如要完成軟性轉換,平台必須等待最後一個應用程式從舊版介面遷移。隨著應用程式數量增加,平台與應用程式之間的耦合減少,軟轉換的執行時間會越來越長。最終,我們將無法透過軟性轉移方式發展平台。

本 RFC 解決了下列問題陳述:

如何讓 Fuchsia 平台持續演進,同時在更長的時間內執行越來越多的舊版應用程式?

為何現在發行?

許多客戶要求平台提供更穩定的服務。如果我們現在提供這項穩定性,將會減緩平台演進的速度。為滿足目前客戶的需求,平台必須提供更長的相容性時間範圍,同時不致導致專案停滯不前。

此外,根據 Windows 的經驗,我們應在應用程式中嵌入目標 ABI 修訂版本,然後再長期提供與這些應用程式的二進位檔相容性,這樣對我們有益。Windows 錯失了這個機會,現在嘗試使用啟發式方法猜測二進位的目標 ABI 修訂版本,這為開發人員帶來了極大的困擾。

術語

Fuchsia 的發布版本是指 Fuchsia 作業系統和相關聯的套件建構版本,會部署給使用者。發布版本有版本號碼,可識別發布版本中包含的軟體構件集。

回溯相容性是指新版 Fuchsia 能否執行適用於舊版 Fuchsia 的二進位檔。

Fuchsia IDK 是開發環境整合人員使用的構件,可向開發人員公開 Fuchsia 平台,讓他們建構可在 Fuchsia 上執行的應用程式。Fuchsia IDK 由 Fuchsia 專案發布,定義 Fuchsia 平台與在 Fuchsia 上執行的應用程式之間的合約。IDK 工具會定義 Fuchsia IDK 工具與開發環境整合人員環境之間的合約。

軟性轉換是一種技術,可將不具回溯相容性的變更分解為一連串較小的平台變更和一組已知二進位檔,確保每個步驟都能維持本機相容性。

設計

本文所述設計是為了對 Fuchsia 系統介面進行版本控管,讓平台和應用程式就應用程式預期平台提供的語意達成共識。

具體來說,如果應用程式可在特定 Fuchsia 版本上運作,除非 Fuchsia 刻意停止支援該應用程式,否則應用程式應可在後續的 Fuchsia 版本上繼續運作。這個設計並未解決相反的問題,也就是建立可在舊版 Fuchsia 上運作的新應用程式。

版本管理

Fuchsia 平台使用兩個版本 ID,分別是 API 級別ABI 修訂版本。這兩個版本都可識別平台提供的介面,而非該介面的實作方式。Fuchsia 發布版本採用不同的版本管理架構,可識別該版本中的特定實作項目。

特定 API 級別會隱含特定 ABI 修訂版本,但多個 API 級別可能隱含相同的 ABI 修訂版本。

API 級別

Fuchsia API 級別是指建構應用程式時可用的 API 集。特定版本的 Fuchsia IDK 通常支援多個 API 級別。在特定支援的 API 級別中,IDK 版本提供的 API 應保持一致。

範例。建議使用 SDK 中的 C++ 程式庫 pkg/fitfit 程式庫會宣告多個函式,每個函式都是程式庫公開的 API。API 會定義這組函式,也就是說,兩個 IDK 版本應在相同 API 級別的 fit 程式庫中公開同一組函式。

就語法而言,Fuchsia API 級別是不帶正負號的 64 位元整數。隨著平台演進 (請參閱下方的「演進」),API 層級會以遞增順序指派,供包括開發人員在內的使用者瞭解。

ABI 修訂版本

Fuchsia ABI 修訂版本是指應用程式預期平台提供的 Fuchsia 系統介面語意。Fuchsia 的特定版本通常支援多個 ABI 修訂版本,但支援的特定 ABI 修訂版本語意在各個 Fuchsia 版本中應保持一致 (請參閱下方的「演進」)。

範例。以 zx_clock_get_monotonic 為例,這是 vDSO 公開的函式,屬於 Fuchsia 系統介面。ABI 修訂版本會指定這個函式是否存在,以及呼叫這個函式時會發生什麼情況,這表示在相同 ABI 修訂版本中,zx_clock_get_monotonic 的語意在各個 Fuchsia 版本中應保持一致。

在語法上,Fuchsia ABI 修訂版本是不帶正負號的 64 位元整數。ABI 修訂版本是不含內部結構的不透明 ID。如要為新的 ABI 修訂版本建立 ID,請從未曾用於識別 Fuchsia ABI 修訂版本的值中,隨機選取未簽署的 64 位元整數。

ABI 修訂版本的 ID 是隨機選擇,避免終端開發人員猜測未來的 ABI 修訂版本 ID,並對 Fuchsia 系統介面未來版本的語意形成預期。因此,ABI 修訂內容應由機器解讀,只有極少數情況需要人工解讀。

演化

每當平台在 Fuchsia IDK 中新增或移除 API,或是 ABI 修訂版本有所變更時,平台就會提高 API 級別。實際上,專案可能會以批次方式變更,並以特定頻率提高 API 級別 (例如每天或每週一次)。

每當平台對 Fuchsia 系統介面的語意進行回溯不相容的變更時,就會變更 ABI 修訂版本。實際上,專案可能會在某些定義的節奏 (例如每六週或每六個月) 變更 ABI 修訂版本,以批次處理不具回溯相容性的變更。

在極限情況下,語意中的每項變更都可能向後不相容,但實際上,作業系統確實會變更語意,而不會導致應用程式中斷。舉例來說,許多熱門作業系統都會新增系統呼叫,但不會中斷應用程式。

行動項目。建立文件,詳細說明平台認為哪些 Fuchsia 系統介面變更屬於回溯相容變更。隨著專案在實作方面累積經驗,瞭解哪些變更通常會導致應用程式中斷,哪些則不會,專案可能需要隨著時間推移修正該文件。

應用程式

建構元件時,終端開發人員會選取單一目標 API 級別。目標 API 層級會控管建構元件時可用的 Fuchsia IDK 宣告。舉例來說,如果建構的元件目標是 API 級別 6,就無法使用 API 級別 7 中導入的 FIDL 訊息,但如果目標是 API 級別 7 或 8,則可使用該訊息 (假設該訊息在 API 級別 8 中未遭淘汰)。

建構元件時,SDK 中的工具會包含與元件資訊清單中目標 API 級別相關聯的目標 ABI 修訂版本。這樣一來,每個元件都會宣告開發人員在建構元件時,預期平台提供的語意。一個套件可以包含許多元件,每個元件都可以選取偏好的目標 ABI 修訂版本。

平台

平台會維護支援的 ABI 修訂版本清單。平台會為指定支援 ABI 修訂版本的元件提供二進位檔相容性,也就是說,平台會嘗試為這些元件提供目標 ABI 修訂版本所指出的平台語意。

範例。請考慮從 fuchsia.foo.Bar 通訊協定轉換為 fuchsia.foo.Bar2 通訊協定。假設元件 baz.cm 的目標 ABI 修訂版本指出元件預期平台提供 fuchsia.foo.Bar。執行 baz.cm 時,平台會將 fuchsia.foo.Bar 的要求轉送至適當的實作項目。不過,在轉換至 fuchsia.foo.Bar2 後,如果使用目標 ABI 修訂版本執行元件,平台就不會再將 fuchsia.foo.Bar 的要求路徑導向實作項目,因為以該 ABI 修訂版本為目標的元件應改用 fuchsia.foo.Bar2

平台可能會在某個時間點移除對特定 ABI 修訂版本的支援。這類移除作業通常會受到重要元件尾端的限制,因為這些元件仍依賴舊版 ABI 修訂版本。平台不會維護舊版 ABI 修訂版本所隱含的完整語意,而是維護舊版元件清單,以及執行這些特定元件所需的特殊行為表格。怪異功能是相容性墊片,可讓舊版元件使用原本不支援的介面。透過這項機制,平台可以移除舊版 ABI 修訂版本的通用支援,同時仍能執行以該舊版 ABI 修訂版本為目標的特定重要元件。

範例。假設平台不再支援任何包含 fuchsia.foo.Bar 的 ABI 修訂版本,但 baz.cm 是尚未遷移至 fuchsia.foo.Bar2 的重要元件。專案可將 baz.cm 視為具有 needs-fuchsia-foo-bar 奇怪行為的舊版元件。即使平台不支援 baz.cm 的目標 ABI 修訂版本,平台仍可繼續執行 baz.cm,方法是將 fuchsia.foo.Bar 的要求路由至相容性墊片 (可能使用 fuchsia.foo.Bar2 實作)。相容性墊片不需要支援 fuchsia.foo.Bar 所隱含的完整語意。相容性墊片只需要運作良好,足以讓 baz.cm (和其他具有 needs-fuchsia-foo-bar 奇怪特性的特定元件) 正常運作即可。

平台無法執行既未指定支援的 ABI 修訂版本,也未列為舊版元件的元件,因為平台不知道這些元件預期的語意。

生命週期

Fuchsia 系統介面的每個元素 (例如系統呼叫或 FIDL 訊息) 都會經歷下列生命週期:

  1. 該元素導入平台後,在 Fuchsia 發布包含該元素的新 API 級別 SDK 之前,終端開發人員無法使用該 API。如果可以在不破壞 ABI 的情況下導入元素 (例如新增系統呼叫),則可以更新現有 ABI 修訂版本的語意,納入新導入的元素。否則,元素必須從以舊版 ABI 修訂為目標的元件中隱藏,以免中斷這些元件。
  2. 如有可能,可以導入子項元素來擴充元素。舉例來說,您可以引入新欄位,擴充 FIDL 表格。 導入子元素會為該子元素啟動另一個元素生命週期例項,包括需要新的 API 級別,才能讓該元素的 API 對於終端開發人員顯示。只有在新增子項元素不會破壞現有 API 或 ABI 時,才能擴充元素。
  3. 該元素可能已淘汰。如果元件是以舊版 ABI 修訂版本為目標,在較新的平台版本上執行時,仍可使用該元素。不過,如果目標是較新的 API 級別,開發人員就無法再使用這個元素。
  4. 平台不再支援元素推出淘汰之間的任何 ABI 修訂版本時,該元素即為舊版。此時,平台只需要支援元素,因為元素實際上是透過特殊情況由特定舊版元件使用。
  5. 如果舊版元件都不再使用該元素,即可從平台移除該元素。

動力學

這種做法會將新版 API 的存取權與遷移作業連結,藉此鼓勵開發人員改用其他介面。具體來說,如要存取新推出的 API,開發人員必須變更目標 API 級別,這表示他們必須從該 API 級別中已淘汰的任何介面遷移。

實作

實作這項設計需要 Fuchsia 系統的許多層級。本文會簡要說明每個相關層級需要進行的變更,但這些層級的詳細設計將留待後續文件說明。

FIDL

FIDL 應提供方法,註解每個通訊協定元素可用的 API 級別範圍。FIDL 工具鍊應瞭解目標 API 級別,並產生適用於該 API 級別的程式碼。

當通訊協定元素 (例如表格中的欄位或通訊協定中的訊息) 在特定 API 層級遭到淘汰時,我們希望以該 API 層級為目標的元件能夠接收含有該通訊協定元素的訊息,但要防止這些元件傳送含有該通訊協定元素的訊息。

系統標頭

系統標頭應允許開發人員指定目標 API 級別,然後根據目標 API 級別,使用這些標頭調整可見的 API 集。此外,系統標頭應定義巨集,可用於將其他程式庫中宣告的瀏覽權限限制在特定 API 級別。

vDSO

系統應提供多個 vDSO,每個 vDSO 支援的 ABI 修訂版本清單。如果可以,系統應以回溯相容的方式擴充 vDSO,但如果無法,系統可以建立新的 vDSO,並提供支援的 ABI 修訂版本清單。

擴充 vDSO 會增加現有二進位檔的攻擊面,因為這些二進位檔可以存取 vDSO 擴充功能。決定是否要擴充現有 vDSO 或鑄造新的 vDSO 時,專案應考量安全性影響和相容性影響。

vDSO 可以提供函式,檢查 vDSO 是否支援特定 ABI 修訂版本,但 vDSO 不應直接公開支援的 ABI 修訂版本清單,因為如果將該清單公開給應用程式,當清單擴充時,應用程式就會中斷。

程序架構

啟動程序時,用戶端應告知程序啟動器程序預期的 ABI 修訂版本。程序啟動器應使用這項資訊,為新啟動的程序選取適當的 vDSO 和程序啟動訊息。

開啟問題。建立沒有元件資訊清單的程序時,應使用哪個 ABI 修訂版本?其中一種做法是將 ABI 修訂版本放在可執行檔的 ELF 資料中,而不是 (或除了) 元件資訊清單中。另一種做法是將 ABI 修訂版本新增至 fuchsia.ldsvc.Loader 通訊協定,這通常會路由至可執行檔的來源。

元件架構

建構元件資訊清單的工具應將目標 API 級別做為指令列參數,並在建立的元件資訊清單中嵌入對應的 ABI 修訂版本。

雖然不需要立即執行,但元件最終會根據 ABI 修訂版本調整能力路徑。舉例來說,某個元件可能想停止向其中一個子項元件提供特定服務。立即移除服務可能會導致與舊版子項元件不相容。家長可能只希望向以較舊 ABI 修訂版本為目標的兒童提供服務。

同樣地,平台可能希望將特定舊版元件的功能,轉送至提供相容性墊片的專用目的地。舉例來說,我們可以定義轉送怪異之處,並套用至怪異之處資料表中有該怪異之處的特定舊版元件。

SDK

SDK 應以機器可讀取的格式 (例如 JSON 中繼資料),指定 SDK 支援的 API 級別,以及這些 API 級別與 ABI 修訂版本的對應關係。應修改 SDK 整合,讓終端開發人員指定目標 API 級別,並將目標 API 級別做為指令列引數,提供給所有需要該值的工具。

效能

本提案嘗試在建構和探索期間介入主要程序,盡量減少平台版本控管對效能的影響。用來執行舊版元件的相容性墊片可能會對效能造成重大影響,但專案可將元件新增至舊版元件清單時,逐一評估這些效能影響。

安全性考量

這項提案應可提升安全性,因為提案會讓 Fuchsia 軟體生態系統更容易遷移至較新的 API,而這些 API 的安全性屬性想必優於舊版 API。

此外,分配新 ABI 修訂版本的機制可避免向現有應用程式公開新 ABI,進而減少這些應用程式暴露的攻擊面。決定是否要擴充現有 ABI 或分配新的 ABI 修訂版本時,專案應考量分配新 ABI 修訂版本的安全性優勢。

這項提案確實提供惡意應用程式在平台中選取不同 (可能較舊) 程式碼路徑的機制,例如聲稱要以較舊的 ABI 修訂版本為目標。隨著平台演進,專案必須以相同的安全謹慎態度,處理支援舊版 ABI 修訂版本的程式碼,以及支援新版 ABI 修訂版本的程式碼。

隱私權注意事項

這項提案應可對隱私權產生正面影響,因為提案可讓 Fuchsia 軟體生態系統更輕鬆地遷移至較新的 API,而這些 API 的隱私權屬性可能優於舊版 API。

測試

這項提案會稍微增加測試矩陣,因為平台行為會因執行元件的 ABI 修訂版本而異。我們需要將測試矩陣的這項增加納入 Fuchsia Compatibility Test Suite (CTS) 的設計。舉例來說,專案可能會想根據 ABI 修訂版本為 CTS 建立版本,確保平台在演進過程中,不會回溯對舊版 ABI 修訂版本的支援。

說明文件

平台說明文件應更新,為每個 API 加上註解,說明目前在生命週期中的階段,以及生命週期記錄 (例如 API 的推出、淘汰和/或移除時間)。這些註解應衍生自相同的可靠資料來源,該來源會控管應用程式在指定特定 API 級別時,是否能存取這些 API。舉例來說,fidldoc 工具應瞭解 FIDL 來源檔案中的 API 級別註解,並在產生的說明文件中產生適當的註解。

每當平台建立新的 ABI 修訂版本 ID 時,專案應更新文件,說明新的 ABI 修訂版本在哪些方面與先前的 ABI 修訂版本不回溯相容,以及終端開發人員在更新應用程式時應採取哪些行動 (如有)。

此外,專案應提供一些概念性文件,說明平台為何有 API 級別,以及如何從一個 API 級別升級至另一個級別。

缺點、替代方案和未知事項

實施這項提案的成本為何?

實作這項提案的主要成本,是平台演進時營運複雜度增加。現在新增 API 時,必須協調整個專案,才能在新 API 級別中發布該 API。同樣地,淘汰 ABI 的過程也比較複雜,因為淘汰作業需要經過多個步驟。

系統本身也會變得更加複雜,因為系統的行為會部分取決於每個元件的 ABI 修訂版本。

還有哪些策略可以解決相同問題?

其他平台採用的策略是絕不移除功能。舉例來說,網路平台幾乎完全是以加法方式演進。從某種程度上來說,這種做法較為簡單,因為系統不需要淘汰功能的機制。

另一種做法是為系統的不同部分使用不同的版本 ID,而不是適用於整個系統的單一 API 級別。在某種程度上,Fuchsia 也採用這種做法。舉例來說,每個檔案系統都有自己的版本 ID,用於磁碟表示法與檔案系統的記憶體內程式碼之間的合約。為整個系統使用單一 API 級別,表示平台和應用程式之間的合約演進需要一定程度的協調。

先前技術和參考資料

這個主題有大量先前技術。本文件中的提案直接以 Android、Windows 和 macOS/iOS 的體驗為基礎。

Android

Android 具有 API 級別的概念。Android 上的每個平台介面都會註解導入介面的 API 級別。Android 應用程式也會使用 uses-sdk 元素,在資訊清單中指定目標 API 級別。原則上,Android 可以使用這個 API 級別機制,淘汰及移除舊版介面。

Windows

Windows 大量使用類似於 ABI 修訂的概念,這會顯示在應用程式資訊清單中的 SupportedOS 項目。Windows 會使用 GUID 識別應用程式的目標 ABI 修訂版本,這與本文中建議使用的不透明 64 位元整數類似。

在 Windows 中,SupportedOS GUID 會與特定 Windows 版本建立關聯。舉例來說,e2011457-1546-43c5-a5fe-008deee3d3f0 會識別 Windows Vista。不過,較新版本的 Windows (例如 Windows 7) 瞭解 GUID,並提供與 Windows Vista ABI 的相容性。e2011457-1546-43c5-a5fe-008deee3d3f0本文件中的提案將 ABI 修訂內容與平台發布內容分離,更具彈性。

macOS、iOS

macOS 和 iOS 都會使用 API_AVAILABLE@available 註解,控管建構應用程式時是否提供宣告。系統程式庫 (又稱架構) 也會使用「連結時間在之後或之前」檢查和明確的特殊情況表格,支援需要平台舊版語意的舊版應用程式。

Apple 已成功運用這些機制,將這些作業系統的應用程式從舊版 API 遷移至新版 API。