RFC-0071:OTA 停止

RFC-0071:OTA 連續停止
狀態已接受
區域
  • 系統
說明

禁止裝置在版本邊界向後無線更新。

問題
變更
作者
審查人員
提交日期 (年/月)2021-02-03
審查日期 (年/月)2021-02-24

摘要

本文件提議的計畫,可防止裝置跨越版本邊界安裝無線更新 (OTA)。

提振精神

當儲存空間堆疊對檔案系統格式做出破壞性變更時,就會擲出格式的主要版本號碼,這會導致在舊版系統上執行的驅動程式無法嘗試掛接並使用新格式的映像檔。

如果系統更新堆疊中有相等的版本號碼,就無法讓使用者嘗試回溯至不支援其裝置所含檔案系統映像檔的驅動程式庫版本。換句話說,在裝置隔離前,這樣做可讓我們執行「反向 OTA」作業失敗。

這麼做可帶來附加價值,原因如下:

  • 因此對任何保留狀態的應用程式來說非常實用。例如,應用程式負責維護 SQLite 資料庫,其結構定義可能會隨時間而改變。
  • 具體而言,這對儲存團隊來說非常實用,因為過去團隊過去必須投入大量時間,才能分類解決這類問題,而這些問題最終是因為跨版本邊界透過反向更新而造成。
  • 可強調 Fuchsia 不支援回溯 OTA,這是嚴格執行的做法。

請特別注意,此提案不會變更支援及不支援的 OTA 序列。明確表示這項支援。OTA 返回停止的主要用途是防止開發人員裝置進入無效狀態。如果是正式版裝置,則不變化的 OTA 主要應由版本管理功能強制執行。

如果沒有本提案,嘗試跨不相容的界線進行反向 OTA 會造成開發人員嘗試啟動裝置時發生問題 (例如驅動程式庫可能不支援檔案系統格式)。透過本提案,開發人員可在執行 OTA 前找到這個問題 (且錯誤會更清楚),這樣可以提升開發人員體驗。

背景

術語

OTA 是一種升級基礎作業系統的機制。Fuchsia 裝置可以接收及安裝系統和應用程式軟體的 OTA 更新。

步進石版本是一種無法在 OTA 中略過的版本。例如,考慮依序發布 A、B 和 C 三個版本。以前,我們需要支援來自 A->BB->CA->C 的 OTA。如果我們將 B 宣告為逐步石頭版本,這會移除 A->C 邊緣,因此 A 升級至 C 的方式只有從 OTA A->B 升級至 B->C。在實務上,這對於有風險的遷移作業,以及減少我們所需的測試 OTA 數量。

OTA 返回停靠站與踏步石之間的關聯

OTA 後端和循序漸進的版本都是基本版本,因此我們必須確保安全遷移 (例如儲存空間格式遷移)。本教戰手冊說明應如何使用 OTA 回溯和步數版本,並不在本 RFC 的涵蓋範圍內。請參閱以下範例,瞭解如何使用這些原始功能支援安全遷移作業。

考慮遷移儲存空間格式。具體處理方式如下:

  1. 新增新格式的支援,但暫時不要啟用/遷移。將 OTA 返回停止。
  2. 請稍候片刻。
  3. 使用上述任一遷移策略啟用新格式。

針對實際遷移裝置的情況,我們可以再採取兩個步驟啟用清除功能:

  1. 減少含有 (3) 的階梯次發布版本。
  2. 移除舊格式的遷移程式碼和支援。

在踏一步前,我們可以假設裝置通過的是包含遷移程式碼的版本,因此可以移除對舊格式的讀取支援。

將 OTA 返回停止 (1) 高,可確保裝置不會降級至不支援新格式的版本。

碰觸返回停止的政策

應視需要推動一次返回停止。大多數變更應該都不需要背部支撐。如果這個 RFC 獲得核准,則應發布官方應對手冊文件,說明連載返回停止的特定步驟。與此同時,我們提議概略瞭解這項政策。

提出 CL 應對反停止做法時,作者應:

  • 請在 error.fuchsia.dev 上提供問題的連結,其中說明需要這麼做的原因,以及開發人員如果絕對需要將應用程式降級至多個返回停止處 (例如答案可能是閃爍或繞行),開發人員可以採取哪些行動。
  • 取得 //src/sys/pkg/OWNERS 核准。

設計

讓我們導入可同時出現在更新套件和系統中的 epoch.json 檔案。它應該是具有兩個字串鍵的 JSON 檔案:

  • 「version」,epoch.json 結構定義版本應有一個單一字串值。實際上,執行更新時不會檢查這個項目,只有在實際工作環境中對 epoch.json 結構定義變更時,這組鍵才會出現變化。
  • 「epoch」,此工作應具有一個 OTA backstop 的單一整數值。如果更新套件的紀元 < 系統週期> <wbr> 就應該在準備階段使用 UNSUPPORTED_DOWNGRADE 失敗 OTA。

舉例來說,epoch.json 可能如下所示:

{
  "version": "1",
  "epoch": 5
}

為了安全碰觸週期,我們還會引進 epoch_history 檔案,此檔案會透過建構系統編譯到 epoch.json 中。epoch_history 檔案可以是以下格式:

0=Initial epoch (https://fxbug.dev/42144857)
1=Storage format migration (https://fxbug.dev/XXXXX)
...
N=Most recent change (https://fxbug.dev/YYYYY)

每次出現回溯不相容的變更時,都應手動疊加 epoch_history 檔案。

雖然中介 epoch_history 檔案增加了一層複雜度,但這種方法的優點如下:

  • 其中提供所有版本上升的異動記錄 (強制說明文件!)
  • 如果兩人因不同原因嘗試碰觸週期,就會產生合併衝突。

實作

變更會完全在平台中進行 (特別是系統更新堆疊)。

為因應這項變革,我們必須:

  • epoch_history 新增至 //src/sys/pkg/bin/system-updater。
    • 此外,請建立可將 epoch_history 轉換為 epoch.json 的指令碼。
    • 讓建構系統使用這個指令碼,將 epoch.json 新增至系統更新工具的退出目錄。
  • 修改 BUILD,讓 epoch.json 也會納入更新套件。
  • 系統更新工具應在「準備」階段結束時檢查 epoch.json
    • 如果更新套件中沒有 epoch.json,或是還原序列化時發生問題,則假設週期為 0。我們會謹慎忽略錯誤,以便在 epoch.json 結構定義變更時仍可透過 OTA 進行通訊。
    • 如果 system-updater 的目錄中沒有任何 epoch.json,或還原序列化時發生問題,則因這是非預期的結果而失敗。建議您使用 include_str 巨集從 out Directory 讀取資料。
    • 如果更新套件中的 Epoch 紀元時間 < epoch 於 system-updater 中的 Epoch,請使用原因 UNSUPPORTED_DOWNGRADE 失敗。您必須為 UNSUPPORTED_DOWNGRADE 建立新的 PrepareFailureReason

安全性

這不是安全性功能。不過,它可能會與安全性功能互動,改善開發人員工作流程。舉例來說,假設某項復原防護功能功能會拒絕啟動低於 N 版本的映像檔,就屬於這個情況。如果在輸出映像檔 N 版時增加週期,則會造成開發人員無法降級無法啟動的版本,因為這些降級會在 OTA 返回停止時失敗。

除此之外,我們選擇將 epoch.json 嵌入 system-updater 二進位檔 (而不是在 config-data) 中,讓 OTA 能更有效地應對設定資料毀損情形。

隱私權和效能注意事項

測試

我們可以在 //src/sys/pkg 中使用現有的系統更新測試架構,這個架構結合了單元和整合測試。

此外,OTA e2e 測試可確保反向停止是不會減少且採用有效格式。例如:

  • 如果建構 N 降低 OTA 反向停止,則 CI 就會失敗,從 N-1 版本到 N
  • 如果建構 N 在系統更新工具中產生無效的 epoch.json,則在 CI 至 OTA 中將失敗。
  • N' 中建構 N

說明文件

我們需要建立文件來說明更新 epoch_history 的政策。

而且,我們還需要修改:

缺點、替代方案和未知

實作這項提案需要多少費用?

實作本提案的主要成本會增加平台的複雜度,因為我們要在平台中加入另一個版本 ID。

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

另一個策略是正式支援所有反向 OTA。這點並不實用,因為如果我們不知道這些變更是什麼,就不能編寫適用於日後變更的程式碼。

另一個策略是明確禁止「所有」反向 OTA (即使在其他情況下可行)。舉例來說,我們可以自動在每個新版本中執行返回停靠站。我們決定不這麼做,因為在實務上,有些開發人員「確實」仰賴這些反向 OTA,我們希望避免破壞這些開發人員。

另一個方法是直接整合 Fuchsia 平台版本管理 (請參閱 RFC-0002)。但是,這個問題有幾個模稜兩可的問題。舉例來說,是否應防範整個 API 級別的所有反向 OTA?還是應選擇特定級別?我們會打破誰?由於 Fuchsia 針對系統的不同部分使用不同的版本 ID (例如檔案系統有自己的版本 ID),所以這似乎是較簡單的選項。

先前的圖片和參考資料

Android 進一步瞭解網路旅行社。

特別銘謝

James Sullivan 貢獻了激勵和步行的石頭區塊。Zach Kirschenbaum 撰寫了 Dan Johnson 評論的原始設計文件