RFC-0076:FIDL API 摘要

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

為人類可讀的 FIDL API 介面提供格式。

問題
更小鳥
作者
審查人員
提交日期 (年月分)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 介面能否發展至另一個 API 介面。與目前使用的方法相比,這種做法的準確度更高。在目前使用的方法中,程式庫來源的穩定 (稱為「正規化」) 形式產生方式,是將所有來源檔案串連起來,並移除註解與不相關的間距。

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

    CTS 尤其需要減少對平台變更執行的測試耗用的電量。瞭解 API 介面的變更項目,可能可讓軟體僅執行受變更影響的測試,進而節省執行時間和運算資源。

入門範例

請考慮以下從 fuchsia.accessibility.gesture 取得的 FIDL 程式庫定義。註解已縮減,但程式庫尚未完整完成。

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 摘要產生的 API 摘要「必須」列出影響 API 介面的 FIDL 程式庫的所有元素。

設計

API 摘要格式包含對 API 影響的程式庫相關資訊。這項資訊在定義: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 檔案中的實際排序方式為何 (包括分割至多個檔案),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 介面摘要