RFC-0196:FIDL 大型郵件

RFC-0196:FIDL 大型郵件
狀態已接受
領域
  • FIDL
說明

支援透過 FIDL 通訊協定傳送大型郵件。

問題
  • 100478
蓋爾特變化
作者
審查人員
提交日期 (年-月-日)2022-06-28
審查日期 (年-月-日)2022-10-27

摘要

目前 FIDL 語言會針對超過 zircon 的郵件限制訊息大小 並且支援 64KiB 的通道及通訊端本文件將 處理任意大型訊息 (即使郵件溢位) 的高階設計 訊息位元組數上限,會限制基礎傳輸作業。藉由 我們採用了類似現有模式的解決方案,來推動類似的解決方案。 使用 fuchsia.mem.Data、最高級別、自動推估 FIDL 以及支援語言

提振精神

目前所有透過電匯傳送的 FIDL 訊息設有 ZX_CHANNEL_MAX_MSG_BYTES,目前相當於 64 KiB,而且衍生自 最多可透過 zircon 管道傳送的訊息大小上限。會傳送訊息 超過此上限就無法編碼

現今的常見解決方法是傳送任意大型資料 對 zx.handle:VMO 執行 blob,或者使用 fuchsia.mem.Data, 包含所傳送資料 blob 的基礎 VMO。這些 blob 含有使用者想代表的 經由 FIDL 編碼/解碼,但無法強制自行進行投放。 今天 fuchsia.git 中的包裝函式類型大量使用。

一些問題是因缺乏大型訊息支援而造成。最核心 其中有眾多錯誤是由少見的通訊協定所造成 傳送大型郵件,但專業技術上來說可進行這項操作。範例包括 。 需要採用 :MAX 大小的 vectorstring 的每個 API 都會安全漏洞 還有許多其他極端情況 (例如:table 版面配置 幾乎所有欄位都會填入資料。一般情況下 利用無法以 64KiB 為目標的訊息形式接受使用者資料 可能會受到這個失敗模式影響

透過 VMO 傳送無類型的資料 blob 也不符合人體工學,因為這一切都會遺失 類型資訊,因此必須在接收端手動重建。 不要利用 FIDL 描述資料形狀,並去除 code->send->decode->分派管道,強制使用者將 將其封裝到另一則 FIDL 訊息中 反而會反向處理例如:ProviderInfo API 具有子項類型 InspectConfigInspectSource 目前分別由 fuchsia.mem.Bufferzx.handle:VMO 表示 但代表可描述及處理的結構化資料 以及 FIDL。

使用 zx.handle:VMOfuchsia.mem.Data 會引發以下情況: 強制使用資料專用的 FIDL 類型必須含有 resource 修飾符。這有 對繫結 API 造成的下游影響,導致在 即使在合理情況下,Rust 仍無法衍生 Clone 特徵。

由於無法充分支援大型訊息支援,造成的錯誤和人因工程問題 的大量性在草擬此 RFC 草擬期間接受的問卷調查至少顯示 大約過去 30 個案例,而更全面地支援大型訊息支援服務 協助 FIDL 使用者

相關人員

講師:hjfreyer@google.com

審查人員:abarth@google.com、chcl@google.com、cpu@google.com、 mseaborn@google.com、nickcano@google.com、surajmalhotra@google.com

諮詢:bprosnitz@google.com、geb@google.com、hjfreyer@google.com、 jmatt@google.com、tombergan@google.com、yifeit@google.com

社交:五個團隊 (元件解析器、DNS 解析器、驅動程式庫 開發、WLAN SME 和 WLAN 政策) 一共測試了原型設計 設計:

  • 元件解析器:geb@google.com
  • DNS 解析器:dhobsd@google.com
  • 驅動程式開發:dgilhooley@google.com
  • WLAN 政策:nmchijacken@google.com
  • WLAN SME:chcl@google.com

此外,現有 fuchsia.mem.Data 和 30 多個使用者 我們已採訪 fuchsia.mem.Buffer 種類型,提供設計相關意見回饋和使用 案例合適度

設計

「必須」、「不得」、「必要」、「應」、「不應」、「應該」、 「不應該」、「建議」、「可能」和「選用」基本上就是 將解讀為 IETF RFC 2119 中所述。

郵件溢位問題與傳輸層級問題有關。如何構成大型訊息 以及如何處理符合該定義的訊息 Zircon 管道、驅動程式庫架構、 Overnet 等等也就是說 呼叫特定方法要求或回應「large」不是抽象 陳述式:「必須」一律定義明確的「大」定義的 以及該方法專屬的通訊協定

下列指令會指定訊息的宣告方式:「我很大, 因此必須特別要求 處理」。無論在介面定義中,這項宣告都「必須」清楚易讀 在 *.fidl 檔案中,為任何指定裝置指定的通訊協定和執行階段 即訊息執行個體發生溢位

具體來說:在這個設計前,寄件人可以傳送完全有效的表單 訊息超過基礎傳輸上限的訊息位元組上限, 這會導致出現意料之外且難以偵錯的 PEER_CLOSED 執行階段 失敗。變更完成後,fidlc 編譯器會以靜態方式檢查,確認是否有輸入錯誤 可能大於傳輸的最大值 訊息位元組限制,如果是的話,會產生特殊的「溢位」處理程式碼 反映這一點這個模式會啟用次要執行階段訊息傳送 大型訊息的機制,無受限的側邊管道 (如果是 zircon 管道、VMO) 用於儲存訊息的內容。這項新功能 訊息傳送路徑完全加到「guts」產生的繫結 因此能維持 API 與 ABI 的相容性。FIDL 方法 實作項目現在可以確定不會觸發任何可分配的訊息 PEER_CLOSED,原因是達到任意位元組大小限制。

傳輸格式變更

名為 byte_overflow 旗標的新位元會新增至動態參數 FIDL 交易郵件部分標示 標題)。翻轉這個標記後,代表 保留的訊息只包含訊息的控制層 系統會將訊息的其餘部分儲存在可能不連續的緩衝區。

這個獨立緩衝區的位置及存取該緩衝區的方式為 須視運輸系統而定。如果 byte_overflow 標記有效,表示傳輸中 控制層訊息「必須」包含 16 位元組交易郵件標頭 後面接著附加 16 位元組附錄訊息,說明 大型訊息。這表示此訊息「必須」為 32 個位元組: 預設 FIDL 郵件標頭,後面接著所謂的 message_info 結構 包含三項資料:uint32標記、uint32保留給 可能指定訊息附加的控點數量 排除溢位緩衝區,以及表示內資料大小的 uint64 VMO 本身:

type MessageInfo = struct {
  // Flags pertaining to large message transport and decoding, to be used for
  // the future evolution and migration of this feature.
  // As of this RFC, this field must be zeroed out.
  flags uint32;
  // A reserved field, to be potentially used for storing the handle count in
  // the future.
  // As of this RFC, this field must be zeroed out.
  reserved uint32;
  // The size of the encoded FIDL message in the VMO.
  // Must be a multiple of FIDL alignment.
  msg_byte_count uint64;
};

由於需要產生額外控制代碼指向溢位緩衝區, 大型 FIDL 郵件可能只有 63 個帳號代碼,而不是一般的 64 個帳號代碼。 這種行為不正常且讓人意料之外,只會在回報時回報 傳送文字訊息這個不幸的邊角案例會因為承諾 開發核心改善功能來修正

byte_overflow 旗標「必須」佔用第 6 個位元 (即倒數第二位元) 重要內容)。位元 #5 會保留給 潛在未來 handle_overflow 位元,但目前未使用。 這個位元不得用於其他用途。

執行階段要求

解碼期間違反多項條件時,必須 否則會導致 FIDL 傳輸錯誤,通訊過程立即關閉 管道。如果已設定 byte_overflow 旗標,控制層的大小 如上所述,訊息「必須」為 32 個位元組。 訊息「必須」透過其他媒介傳輸。

如為 Zircon 管道傳輸,位元組溢位的媒介 緩衝區必須為 VMO。也就是關聯控制代碼的 控制層訊息必須至少含有一則指向的核心物件 最後一個控制代碼「必須」為 VMO,而系統讀取的位元組數 接收方 VMO 的 VMO必須等於 msg_byte_count 的值 message_info結構中的欄位。如果已知郵件是繫結 此值必須小於或等於靜態計算的大小上限 其他酬載

訊息傳送者必須透過 zx_vmo_create syscall 建立新的 VMO。 後面緊接著 zx_vmo_write 來填入該參數的主體 撰寫新的電子郵件訊息這些物件「必須」確保代表溢位 VMO 的控制代碼確實 沒有正確的 ZX_RIGHT_WRITE

在接收端,訊息的收件者「必須」唸出資料 包含使用 zx_vmo_read 的訴訟保留。因此,透過 zircon 傳送的一般 FIDL 訊息 管道只需要兩個系統呼叫 (zx_channel_write_etc代表傳送者和 接收端的 zx_channel_read_etc,位元組溢位訊息需求 這些國家/地區 (zx_channel_write_etczx_vmo_createzx_vmo_write 的 傳送者,以及 zx_channel_read_etczx_vmo_readzx_handle_close: 接收方)。這樣很容易受到懲罰,但日後的最佳化作業 (例如 改善 zx_channel_write_etc API,因此可能去除 這些費用訊息接收者不得嘗試寫入 溢位 VMO

程式碼產生功能異動

FIDL 繫結實作必須針對任何酬載產生溢位處理常式 位元組上限可能大於其通訊協定的訊息 傳輸負載的上限。為此,FIDL 訊息可能會廣泛拆分為 三個類別:

  • 有界限: 累計位元組數上限的訊息一律已知。 這個類別包含大部分的 FIDL 郵件。如為這類訊息 產生器必須採用計算出的訊息位元組數上限 決定是否納入設定 byte_overflow 旗標的功能 以及是否在解碼時間檢查具體而言 如果累積位元組數上限大於 通訊協定傳輸上限 (如 Zircon 頻道則為 64KiB)、功能 在編碼時間設定 byte_overflow 旗標和必要的解碼時間標記 檢查產生的程式碼「必須」加入;否則這些廣告素材必須 不要
  • 半界限: 累計位元組數上限的訊息僅 都能得知相關資訊這個類別包括任何會生成發送通知的郵件 可繫結,但遞移包含 flexible uniontable 定義針對這類訊息,繫結產生器必須使用計算出的 確認訊息的位元組上限,判斷是否要將 在編碼時設定 byte_overflow 旗標的功能,但此旗標必須 一律會在解碼時檢查
  • Unbounded: 累計位元組計數上限的訊息是由 定義永遠無法理解這個類別包括 轉換方式包含遞迴定義或不受限的 vector。針對這類 訊息、產生的繫結程式碼必須一律包括 編碼上的 byte_overflow 旗標,而且「必須」一律檢查 解碼器。
@transport("Channel")
protocol Foo {
  // This request has a well-known maximum size at both encode and decode time
  // that is not larger than 64KiB limit for its containing transport. The
  // generated code MUST NOT have the ability to set the `byte_overflow` on
  // encode, and MUST NOT check it on decode.
  BoundedStandard() -> (struct {
    v vector<string:256>:16; // Max msg size = 16+(256*16) = 4112 bytes
  });
  BoundedStandardWithError() -> (struct {
    v vector<string:256>:16; // Max msg size = 16+16+(256*16) = 4128 bytes
  }) error uint32;

  // This request has a well-known maximum size at both encode and decode time
  // that is greater than the 64KiB limit for its containing transport. The
  // generated code MUST have the ability to set the `byte_overflow` on encode,
  // and MUST check it on decode.
  BoundedLarge() -> (struct {
    v vector<string:256>:256; // Max msg size = 16+(256*256) = 65552 bytes
  });
  BoundedLargeWithError() -> (struct {
    v vector<string:256>:256; // Max msg size = 16+16+(256*256) = 65568 bytes
  }) error uint32;

  // This response's maximum size is only statically knowable at encode time -
  // during decode, it may contain arbitrarily large unknown data. Because it
  // is not larger than 64KiB at encode time, the generated code MUST NOT have
  // the ability to set the `byte_overflow` on encode, but MUST check for it on
  // decode.
  SemiBoundedStandard(struct {}) -> (table {
    v vector<string:256>:16; // Max encode size = 32+(256*16) = 4128 bytes
  });
  SemiBoundedStandardWithError() -> (table {
    v vector<string:256>:16; // Max encode size = 16+32+(256*16) = 4144 bytes
  }) error uint32;

  // This response's maximum size is only statically knowable at encode time -
  // during decode, it may contain arbitrarily large unknown data. Because it
  // is larger than 64KiB at encode time, the generated code MUST have the
  // ability to set the `byte_overflow` on encode, and MUST check for it on
  // decode.
  SemiBoundedLarge(struct {}) -> (table {
    v vector<string:256>:256; // Max encode size = 32+(256*256) = 65568 bytes
  });
  SemiBoundedLargeWithError(struct {}) -> (table {
    v vector<string:256>:256; // Max encode size = 16+32+(256*256) = 65584 bytes
  }) error uint32;

  // This event's maximum size is unbounded. Therefore, the generated code MUST
  // have the ability to set the `byte_overflow` on encode, and MUST check for
  // it on decode.
  -> Unbounded (struct {
    v vector<string:256>;
  });
};

ABI 與 API 相容性

這項設計在全面推出後,與 ABI 和 API 完全相容。是 一律支援 ABI,因為任何會將先前限定酬載轉換為 不受限或半界限的特徵,例如將 struct 變更為 table,或 修改 vector 大小邊界已經是 ABI 破壞活動的變更。

對於未受限或半限定酬載,byte_overflow 標記一律會是 系統會執行檢查程序,無論大小為何。這表示 而可在連線的一端進行編碼,則即使是在另一端, 因此,當演變時加入不明資料,導致訊息來自 而非解碼器的酬載類型檢視畫面

在推出期間的中間期,可能是當事方 就會擁有能夠得知大型郵件的 FIDL 繫結,而 否則大型訊息將無法解碼這類似於 目前這類訊息在編碼過程中會失敗 並且會稍微遠離來源。

在中繼推出期間,解碼失敗的風險會視為風險 非常低,因為大多數可以傳送大型訊息的 API 都已有通訊協定 和分塊等類似措施主要風險媒介是 通訊協定開始透過現有方法傳送現在允許的大型郵件。這些 通訊協定改為導入新的大型訊息功能 方法。

設計原則

這項設計遵循幾項重要原則。

用多少付多少

FIDL 語言的主要設計原則是您只需要為您所用的部分付費 使用方式。本文所述的大型訊息功能 堅持到底

使用受限酬載的方法,對於此 RFC 的效能也不會降低 存在。使用半受限或未受限酬載的方法,但不可使用 傳送超過通訊協定傳輸上限的郵件,只要支付 單一位元旗標檢查作業的費用。僅限符合下列條件的訊息 實際使用大型訊息溢位緩衝區時,就會發現 受影響的資源。

不需要大型訊息支援的使用者 (即大多數的方法/通訊協定) 表示都不需要支付任何費用 寫入時產生的執行階段效能成本及心理負擔 FIDL API。

不遷移

現在可以在任何位置啟用大型訊息,任何可能的酬載 使用這類 API,而且無須遷移現有的 FIDL API 或其用戶端/伺服器 。先前會導致 PEER_CLOSED 執行階段的案件 「只是工作」的錯誤。

訂製交通

這項設計可靈活滿足不同傳輸方式的需求,包括現有和新的傳輸方式 推測。舉例來說,如果是在 Pod 中運作的 只要翻轉 byte_overflow 位元並 傳輸會知道如何排序包含封包的溢位。

實作

這項功能將在實驗性的 fidlc 標記之後推出。每項 接著,繫結後端會進行修改,以處理大型訊息,方法如指定 這個 RFC。產生 功能視為穩定版,標記會遭到移除, 相關單位會如何運用資料,並讓他們覺得自己 獲得充分告知,且能夠針對該使用方式表示同意

這項屬性只是用途,因此不需要額外的 fidlc 支援 會將執行溢位檢查的必要資訊傳遞給 說明如何支援大型訊息的一系列後端

在此 RFC 之前,繫結都會將所有編碼/解碼緩衝區放在 建議日後「必須」繼續繫結 對沒有 byte_overflow 旗標的訊息行為而言。 如果是這種情況,請務必在堆積上分配繫結。

成效

如要估算提議的放送方式對成效的影響,可以使用 核心 Microbenchmark 整理並比較兩個案例:傳送 B 大小與傳送 16 位元組管道訊息及傳送 VMO 的總和 尺寸 B - 16,適用於下列 B 的值:16KiB、32KiB、64KiB、128KiB、256KiB 512KiB、1024KiB、2048KiB 和 4096KiB。

清單 1:顯示預估 1送達時間成效的表格 「tax」以 16 位元組管道訊息和 VMO 的形式傳送 B 個位元組的資料,會付費 而不是採用 B 大小的管道訊息:

訊息大小 / 策略 僅限頻道 管道 + VMO VMO 使用稅
16KiB 2.5 微秒 5.9 微秒 136%
32KiB 4.5 微秒 7.7 微秒 71%
64KiB 7.9 微秒 13 微秒 65%
128KiB 16.5 微秒 23.3 微秒 41%
256KiB 35.8 微秒 54.4 微秒 52%
512KiB 71.3 微秒 107.4 微秒 51%
1024KiB 157.0 微秒 223.4 微秒 42%
2048KiB 536.2 微秒 631.8 微秒 18%
4096KiB 1328.2 微秒 1461.8 微秒 10%

清單 2:顯示預估送達時間成效「稅金」的圖表已付款 以 16 位元組管道訊息和 B 大小的 VMO 的形式傳送 B 個位元組的資料時 - 避免採用 B 大小的管道訊息,而是 16。

比較純管道與管道 + VMO 的比較
圖表

清單 3:以線性方式比較不同廣告活動之間交付時間的成效 以 16 位元組管道訊息和 B 到 16 的 VMO 的形式傳送 B 個位元組的資料 而不是 B 大小的管道訊息

不同酬載的 VMO 用量懲罰圖表
大小

這些資料帶來幾項有趣的觀察結果。這裡可以看到 資料大小與放送時間之間的關聯性約為線性。另有 這兩種方法的成效差距很明顯 差距似乎會隨著訊息大小而縮小。

綜合這些結果後,我們就能建立傳送 FIDL 的預期效能 藉此建立大型訊息應該就能 所謂的「VMO 稅」比一般的舊管道訊息大小高出一定大小 對於相同大小 (允許) 端對端約增加 20% 到 60% 運送時間。有趣的是,依此百分比的差距 就能大幅降低 傳送的訊息大小增加,表示 VMO 稅金增加 在酬載大小方面,則略有非線性。

清單 4:顯示模擬推送時間成效的表格 部分相關內容。

訊息大小 / 策略 僅限頻道 訊息 + VMO
16KiB 2.5 微秒 --
32KiB 4.5 微秒 --
64KiB 7.9 微秒 13 微秒
128KiB -- 23.3 微秒
256KiB -- 54.4 微秒
512KiB -- 107.4 微秒
11024KiB -- 223.4 微秒
2048KiB -- 631.8 微秒
4096KiB -- 1461.8 微秒

清單 5:以線性比例圖顯示模擬推送時間成效 實作本文件所述的設計請注意 64KiB 的不連貫性 建議從一般訊息改為大型訊息

模擬結果的線性圖
表演

人體工學

這項變動對人體工學有重大改善,基本上 zx.handle:VMOfuchsia.mem.Buffer 和 您現在可以改用第一級的 FIDL 概念來描述 fuchsia.mem.Data。 下游繫結程式碼的優點,以及之前必須 仍可使用一般的 FIDL 路徑進行無類型的處理。於 基本上,針對大型郵件產生的 FIDL API 與 非大型訊息副本

回溯相容性

這些變更將可完全回溯相容。現有 API 已具備 語意稍有變化 (從每封郵件 64KiB 限制為 不受限),但由於這項限制已鬆散先前的限制 現有的 API 都會受到影響

安全性考量

這些變化對於安全性的影響微乎其微。增加的模式 變更為「第一級」狀態是利用 fuchsia.mem.Data 建立 沒有觀察到對安全性的負面影響這仍相當重要 但應確保實作方式在任何情況下都安全無虞。

這項設計也拓展了阻斷服務風險 與 FIDL 通訊協定之間的關聯在此之前,傳送 VMO 的攻擊向量 分配過多記憶體,導致接收器只能透過通訊協定存取 明確傳送了 fuchsia.mem.Data/fuchsia.mem.Buffer/zx.handle:VMO 包含型別。現在,凡是包含至少一個方法,且 未受限或半受限的酬載就會暴露在這項風險中。這就視為 目前可容忍受制於許多阻斷服務向量 。為解決問題而提供更全面的解決方案 這個設計的細節

這項設計引入一個額外的阻斷服務向量 檢查 ZX_INFO_VMO 的接收端。這麼做可讓 VMO 不會為了變更伺服器承諾的頁面而停止運作,導致伺服器停止運作 因此,使用 Kubernetes Engine 即可。我們判斷這類意外行為的風險很低 因為只有少數程式使用以呼叫器支援的 VMO 以注意力機制為基礎與上述原因類似,這個阻斷服務向量 直到未來設計可以導入更全面的解決方案。

隱私權注意事項

其中一項重要的隱私權考量是郵件寄件者「必須」確保 但針對每則 VMO 訊息使用新建立的 VMO這些 API 不得 在訊息之間重複使用 VMO,否則可能會導致資料外洩。繫結為 強制執行這些限制條件

測試

fidlc 的單元測試標準 FIDL 測試策略,以及 將擴充下游和繫結輸出內容,以配合大型訊息用途 用途

說明文件

FIDL 電匯格式規格需採用 內容更新,說明本文件採用的線路格式異動。

缺點、替代方案和未知

缺點

這種設計有許多缺點。雖然系統會裁定 未成年人,尤其是與不執行任何行動或執行 但還是值得一提的是

效能驟降

成效探索所示 使結果「懸崖」的 ZX_CHANNEL_MAX_MSG_BYTES 使用者開始支付「稅金」的截止點到 傳送大型訊息。具體來說,如果訊息大於 1 個位元組 64 KiB 的測溫和 翻譯為 64KiB 的訊息雖然這層懸崖不太理想,但相對來說 小,而且有可能透過日後的核心變更來演化。

阻斷服務

具備至少一個方法接受不受限或 與 記憶體:惡意攻擊者可能利用 值,msg_byte_countmessage_info 結構體 欄位內的值,並使用 也同樣是大型的 VMO接收方接著會強制分配 足以應付此酬載 惡意酬載的規模夠大

安全性考量中所述 上方列舉了,這確實會帶來極大風險 直到未來能找到更全面的解決方案。

處理溢位邊緣情況

這項設計無法完全消除 PEER_CLOSED 在執行階段因訊息意外過大而感到意外: 或是含有超過 64 個帳號代碼的大型訊息 仍會觸發錯誤狀態目前這種行為可以接受, 作者不知道在實務中使用這類酬載。這個極端案例 協助處理需求這個欄位中包含 reserved 欄位 message_info 結構體可確保未來會有彈性 處理溢位支援的設計

依情境調整的訊息屬性

byte_overflow 和旗標是第一個表示不同 不同傳輸端的輸出內容 (但靜態資料除外) 標記,取決於我們是否將靜態 FIDL 視為「傳輸」 不一定)。這會造成一些不確定性:只是檢查電匯的 FIDL 如果不知道傳送哪個傳輸郵件,可能就不再是交易郵件 足以處理訊息現在有「預先處理」步 依照標頭旗標和傳輸訊息 訊息傳送之後,我們會執行特殊程序來組合完整的訊息內容。 例如,無手能傳送 Zircon 管道溢位的訊息 傳輸現在會在其控制陣列中取得控制代碼,而 fdf 訊息 這些溢位現象

遭拒的替代方案

設計 墨西哥的 RFC。以下列出最有意思的提案。

提高 Zircon 訊息大小限制

大型郵件最迫切的需求在於 zx.channel 傳輸。 這個解決方案目前的郵件大小上限為 64KiB。有一個顯而易見的解決方案 您只需提高上限

但有幾個原因不適合使用。第一個原因是 有些困難這會因 ABI 打破核心而變得複雜 這類限額遷移作業並不簡單,因為需要謹慎管理 確保在提高限制之後編譯二進位檔不會意外 傳送的資料量大於已編譯的二進位檔,則提高其處理量後即可處理。

許多 FIDL 實作項目也會根據限製做出有用的假設。 部分繫結 (例如 Rust 的繫結) 採用「猜測和檢查」分配作業 接收訊息的策略他們會分配一個小型緩衝區,並嘗試 zx_channel_read_etc。如果系統呼叫因 ZX_ERR_BUFFER_TOO_SMALL 失敗, 會傳回實際的訊息大小。如此一來,繫結即可分配 適合大型緩衝區並重試

其他繫結 (例如適用於 C++ 的繫結) 只對風力發出注意 為收到的郵件配置 64KiB,避免可能會產生多個 Sy Ads 發出 100 回應,而代價較高。第二種策略無法擴充 任意大型郵件。

最後,使用 VMO 是經過充分測試的解決方案, 透過 fuchsia.mem.Datafuchsia.mem.Buffer 類型。對核心限制提高,不利於解決方案 提供更多潛在的未知資料

zx_vmar_map 取代 zx_vmo_read

針對目前設計進行最佳化時,系統會直接讀取 FIDL 編碼器 從 VMO 緩衝區使用 zx_vmar_map。這個問題有兩個問題 。

主要問題在於這個方法並不安全,否則 需要修改核心基元才能解決問題。但問題是 對應記憶體會造成訊息傳送者修改訊息的情況 進而建立 TOCTTOU 風險。讀取器可以嘗試直接從對應的 可能在沒有先複製的情況下可變動的 VMO,但即使防禦性副本 則很難以安全的方式進行。這些安全性作業 透過強制執行 VMO 的不變性 呼叫 zx_vmo_create_child 呼叫,但會產生額外的系統呼叫,最糟糕的情況 複製負擔

與記憶體對應效能有關的其他問題,以及 有線 C++ 繫結的小工具,例如決定記憶體的 則不適合使用這個選項

封包化

這個步驟的用意是擷取大型訊息 並分散在多封郵件上 每個區塊大小不超過 64KiB,在另一端進行組合。 交易郵件標頭中有一些接續標記 指出其預期會「更多資料」才會追蹤或追蹤這個引數包含 利用內建流量控制,對程式設計人員將來 ,在標準程式庫中持續顯示串流原始語言的內容

這個方法的缺點是,當某些情況下 訊息不容易分塊也複雜許多:當多個廣告為單一字詞時 執行緒正在傳送中,但部分訊息區塊的不完整陣列將停滯 需要在另一端重新組合的傳輸元件

請放心,這項策略會產生阻斷服務風險, 不會之後透過新的核心基元進行修正,或是日後新增 繫結的通訊協定:惡意或錯誤型用戶端可能會傳送 但卻無法傳送「結束」 封包。接收者被迫將所有其他封包保存在記憶體中 等待用戶端「預訂」潛在 在伺服器上分配無限量的記憶體。有很多方法可以 例如逾時和政策限制 透過 FIDL 重新實作 TCP。

明確溢位

本文件提議的設計僅列出 訊息傳送使用者只需定義自己的酬載 繫結作業會完成後續的程序

替代設計可讓使用者以宣告方式指定 VMO 分別用於每個酬載或每個酬載成員於 基本上,這樣只要修改 FIDL 語言, 「fuchsia.mem.Data」的拼字。

現有設計得取下效能提升和 API 的取捨 準確度較低,但一般來說是 值得的交換

僅允許值類型

此設計的早期版本提議只為 value 啟用 overflowing 類型。原因很簡單:目前完全沒有用到 而且單一 FIDL 訊息不太可能是資源類型 需要一次傳送超過 64 個帳號代碼,因此被認定為低 優先順序。

在設計這個解決方案的原型的過程中 fuchsia.component.resolution library,一個雜草 會發現映像檔某些方法已使用資料表來存放其酬載 比起取代方法批發,我們仍希望將表格擴充為 也會逐漸淘汰 fuchsia.mem.Data具體:

// Instead of adding a new method to support large messages, the preferred
// solution is to extend the existing table and keep the current method.
protocol Resolver {
  Resolve(struct {
    component_url string:MAX_COMPONENT_URL_LENGTH;
  }) -> (resource struct {
    component Component;
  }) error ResolverError;
};

type Component = resource table {
  // Existing fields - note the two uses of `fuchsia.mem.Data`.
  1: url string:MAX_COMPONENT_URL_LENGTH;
  2: decl fuchsia.mem.Data;
  3: package Package;
  4: config_values fuchsia.mem.Data;
  5: resolution_context Context;

  // Proposed additions for large message support.
  6: decl_new fuchsia.component.decl.Component;
  7: config_values_new fuchsia.component.config.ValuesData;
};

這些方法相當有趣: 酬載很龐大,且其中含有帳號代碼的實際運作情形 但是這並不是 fidlc 編譯器的名稱。從觀點來看 只是資源類型雖然我們可以想出一些學習方式 這個特定案例的編譯器則視為較簡單的判斷範圍 會處理大型訊息,直到更合適的核心原始物件

overflowing 修飾符

及早採用此設計,使用者就能在以下位置設定 overflowing 個值區: 定義其通訊協定方法的 FIDL,如下所示:

// Enumerates buckets for maximum zx.channel message sizes, in bytes.
type msg_size = flexible enum : uint64 {
  @default
  KB64 = 65536;    // 2^16
  KB256 = 262144;  // 2^18
  MB1 = 1048576;   // 2^20
  MB4 = 4194304;   // 2^22
  MB16 = 16777216; // 2^24
};

@transport("Channel")
protocol Foo {
  // Requests up to 1MiB are allowed, responses must still be less than or equal
  // to 64KiB.
  Bar overflowing (BarRequest):zx.msg_size.MB1
      -> (BarResponse) error uint32;
};

這種做法實際上相當複雜又巧妙 沒有明確的指引最終,大多數使用者 回答簡單的是非題 (「我需要大型郵件支援嗎?」); 而不是擔心機器學習的具體問題

另一個替代方法是考慮單獨考慮單獨使用 overflowing 關鍵字, 向使用者清楚說明 高效能 API成效差距最後決定不大 即使在任何情況下,仍能縮減 語言本身

日後可能的工作

有許多夥伴合作,但其實並非強制要求 此功能具有大型訊息功能,也是重要的輔助與最佳化 。

核心變更

核心變更的可能變更數量,但關鍵路徑不是 仍有助於減少系統呼叫輾轉現象,以及 並獲得最佳成效大型訊息的使用者提供 API 是 進行這些額外的最佳化措施後,請勿變更。大多數 fuchsia.mem.Data 的現有使用者不太容易受到延遲影響 (否則它們不會使用 fuchsia.mem.Data!),因此是 修改核心有助針對突發的突發用途提升效能 等到 FIDL 啟用大型郵件後才會更新。

一流訊息串

每當有大型訊息用途時 就會問問題 「在 FIDL 中實作第一級串流無法解決這個問題嗎?」目的地: 都可以回答這個情況,但 大量資料都可加以分類: 可分割性適用性

可組性是指能否分割相關資料 更重要的是,如果資料的接收端可以 建議只對子集進行研究本質上 在一方面輸入 T,以及 vector<T>array<T> 類型的資料,其中 您還是可以對清單部分檢視分頁清單 可分塊,但傳送以供排序的項目清單則不行。同樣地, 無法分塊: (任意) 部分的樹狀結構。

「附加性」意指資料傳送後能否遭到修改。 可附加 API 的典型範例為 Unix 管道:當資料傳輸時 讀取或讀取的內容 所加上的文字內容可在傳送後加入的資料 可附加元件。即使以清單形式呈現,傳送時即無法變更的資料, 而不是

清單 6:一個矩陣,說明所有人對資料的偏好大型資料處理策略 組合性和附加性可能組合。

大型資料處理策略
矩陣

這兩種差異在矩陣上合併, 妥善判斷哪些大型訊息或串流更適合。

若是靜態 blob (例如資料傾印、B 樹狀結構或大型 JSON 字串),使用者不會 無論是單一訊息,還是需要傳遞資訊 (例如 至少可能) 對 FIDL 而言過大 會有點意外複雜性 遠離他們擔憂的一分子在此情況下,使用者希望能夠 以雜亂無章的態度處理郵件 代表「跨越線索」將資料具體化為 而在程序各階段之間進行移轉並不合理。

針對可區塊的動態資料結構,例如一連串網路封包 是最顯而易見的選擇 (名稱就在這樣!)。使用者已完成 以便處理這種情況,編寫可處理設定程序的程式庫 然後在接收端乾淨地公開發布串流 看來適合接受頂級治療該平台也 具有強大的支援及程式設計人員熟悉的自然模式 FIDL 的語言具備繫結機制 (C++、Dart、Rust)。

如果有可區塊但大多數為靜態訊息,例如快照 列出與裝置連線的周邊裝置?方法很簡單 將這些模組分成多個區塊,以串流形式公開,但我們不明顯看出 有益:在部分 API 情況下,系統會公開這類資訊 作者看到分頁的標示是他們 感謝 FIDL 而非核心功能在此情況下,背景資料看起來非常多元 建議選擇「串流」或「大型訊息」

所有錯誤都知道:大型郵件只是工具箱中的一種功能 可能的方法。非常適合 FIDL 未來可能發展出一流的串流實作, 功能,而不是取代大型訊息所提供的功能。

有界限的通訊協定和彈性的信封大小限制

這種設計具有極大的阻斷服務風險, 一些通訊協定,尤其是在許多其他用戶端之間共用的通訊協定 可以避免的問題為此,我們也許會想為bounded 通訊協定,提供編譯時強制執行的通訊協定,確保所有方法都僅使用 受限類型:

// Please note that this syntax is very speculative!
bounded protocol SafeFromMemoryDoS {
  // The payload is bounded, so this method compiles.
  MySafeMethod(resource struct {
    a bool;
    b uint64;
    c array<float32, 4>;
    d string:32;
    e vector<zx.handle, 64>;
  });
};

這項設計所產生的其中一個後果,就是 FIDL 通訊協定作者面臨問題 「bifurcating」選擇:加入 bounded 會確保通訊協定盡可能安全 無界限的訊息導致阻斷服務,但會阻止該方法的 使用 tableflexible union 類型間接產生酬載。這是 不幸的是,提升效能與 ABI 相容性是 FIDL 語言。強迫使用者採用 ABI 穩定類型之後, 日後發展有效酬載的能力

其中一項可能的妥協,是針對 flexible 導入明確的大小限制 屏風版面配置。這提供了 ABI 相容性,因為彈性定義是 而會隨著時間的推移,對該型別的 大小上限:

// Please note that this syntax is very speculative!
@available(added=1)
type SizeLimitedTable = resource table {
  1: orig vector<zx.handle>:100;
  // Version 2 still compiles, as it contains <=4096 bytes AND <=1024 handles.
  @available(added=2)
  2: still_ok string:3000;
  // Version 3 fails to compile, as its maximum size is greater than 4096 bytes.
  @available(added=2)
  3: causes_compile_error string:1000;
}:<4096, 1024>; // Table MUST contain <=4096 bytes AND <=1024 handles.

此類大小限制可讓您使用「柔軟」靈活彈性:酬載 即使能隨著時間的推移而變更 針對首次定義酬載時可能增加的額度。

既有藝術品和參考資料

此提案開頭是 fuchsia.mem.Data,早於前。 fuchsia.mem.Bufferzx.handle:VMO 廣泛使用並支援 建立 fuchsia.git 程式碼集。這項決策基本上是「第一級」進化 這些經過充分測試的模式

前一個已捨棄的 RFC 說明與目前的 RFC 相似 使用 VMO 做為大型訊息的基礎傳輸機制

附錄 A:fuchsia.git 中 FIDL 酬載的範圍

下表顯示溢流之間的邊界分佈情形 (大於 64KiB) 以及截至 2022 年 8 月初。資料是透過 「一切」建立 fuchsia.git 的建構作業接著,系統會透過 一系列 jq 查詢。

清單 7:顯示各種酬載受限程度的測量頻率表格 這個值區的大小

邊界 / 訊息種類 標準 溢位 總計
無界限 3851 (76%) 45 (%) 3896 (77%)
半下限 530 (10%) 70 (1%) 600 (11%)
無限制 0 (0%) 602 (12%) 602 (12%)
總計 4381 (86%) 717 (14%) 5098 (100%)

  1. 您可能會好奇 封包化解決方案,比如 將 64KiB 訊息的傳送時間乘以 64,但不正確。 效能比較作業在電腦上產生的處理器快取效果 確保 <=1MiB 傳輸作業的執行速度,比 用於轉移超過 1 MiB 的裝置;會顯示在「凹口」中 商家資訊 2 中顯示的圖表 1 MiB 中唯一已啟用的有效比較項目 會直接在相同大小的訊息之間