RFC-0002:Fuchsia 平台版本管理 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 使用版本管理功能,讓平台在提供相容性時持續演進。 |
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2020-04-30 |
審查日期 (年-月-日) | 2020-05-23 |
摘要
本文件提出了 API 級別和 ABI 修訂版本的概念,適用於 Fuchsia 平台。最終開發人員會根據目標 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 級別中提供的 API,應與 IDK 版本保持一致。
示例:請考慮使用
pkg/fit
,這是 SDK 中的 C++ 程式庫。fit
程式庫會宣告多個函式,每個函式都是由程式庫公開的 API。API 會定義該函式集,這表示兩個 IDK 版本應在相同 API 級別的fit
程式庫中公開相同的函式集。
在語法上,Fuchsia API 級別是未簽署的 64 位元整數。隨著平台演進 (請參閱下方的「演進」),API 層級會依序指派,並且可供人類 (包括最終開發人員) 瞭解。
ABI 修訂版本
Fuchsia ABI 修訂版本代表應用程式預期平台提供的 Fuchsia 系統介面語意。特定版本的 Fuchsia 通常支援多個 ABI 修訂版本,但特定支援的 ABI 修訂版本在 Fuchsia 版本之間的語意應保持一致 (請參閱下方的演進)。
示例:請考慮
zx_clock_get_monotonic
,這是 vDSO 在 Fuchsia 系統介面中公開的函式。ABI 修訂版本會指定此函式是否存在,以及呼叫此函式時會發生什麼事,這表示zx_clock_get_monotonic
的語意應在相同 ABI 修訂版本的 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 修訂版本,但只要將fuchsia.foo.Bar
的請求重新導向至相容性墊片,平台就能繼續執行baz.cm
,而這個墊片可能會使用fuchsia.foo.Bar2
實作。相容性墊片不需要支援fuchsia.foo.Bar
隱含的完整語意。相反地,相容性墊片只需要運作得足以讓baz.cm
(以及具有needs-fuchsia-foo-bar
異常的其他特定元件) 正常運作。
平台無法執行目標為不支援的 ABI 修訂版本,或未列為舊版元件的元件,因為平台不知道這些元件預期的語意。
生命週期
Fuchsia 系統介面的每個元素 (例如系統呼叫或 FIDL 訊息) 都會經歷以下生命週期:
- 元素會導入平台。除非 Fuchsia 發布 SDK,並且該 SDK 包含包含該元素的新 API 級別,否則終端開發人員無法使用該 API。如果元素可在不破壞 ABI (例如新增系統呼叫) 的情況下導入,則可更新現有 ABI 修訂版本的語意,以納入新導入的元素。否則,您必須隱藏元素,避免讓指定舊版 ABI 修訂版本的元件發生錯誤。
- 如有可能,您可以透過引入子項擴充元素。舉例來說,您可以透過引入新的欄位來擴充 FIDL 資料表。引入子元素會啟動該子元素的另一個元素生命週期例項,包括需要新的 API 級別,才能讓該元素的 API 對最終開發人員顯示。只有在新增子項元素不會破壞現有 API 或 ABI 時,才能擴充元素。
- 該元素可能已淘汰。針對舊版 ABI 修訂版本指定的元件,在較新的平台版本上執行時,仍可使用該元素。不過,以較新 API 級別為目標的終端開發人員將無法再使用該元素。
- 一旦平台不再支援元素的引入和淘汰之間的任何 ABI 修訂版本,該元素就會成為舊版。此時,平台只需支援元素,因為元素實際上會透過奇特的方式,由特定舊版元件使用。
- 一旦所有舊版元件都不再使用該元素,即可從平台上移除該元素。
動力學
這種做法會將存取新 API 的權限與執行這些遷移作業連結在一起,鼓勵開發人員改用非淘汰的介面。具體來說,如要取得新推出的 API 存取權,開發人員必須變更目標 API 級別,這會要求他們遷移任何在該 API 級別中已淘汰的介面。
實作
實作這項設計涉及 Fuchsia 系統的許多層,本文件將概略說明各個相關層級所需的變更,但這些層級的詳細設計則留待後續文件說明。
FIDL
FIDL 應提供一種方式,用於註解各個通訊協定元素可用的 API 級別範圍。FIDL 工具鍊應瞭解目標 API 級別,並產生適合該 API 級別的程式碼。
當特定 API 級別淘汰某個通訊協定元素 (例如表格中的欄位或通訊協定中的訊息) 時,我們希望以該 API 級別為目標的元件能夠接收含有該通訊協定元素的訊息,但希望避免這些元件傳送含有該通訊協定元素的訊息。
系統標頭
系統標頭應讓最終開發人員指定目標 API 級別,然後根據目標 API 級別調整可透過這些標頭顯示的 API 組合。此外,系統標頭應定義巨集,用於將其他程式庫中的宣告限制為特定 API 級別。
vDSO
系統應提供多個 vDSO,每個 vDSO 都支援一系列 ABI 修訂版本。在可行情況下,系統應以向後相容的方式擴充 vDSO,但如果無法這樣做,系統可以使用支援的 ABI 修訂版本清單,鑄造新的 vDSO。
擴充 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 相容性測試套件 (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) 可瞭解 e2011457-1546-43c5-a5fe-008deee3d3f0
GUID,並提供與 Windows Vista ABI 的相容性。本文件中的提案會將 ABI 修訂版本與平台版本分開,提供更彈性的彈性。
macOS、iOS
macOS 和 iOS 都會使用 API_AVAILABLE
和 @available
註解,控制在建構應用程式時是否可使用宣告。系統程式庫 (又稱為架構) 也會使用「已連結或之後」檢查和明確的異常表,以支援需要平台舊版語義學的舊版應用程式。
Apple 已成功使用這些機制,將這些作業系統的應用程式從舊版 API 遷移至新版 API。