如要進一步瞭解 FIDL 的整體用途、目標和需求,請參閱概念總覽。
核心概念
訊息
FIDL 訊息是一組資料。
訊息是一種連續結構,包含單一「行內主要物件」,後面加上零個或多個「外線次要物件」。
物件會以遍歷順序儲存,並受邊框間距規範。
主要和次要物件
第一個物件稱為主要物件。這是固定大小的結構,其類型和大小可以從背景資訊得知。讀取訊息時,您需要知道應讀取的類型,亦即格式不是自述式。執行讀取作業的情境應避免造成混淆。舉例來說,如果訊息作為處理序間通訊 (IPC) 的一部分 (請參閱交易訊息標頭),則背景資訊會由標頭中包含的資料完整指定 (特別是序線可讓接收者瞭解預期類型)。如果是讀取靜態資料,沒有對等的描述元,但假設編碼器和解碼器都知道要編碼或解碼的類型 (例如,這項資訊會編譯至編碼器和解碼器使用的個別程式庫中)。
如果需要其他變數大小或選用資料,主要物件可能會參照「次要物件」 (例如字串、向量、聯集等)。
次要物件會以遍歷順序儲存,並由「外移」儲存。
主要和次要物件皆對齊 8 位元組,而且儲存時不會有間隔 (除了校正所需物件之外)。
主要物件及其次要物件稱為「訊息」。
交易訊息
交易 FIDL 訊息 (交易訊息) 用於在應用程式之間傳送資料。
「交易訊息」一節說明交易訊息是如何由標頭訊息構成,可以視需要加上主體訊息。
遍歷順序
訊息的「週遊順序」是由其中所有物件的遞迴深度優先步驟所決定,取決於透過參照鏈取得該訊息。
請採用下方結構:
type Cart = struct {
items vector<Item>;
};
type Item = struct {
product Product;
quantity uint32;
};
type Product = struct {
sku string;
name string;
description string:optional;
price uint32;
};
Cart
訊息的深度優先週遊順序是由下列虛擬程式碼定義:
visit Cart:
for each Item in Cart.items vector data:
visit Item.product:
visit Product.sku
visit Product.name
visit Product.description
visit Product.price
visit Item.quantity
雙表單:編碼與解碼
相同的訊息內容可以使用以下兩種形式表示:編碼和解碼。兩者的大小和整體版面配置相同,但兩者的指標 (記憶體位址) 或處理 (功能) 表示法不同。
FIDL 在記憶體中能編碼及解碼訊息。
訊息編碼是標準格式,也就是說,特定訊息只有一種編碼。
已編碼的訊息
編碼訊息已準備好轉移至其他程序:不含指標 (記憶體位址) 或處理 (功能)。
在編碼期間...
- 訊息中的所有子物件指標都會替換成標記,指出參照項目是否存在。
- 訊息中的所有帳號代碼都會擷取到相關聯的處理向量,並替換成指出參照項目是否存在的標記。
接著,系統就可以將產生的編碼訊息和處理向量使用 zx_channel_write() 或類似的 IPC 機制傳送至另一個程序。這類 IPC 還有其他限制。請參閱「交易訊息」。
解碼後的訊息
解碼訊息已準備好用於程序位址空間內:其中可能包含指標 (記憶體位址) 或處理 (功能)。
在解碼期間:
- 訊息中的所有子物件指標都會使用經過編碼的「存在」及「不存在」標記重新建構。
- 訊息中的所有控點都會使用編碼的目前及不存在的標記,從相關聯的處理向量還原。
現在可以直接從記憶體使用產生的解碼訊息。
內嵌物件
物件也可能含有內嵌物件,這些物件在所屬物件的主體中匯總,例如內嵌結構體和固定大小的結構體陣列。
範例
在以下範例中,Region
結構包含 Rect
結構的向量,每個 Rect
包含兩個 Point
。每個 Point
都包含一個 x
和 y
值。
type Region = struct {
rects vector<Rect>;
};
type Rect = struct {
top_left Point;
bottom_right Point;
};
type Point = struct {
x uint32;
y uint32;
};
以周遊順序檢查物件意味著我們從 Region
結構開始,也就是主要物件。
rects
成員是 vector
,因此其內容會儲存在非行狀態。這表示 vector
內容緊接在 Region
物件之後。
每個 Rect
結構包含兩個 Point
,由內嵌儲存 (因為其數量固定),而 Point
的每個原始資料類型 (x
和 y
) 也都是內嵌儲存。原因也相同;成員類型有固定的數目。
當從屬物件的大小固定時,我們會使用「內嵌」儲存空間,若其變數是「非行」 (包括黑邊的結構體),我們會使用「內外」儲存空間。
類型詳細資料
本節將說明所有 FIDL 物件的編碼方式。
基本
- 以Litle-endian 格式儲存的值。
- 採用自然對齊。
- 每個 m 位元組原始儲存在 m 位元組邊界上。
- 非選填。
支援下列原始類型:
類別 | 類型 |
---|---|
布林值 | bool |
帶號整數 | int8 、int16 、int32 、int64 |
非帶號整數 | uint8 、uint16 、uint32 、uint64 |
IEEE 754 浮點 | float32 、float64 |
字串 | (非原始,請參閱字串) |
數字類型會加上其大小後置字串。
布林類型 bool
會儲存為單一位元組,且只有值 0 或 1。
所有浮點值都代表有效的 IEEE 754 位元模式。
列舉和位元
位元欄位和列舉會以基礎原始類型 (例如uint32
).
帳號代碼
帳號代碼是 32 位元整數,但經過特殊處理。對傳輸編碼進行編碼時,帳號的傳輸中表示法會替換為顯示及不存在的指標,且控點本身會儲存在獨立的控點向量中。解碼時,帳號代碼出現狀態指示會替換為零 (如果沒有) 或有效的帳號代碼 (如有)。
控制代碼「值」本身「不會」從一個應用程式轉移至另一個應用程式。
在此情況下,帳號代碼就像指標,會參照每個應用程式的專屬結構定義。控點會從一個應用程式的結構定義移至另一個應用程式的結構定義。
值 0 可用來表示沒有選用的帳號代碼1。
如需透過 FIDL 轉移帳號代碼的詳細範例,請參閱「帳號代碼生命週期」一文。
匯總物件
匯總物件可做為其他物件的容器。視使用者類型而定,他們可能會在資料外儲存這些資料,
陣列
- 修正同質元素的長度序列。
- 採用其元素的自然對齊方式。
- 陣列的對齊方式與其元素的對齊方式相同。
- 每個後續的元素都會對齊元素的對齊邊界。
- 陣列的步長等於元素大小 (包括滿足元素對齊限制所需的邊框間距)。
- 絕非選用。
- 布林值陣列沒有特殊案例。每個布林值元素會照常使用一個位元組。
陣列會註明:
array<T, N>
:其中 T 可以是任何 FIDL 類型 (包括陣列),而「N」是陣列中的元素數量。注意:陣列的大小不得超過 232-1。詳情請參閱 RFC-0059。
向量
- 相同元素的變數長度序列。
- 可能是選用設定;缺少向量和空白向量皆不同。
- 可以指定大小上限,例如最多可指定 40 個元素向量
vector<T>:40
。 - 會儲存為 16 位元組記錄,其中包含:
size
:64 位元無正負號的元素數 注意:向量大小不得超過 232-1。詳情請參閱 RFC-0059。data
:64 位元狀態指標或指向行外元素資料的指標
- 編碼進行轉移時,
data
表示內容存在:0
:缺少向量UINTPTR_MAX
:有向量,資料為下一個外線物件
- 解碼為消耗時,
data
是內容的指標:0
:缺少向量<valid pointer>
:有向量,資料位於指定的記憶體位址
- 布林值類的向量並沒有特殊規定。每個布林值元素會照常使用一個位元組。
向量表示如下:
vector<T>
:必要元素類型 T 的向量 (如果沒有data
,就會發生驗證錯誤)vector<T>:optional
:選用元素類型的 T 向量vector<T>:N
、vector<T>:<N, optional>
:長度上限為 N 個元素的向量
T 可以是任何 FIDL 類型。
字串
字串會以 uint8
個位元組的形式實作,並設下限制,也就是位元組「必須」採用有效的 UTF-8。
建築
結構包含一系列型別欄位。
結構會在內部設有邊框間距,讓所有成員都能符合所有成員的最大對齊要求。在外部,結構是在 8 位元組邊界對齊,因此可能包含符合該要求的最終邊框間距。
以下是幾個範例。
包含 int32 和 int8 欄位的結構具有 4 個位元組的對齊方式 (因為 int32),大小為 8 個位元組 (int8 後有 3 個位元組的邊框間距):
具有 bool 和 string 欄位的結構具有 8 個位元組的對齊方式 (由於使用字串),且大小為 24 個位元組 (bool 後方有 7 個邊框間距):
具有 bool 和兩個 uint8 欄位的結構體已完成 1 位元組,且大小為 3 個位元組 (沒有邊框間距!):
結構可以是:
- 空白 — 沒有欄位。這類結構的大小為 1 位元組,其對齊距離 1 位元組,並且等於包含
uint8
值為 0 的結構。 - 必要時,結構內容將以內嵌方式儲存。
- 選用:這個結構的內容將離線儲存,並可透過間接參照存取。
結構物的儲存方式取決於在參照點是否已加上方塊。
- 非盒子結構:
- 內容會以內嵌方式儲存在其所含類型中,因此可有效地建構匯總結構。
- 結構版面配置在內嵌時不會變更;其欄位不會重新封裝,以填補其容器中的缺口。
- 盒裝結構:
- 內容不會動態儲存,並可透過間接參照存取。
- 在編碼進行傳輸編碼時,已儲存的參照會指出具有結構:
0
:缺少參照UINTPTR_MAX
:有參照,結構內容是下一個外部物件- 解碼以供使用時,儲存的參照會是指標:
0
:缺少參照<valid pointer>
:有參照,結構內容位於指定的記憶體位址
結構體會以宣告的名稱 (例如 Circle
) 表示,可以盒子:
Point
:必填的Point
box<Color>
:盒裝,一律選用Color
以下範例說明:
- 結構版面配置 (排序、封裝與對齊)
- 必要結構 (
Point
) - 盒裝 (
Color
)
type Circle = struct {
filled bool;
center CirclePoint; // CirclePoint will be stored in-line
radius float32;
color box<Color>; // Color will be stored out-of-line
dashed bool;
};
type CirclePoint = struct {
x float32;
y float32;
};
type Color = struct {
r float32;
g float32;
b float32;
};
Color
內容會填充至 8 位元組次要物件對齊界線。仔細瀏覽版面配置:
- 第一位成員
filled bool
佔用一個位元組,但由於下一個成員有 4 位元組的對齊要求,因此需要三個邊框間距。 center CirclePoint
成員是必要結構的範例。因此,其內容 (x
和y
32 位元浮點值) 會內嵌,且整個內容會耗用 8 個位元組。radius
是 32 位元的項目,需要 4 位元組對齊。由於下一個可用位置已位於 4 位元組對齊邊界,因此不需要填充。color box<Color>
成員是方塊結構的範例。color
資料不一定存在,因此最有效的處理方式,是將指標保留在結構上做為內嵌資料。如此一來,如果color
成員確實存在,指標會指向其資料 (如果採用已編碼的格式,則代表「存在」),而資料本身儲存在去外的位置 (Circle
結構的資料之後)。如果沒有color
成員,指標則為NULL
(如果採用編碼格式,則會儲存 0 以表示「不存在」)。dashed bool
不需要任何特殊對齊,因此會在下一個使用。不過,我們已到達物件的結尾,且所有物件都必須對齊 8 位元組。也就是說,我們需要額外的 7 個位元組的邊框間距。color
的過時資料採用Circle
資料結構,其中包含三個 32 位元的float
值 (r
、g
和b
);它們需要 4 位元組對齊,因此可以相鄰而不加上邊框間距。不過,就像Circle
物件的情況一樣,我們要求物件本身必須與 8 位元組對齊,因此需要 4 個位元組的邊框間距。
整體而言,這個結構需要 48 個位元組。
不過,只要將 dashed bool
移到 filled bool
之後,即可大幅節省儲存空間2:
- 這兩個
bool
值會在原本浪費的空間內「封裝」。 - 邊框間距會縮減為兩個位元組,因此適合加入 16 位元值或更多
bool
或 8 位元整數。 - 請注意,
Color
方塊之後不需要邊框間距;所有內容都會在 8 位元組邊界上完美對齊。
結構目前需要 40 個位元組。
信封
信封是資料的容器,供資料表和聯集在內部使用。不會向 FIDL 語言公開。採用固定 8 位元組格式。
信封標頭全為零,稱為「零信封」。用來表示缺少的信封。否則,信封會存在,且其中的 0 個標記會指示資料是以內嵌或外部的方式儲存:
- 如果設定了位元 0,則會使用內嵌表示法。
- 如果未設定位元 0,就會使用非線條表示法。
酬載大小必須小於 4 個位元組,才能設定位元 0。只有在信封是零信封或酬載大小超過 4 個位元組時,位元 0 才能取消設定。
使用 num_bytes
和 num_handles
即可略過未知的信封內容。
num_bytes
一律為 8 的倍數,因為跨行物件會對齊 8 位元組。
桌子
- 由元素數量和指標組成的記錄類型。
- 指標指向信封陣列,每個信封都包含一個元素。
- 每個元素都與序數相關聯。
- 序數會循序漸進,避免產生空白信封,因此不建議使用。
資料表會依宣告的名稱表示 (例如Value) 的值,且不一定是選用項目:
Value
:必填的Value
以下範例顯示如何根據欄位配置資料表。
type Value = table {
1: command int16;
2: data Circle;
3: offset float64;
};
工會
- 由序數和信封組成的記錄類型。
- 序數表示成員選取,以 uint64 表示。
- 每個元素都與使用者指定的序數相關聯。
- 序數依序為進行。與資料表不同的是,序數的間差不會產生傳輸格式空間成本。
- 缺少選用的聯集會以
0
序數和零信封表示。 - 不允許空白聯集。
聯集會顯示其宣告的名稱 (例如 Value
) 和選擇性性:
Value
:必填的Value
Value:optional
:選用Value
以下範例說明如何根據欄位配置聯集。
type UnionValue = strict union {
1: command int16;
2: data Circle;
3: offset float64;
};
交易訊息
交易訊息一律包含「標頭」和選用的「主體」。
如上文定義,標頭和主體都是 FIDL 訊息;即資料集合。
標頭的格式如下:
zx_txid_t txid
,交易 ID (32 位元)- 具有高位元組合的
txid
已保留供 zx_channel_call() 使用 - 未設定高位元的
txid
已保留供使用者空間使用 txid
的0
值會保留給不需要其他端回應的訊息。注意:如要進一步瞭解txid
分配,請參閱 zx_channel_call() 的說明。
- 具有高位元組合的
uint8[3] flags
,「不得」透過繫結檢查。這些標記可用於啟用線段格式的軟轉換度。如需目前標記定義的說明,請參閱標頭旗標。uint8 magic number
,決定兩種線路格式是否相容。uint64 ordinal
- 零序數無效。
- 最大位元集的序數保留給控制訊息和日後的擴充。
- 沒有最大位元集的序數表示方法呼叫和回應。
交易訊息分為三種:
- 方法
- 方法回應,
- 事件要求
在接下來的幾個範例中,我們會使用以下介面:
type DivisionError = strict enum : uint32 {
DIVIDE_BY_ZERO = 1;
};
protocol Calculator {
Add(struct {
a int32;
b int32;
}) -> (struct {
sum int32;
});
Divide(struct {
dividend int32;
divisor int32;
}) -> (struct {
quotient int32;
remainder int32;
}) error DivisionError;
Clear();
-> OnError(struct {
status_code uint32;
});
};
Add() 和 Divide() 方法說明方法要求 (從用戶端傳送至伺服器),以及方法回應 (從伺服器傳回用戶端)。
Clear() 方法是沒有主體的方法要求示例。
不該認為物件具有「空白」的主體,因為這樣可能在 body 後方存在「主體」body。在 Clear(),沒有 body 的情況下,只有 header。
方法要求訊息
介面的用戶端會將方法要求訊息傳送至伺服器,以便叫用方法。
方法回應訊息
伺服器會傳送方法回應訊息給用戶端,指出方法叫用已完成,並提供結果 (可能為空白) 的結果。
只有定義為提供 (可能為空白) 的雙向方法要求才會產生方法回應。單向方法要求不得產生方法回應。
方法回應訊息可提供與先前方法要求相關聯的結果。訊息內文包含方法結果,就如同它們在 struct 中封裝一樣。
在這裡,我們可以看到 912 / 43 的答案是 21,其餘則是 9。
請注意 1
的 txid
值,用來識別交易。2
的 ordinal
值代表方法 — 在本例中為 Divide() 方法。
在下方,123 + 456
是 579
。這裡的 txid
值現在是 2
,這只是指派給交易的下一個交易編號。ordinal
為 1
,表示 Add(),請注意,結果需要 4 個位元組的邊框間距,才能讓 body 物件的大小為 8 個位元組的倍數。
最後,Clear() 方法與 Add() 和 Divide() 不同,兩個重要部分不同:
* 它沒有主體 (也就是說,僅包含 header),且
* 並未從介面發出回應 (txid
為零)。
事件要求
Calculator
中的 OnError() 事件就是一個事件的範例。
伺服器會將主動事件要求傳送至用戶端,以指出發生非同步事件 (如通訊協定宣告所述)。
在 Calculator
範例中,我們可以假設嘗試除以零,會導致 OnError() 事件在連線關閉前傳送「除以零」狀態碼。如此一來,用戶端就能區分因錯誤而關閉的連線,而非其他原因 (例如計算工具程序異常終止)。
請注意,txid
為零 (表示這並非交易的一部分),而 ordinal
是 4
(表示 OnError() 方法)。
body 包含事件引數,就像封裝在 struct 中一樣,就像方法結果訊息一樣。請注意,主體會填補,維持 8 位元組對齊。
Epitaph (控制訊息序數 0xFFFFFFFFFFFFFF)
1 詩人為 (txid 0) 與 0xFFFFFFFFFFFFFFFF 相除的事件。伺服器可能會在關閉連線前,傳送第一個訊息做為最後一個訊息,以指出連線關閉的原因。對話結束後,就不能再透過該連線傳送其他訊息。Epitaph 不會從用戶端傳送至伺服器。
橢圓的傳輸表示法等同這個 FIDL:
fidl
struct {
error zx.Status;
};
Epitaph 日後可能會在 FIDL 中正式定義。
詳細說明
大小和對齊方式
sizeof(T)
代表 T 類型物件的大小 (以位元組為單位)。
alignof(T)
表示儲存 T 類型的物件時,是以位元組為單位的對齊係數。
FIDL 原始類型會以訊息大小的倍數 (以位元組為單位) 的偏移儲存在訊息中的偏移量。因此,如果是原始 T,alignof(T) ==
sizeof(T)
。這就是所謂的「自然對齊」。它具有滿足現代 CPU 架構一般對齊要求的絕佳屬性。
FIDL 複雜類型 (例如結構和陣列) 會以訊息中的偏移量儲存,該值是所有欄位最大對齊係數的倍數。因此,如果是複雜的 T 類型,在 T 中的所有 F 欄位則為 alignof(T) ==
max(alignof(F:T))
。該元素具有滿足一般 C 結構封裝要求的良好屬性 (可在產生的程式碼中使用封裝屬性強制執行)。複雜類型的大小是指以適當對齊方式儲存成員所需的位元組總數,以及與類型對齊係數的邊框間距。
FIDL 主要和次要物件會在訊息內以 8 位元組偏移的方式對齊,無論內容為何。FIDL 訊息的主要物件會從位移 0 開始。次要物件是訊息中唯一可能的參照指標,一律從偏移值為 8 的倍數開始。(因此訊息點與偏移量為 8 的倍數)。
FIDL 內嵌物件 (主要或次要物件內嵌的複雜類型) 會根據其類型對齊。而不會強制調整為 8 位元組對齊。
類型
注意:
- 「N」表示元素數量,無論是否明確指出 (如
array<T, N>
中,含有 N 類型的 N 元素陣列) 或隱含 (包含 7 個元素的table
包含N=7
)。 - 行外大小一律會填充至 8 個位元組。我們會在下方指出內容大小 (不含邊框間距)。
- 以下
vector
項目中的sizeof(T)
為
in_line_sizeof(T) + out_of_line_sizeof(T)
。 - 以下
table
項目中的 M 是目前欄位的最大序數。 - 在下方的
struct
項目中,邊框間距是指必要的邊框間距,可讓struct
對齊最寬的元素。舉例來說,struct{uint32;uint8}
的邊框間距有 3 個位元組,與對齊至 8 個位元組邊界的邊框間距不同。
類型 | 大小 (內嵌) | 尺寸 (外框) | 對齊 |
---|---|---|---|
bool |
1 | 0 | 1 |
int8 、uint8 |
1 | 0 | 1 |
int16 、uint16 |
2 | 0 | 2 |
int32 ,uint32 ,float32 |
4 | 0 | 4 |
int64 ,uint64 ,float64 |
8 | 0 | 8 |
enum 、bits |
(基礎類型) | 0 | (基礎類型) |
handle 等人 |
4 | 0 | 4 |
array<T, N> |
sizeof(T) * N | 0 | alignof(T) |
vector 等人 |
16 | N * 尺寸(T) | 8 |
struct |
Total(sizeof(fields)) + padding | 0 | 8 |
box<struct> |
8 | Total(sizeof(fields)) + padding | 8 |
envelope |
8 | sizeof(欄位) | 8 |
table |
16 | M * sizeof(信封) +Sum(aligned_to_8(存在欄位)) | 8 |
union 、union:optional |
16 | sizeof(已選取的變化版本) | 8 |
上方的 handle
項目是指控點的所有變種版本,特別是 handle
、handle:optional
、handle:H
、handle:<H, optional>
、client_end:Protocol
、client_end:<Protocol, optional>
、server_end:Protocol
和 server_end:<Protocol, optional>
。
同樣地,上述 vector
項目參照向量的所有變種版本,特別是 vector<T>
、vector<T>:optional
、vector<T>:N
、vector<T>:<N, optional>
、string
、string:optional
、string:N
和 string:<N, optional>
。
邊框間距
訊息建立者必須用零來填補所有對齊的邊框間距。
訊息的取用端必須確認邊框間距包含零 (如果沒有,則會產生錯誤)。
週期深度上限
FIDL 向量、選用結構、資料表和聯集可以建構遞迴訊息。如未勾選,處理過度深的訊息可能會導致資源耗盡,或是未偵測到無限迴圈。
基於安全考量,所有 FIDL 訊息的遞迴深度上限為 32 級。FIDL 編碼器、解碼器或驗證工具「必須」在訊息驗證期間追蹤目前的週期深度,以強制執行這項限制。
遞迴深度的正式定義:
- FIDL 訊息的內嵌物件已定義為遞迴深度 0。
- 每次間接週遊,透過指標或信封,都會使遞迴深度增加 1。
如果遞迴深度超過 32,就必須終止作業並引發錯誤。
比方說:
type InlineObject = struct {
content_a string;
vector vector<OutOfLineStructAtLevel1>;
table TableInlineAtLevel0;
};
type OutOfLineStructAtLevel1 = struct {
content_b string;
};
type TableInlineAtLevel0 = table {
1: content_c string;
};
對 InlineObject
的執行個體進行編碼時,會有相應的遞迴深度:
content_a
的位元組位於 1 的遞迴深度。也就是說,content_a
字串標頭內嵌在InlineObject
結構中,而位元組位於可透過指標間接存取的外行物件中。content_b
的位元組位於 2 的遞迴深度 2. 即vector
標頭內嵌在InlineObject
結構中,OutOfLineStructAtLevel1
結構為遞迴深度 1,content_b
字串標頭內嵌於OutOfLineStructAtLevel1
內,而位元組位於從深度 1 從深度 2 經由指標間接存取的外線物件。content_c
的位元組位於 3 的遞迴深度,即table
標頭內嵌在InlineObject
結構中;資料表信封深度為 1,指向深度為 2 的content_c
字串標頭,位元組則位於外部物件,可透過指標間接存取,因此深度為 3。
驗證
訊息驗證的目的是及早發現傳輸格式錯誤,以免引發安全性或穩定性問題。
您必須進行訊息驗證,才能將來自對等點的訊息解碼,以免錯誤的資料在服務進入點之外傳播。
對於要傳送至對等點的訊息進行編碼,訊息驗證是選用步驟,以協助本地化違反完整性限制。
為了將執行階段的負擔降至最低,通常應透過單一傳遞訊息編碼或解碼程序進行驗證,這樣只需進行一次週遊。由於訊息是採用深度優先週遊順序編碼,因此週遊會顯示良好的記憶體位置,因此應該相當有效率。
對於簡單的訊息,驗證可能非常簡單,只有少數幾個大小檢查。雖然我們建議程式設計師依賴 FIDL 繫結程式庫來驗證訊息,但如有需要,也可以手動進行驗證。
符合標準的 FIDL 繫結必須檢查下列所有完整性限制:
- 訊息的總大小 (包括其所有外線子物件) 完全等於包含它的緩衝區總大小。所有子物件都會納入考量。
- 訊息參照的控點總數等於控制點資料表的總大小。所有帳號代碼都會納入考量。
- 未超過複雜物件的遞迴深度上限。
- 所有列舉值都在其定義的範圍內。
- 所有聯集標記值都在定義範圍內。
- 僅限編碼:
- 週遊期間遇到的所有子物件指標都完全是指應顯示子物件的下一個緩衝區位置。做為聯合發布項目時,指標一律不會參照緩衝區以外的位置。
- 僅限解碼:
- 參照子物件目前和不存在的所有標記,都只包含 0 或 UINTPTR_MAX 值。
- 所有目前和未存在的標記都只會保留 0 或 UINT32_MAX 值。
標頭標記
Flags[0]
位元 | 目前用量 | 過往用量 |
---|---|---|
7 (MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 指出是否使用 v2 傳輸格式 (RFC-0114) | |
0 | 未使用 | 指出靜態聯集是否應以 xunions 編碼 (RFC-0061) |
Flags[1]
位元 | 目前用量 | 過往用量 |
---|---|---|
7 (MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 未使用 | |
0 | 未使用 |
Flags[2]
位元 | 目前用量 | 過往用量 |
---|---|---|
7 (MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 未使用 | |
0 | 未使用 |
-
定義零控點表示「沒有控點」,表示可以將線路格式結構預設為全部零,這樣是安全的做法。零也是
ZX_HANDLE_INVALID
常數的值。↩ -
如要進一步瞭解相關主題,請參閱「The 失落的藝術包裝」。↩