RFC-0076:FIDL API 摘要

RFC-0076:FIDL API 摘要
狀態已接受
區域
  • FIDL
說明

提供可供人類閱讀的 FIDL API 途徑格式。

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

摘要

提供摘要方法來說明 FIDL API 介面,並以人類可讀格式做為第一個輸出內容,並建議利用這項摘要來識別 Fuchsia 來源樹狀結構中 FIDL 程式庫的 API 異動。

修訂 (2022 年 8 月):這份 RFC 說明瞭一種人類可讀的文字格式,每個 API 元素都位於單一行中。在導入期間,我們新增了含有相同資訊的 JSON 格式 (https://fxrev.dev/480357)。與文字格式不同,JSON 格式可解析回 Go 資料結構,這對 fidl_api_diff 特別有用。由於目前只使用 JSON 格式,因此我們已移除文字格式,以利維護。

提振精神

在撰寫本文時,Fuchsia 專案已展開多項努力,共同目標是追蹤平台 API 途徑的變更。完成後,我們就能使用版本管理,將平台開發作業與 SDK 使用者使用的程式庫版本分開。

特別是在 FIDL 的網域中,需要以人類可讀的方式呈現 FIDL 程式庫的 API 途徑。這項表示法 (以下稱為「摘要」) 可用於多種用途:

  • 以人性化的方式,列出 FIDL 程式庫提供的 API。

    其他產生 API 介面的軟體 (例如 go) 也會保留類似的清單。這樣一來,在需要版本化的情況下,您就能將版本歸給特定 API 摘要。

  • 用於偵測 FIDL API 中不可向下相容的變更。

    您可以使用 API 摘要功能計算兩個 API 途徑之間的差異,以便自動檢查一個 API 途徑是否可演變為另一個。這項功能可改善目前使用的準確度,在該方法中,系統會以可預測的方式連結所有來源檔案,並移除註解和不相關的空格,產生穩定的 (稱為「標準化」) 程式庫來源形式。

  • 作為其他工作 (例如 Compatibility Testing Suite (CTS,請參閱 RFC-0015) 的構建區塊,用於偵測 API 變更後需要執行的測試。

    特別是 CTS 需要裁減在平台變更時執行的測試套組。瞭解 API 途徑中的變更內容,可讓軟體只執行受變更影響的測試,進而節省執行時間和運算資源。

入門範例

請參考下列 FIDL 程式庫定義,取自 fuchsia.accessibility.gesture。雖然註解已刪除,但程式庫仍完整無缺。

library fuchsia.accessibility.gesture;

/// Maximum size of a returned utterance.
const uint64 MAX_UTTERANCE_SIZE = 16384;

/// Gesture types that accessibility offers to a UI component for listening.
enum Type {
    THREE_FINGER_SWIPE_UP = 1;
    THREE_FINGER_SWIPE_DOWN = 2;
    THREE_FINGER_SWIPE_RIGHT = 3;
    THREE_FINGER_SWIPE_LEFT = 4;
};

/// An interface to listen for accessibility gestures.
protocol Listener {
    /// When accessibility services detect a gesture, the listener is informed
    /// of which gesture was performed.
    OnGesture(Type gesture_type) -> (bool handled, string:MAX_UTTERANCE_SIZE? utterance);
};

/// An interface for registering a listener of accessibility gestures.
[Discoverable]
protocol ListenerRegistry {
    /// A UI registers itself to start listening for accessibility gestures
    /// through `listener`.
    Register(Listener listener) -> ();
};

上述程式庫的 API 摘要如下所示:

protocol/member fuchsia.accessibility.gesture/Listener.OnGesture(fuchsia.accessibility.gesture/Type gesture_type) -> (bool handled,string:16384? utterance)
protocol fuchsia.accessibility.gesture/Listener
protocol/member fuchsia.accessibility.gesture/ListenerRegistry.Register(fuchsia.accessibility.gesture/Listener listener) -> ()
protocol fuchsia.accessibility.gesture/ListenerRegistry
const fuchsia.accessibility.gesture/MAX_UTTERANCE_SIZE uint64 16384
enum/member fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_DOWN 2
enum/member fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_LEFT 4
enum/member fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_RIGHT 3
enum/member fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_UP 1
strict enum fuchsia.accessibility.gesture/Type uint32
library fuchsia.accessibility.gesture

請注意以下幾點:

  • 每個 API 元素都是一行文字。
  • 每個 API 元素都會以完整的名稱參照。
  • API 元素在摘要中顯示的順序是固定的。如果 FIDL 檔案中的宣告順序有所變更,這不會影響 API 摘要的形狀。
  • 您可以輕鬆使用 grep 等文字工具,擷取摘要的部分內容。舉例來說,假設 API 摘要位於名為 fidl.api_summary 的檔案中,下列指令列就只會擷取該通訊協定的 API 介面:

    cat fidl.api_summary | grep "fuchsia.accessibility.gesture/ListenerRegistry"
    

    同樣地,您也可以輕鬆擷取方法:

    cat fidl.api_summary \
      | grep "fuchsia.accessibility.gesture/ListenerRegistry" \
      | grep "protocol/member"
    
  • 您可以透過以下方式產生基本的 API 介面差異:

    diff -u fidl.old.api_summary fidl.new.api_summary
    

    (假設 fidl.{old,new}.api_summary 分別包含原始和修改過的 API 途徑)

需求條件

  • API 摘要應可供人類閱讀,並可透過 grepdiff 等簡單工具處理。

  • 產生的 API 摘要必須列出所有 FIDL 程式庫元素,且僅限於會影響 API 介面的元素。

設計

API 摘要格式包含有 API 影響的程式庫相關資訊。這項資訊已在「Definitions: Source Compatibility and Transitionability of RFC-0024」一節中定義,並在 FIDL 繫結規格中擷取。這項資訊其實只是 FIDL IR 中現有資訊的一小部分,但以更易於人類閱讀及文字公用程式處理的方式呈現。如需完整清單,請參閱規則摘要

每個 FIDL 語言結構都涵蓋在摘要規則中。

每個 FIDL 宣告都會使用完整的名稱命名。舉例來說,在上述範例中擷取的縮短程式碼片段:

library fuchsia.accessibility.gesture;
enum Type { THREE_FINGER_SWIPE_UP = 1; };
protocol Listener {
  OnGesture(Type gesture_type);
};

而 ID OnGesture 一律會稱為 fuchsia.accessibility.gesture/Listener.OnGesture

為了方便閱讀和處理,我們刻意將檔案格式保持平面。這表示 FIDL 成員 (出現在 structprotocol 等範圍中) 會列在不同的文字行中。這樣一來,我們日後就能視需要擴充格式。舉例來說,日後推出的版本屬性可供使用時,您就能納入這些屬性。

單一 API 摘要檔案會列出整個 FIDL 程式庫中顯示的所有宣告,不論宣告是在多少個檔案中指定皆然。

在 API 摘要中顯示的宣告順序不受宣告順序影響,且不會變動。相關宣告會刻意保持緊密,以利後續處理,但這並非正確性要求:任何與宣告順序無關且穩定的順序都已足夠。

API 摘要排序

宣告的順序會取自 FIDL AST:宣告會按照 AST 的後序順序進行檢查,在同層宣告中選擇字母數字較小的完整名稱做為 ID。

我們稱這種排序為 API 摘要排序。

這種做法建議在 API 摘要檔案中,以以下順序宣告:

fuchsia.accessibility.gesture/Listener.OnGesture
fuchsia.accessibility.gesture/Listener
fuchsia.accessibility.gesture/ListenerRegistry.Register
fuchsia.accessibility.gesture/ListenerRegistry
fuchsia.accessibility.gesture/MAX_UTTERANCE_SIZE
fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_DOWN
fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_LEFT
fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_RIGHT
fuchsia.accessibility.gesture/Type.THREE_FINGER_SWIPE_UP
fuchsia.accessibility.gesture/Type
fuchsia.accessibility.gesture

上述 FIDL 程式庫的範例。

無論宣告在 .fidl 檔案中的實際順序為何 (包括是否已分散至多個檔案),API 摘要中的宣告順序都會保持不變。

API 摘要宣告結構定義

以下列出 API 摘要檔案的簡化 BNF,供您參考。

summary          ::= declaration_list

declaration_list ::= declaration
                   | declaration "\n" declaration_list
declaration      ::= library
                   | const
                   | bits
                   | bits_member
                   | enum
                   | enum_member
                   | struct
                   | struct_member
                   | union
                   | union_member
                   | protocol
                   | protocol_member
                   | alias

alias           ::= "alias" fqn
bits            ::= strictness "bits" fqn fp
bits_member     ::= "bits/member" fqn
const           ::= "const" fqn d fv
enum            ::= strictness "enum" ft
enum_member     ::= "enum/member" fqn fv
library         ::= "library" fqn
protocol        ::= "protocol" fqn
protocol_member ::= "protocol/member" fqn d
struct          ::= resourceness "struct" fqn
struct_member   ::= "struct/member" fqn ft [ fv ]
union           ::= strictness "union" fqn
union_member    ::= "union/member" fqn

resourceness    ::= "" | "resource"
strictness      ::= "flexible" | "strict"

d   ::= <FIDL protocol member type signature>
fp  ::= <FIDL primitive type>
fqn ::= <FIDL identifier>
ft  ::= <FIDL type>
fv  ::= <FIDL value>

實作

API 摘要功能是由程式 fidl_api_summarize 實作。程式會將 FIDL IR 做為輸入,並輸出 FIDL API 摘要,兩個檔案名稱都會指定為標記。呼叫端應當使用擴充功能 .api_summary 來輸出這個程式的內容,但這並非硬性規定。

成效

fidl_api_summarize 是 FIDL IR 檔案的簡單轉換。根據隨機檢查結果,在相當大的程式庫上執行時,程式可在約 0.1 秒內完成執行。也就是說,這個程式很可能可在每個 FIDL 程式庫上執行,並納入一般建構程序。

安全性考量

fidl_api_summarize 目前的實作方式不會嘗試驗證 FIDL IR,並假設其輸入內容一律會產生為 fidlc 的有效輸出內容。這可能會讓程式容易受到格式錯誤的輸入內容影響,但很難判斷這是否可用於攻擊 Fuchsia 建構程序的攻擊向量。

隱私權注意事項

fidl_api_summarize 處理的資訊到目前為止都是公開可見的程式碼存放區的一部分。因此,我們可以合理地假設,對輸入內容適用的隱私權規則也適用於輸出內容。

也就是說,如果用於匯總非公開的 FIDL 程式庫程式碼,其輸出內容應遵循與所用程式庫程式碼相同的隱私權標準。

測試

我們會使用豐富的範例輸入程式庫測試程式,並將處理後的結果與本機輸出結果進行比較。這可確保在 Fuchsia 程式碼集的整個生命週期中,結果一致。

說明文件

fidl_api_summarize 的使用方式應記載於 https://fuchsia.dev 的 FIDL 說明頁面。

既有技術與參考資料

Go 語言 API 會定期產生 API 介面摘要