Fuchsia 接口定义语言 (FIDL) 是一种用于描述 Fuchsia 程序所用进程间通信 (IPC) 协议的语言。FIDL 为提供方提供了一种简化的声明语法,用于将接口定义为协议。支持的数据类型包括整数、浮点数、布尔值、字符串和 句柄。 这些类型可以整理成更复杂的数组、向量、结构体、表和联合。
请考虑以下 Echo 接口的 FIDL 协议示例:
library fuchsia.examples;
const MAX_STRING_LENGTH uint64 = 32;
@discoverable
closed protocol Echo {
strict EchoString(struct {
value string:MAX_STRING_LENGTH;
}) -> (struct {
response string:MAX_STRING_LENGTH;
});
strict SendString(struct {
value string:MAX_STRING_LENGTH;
});
strict -> OnString(struct {
response string:MAX_STRING_LENGTH;
});
};
FIDL 协议描述了一组通过在渠道上发送消息来调用的方法。渠道消息本质上是异步的,发送者和接收者彼此独立运作。FIDL 方法引入了更高级别的语义,可在 FIDL 交易的客户端和服务器端实现更惯用的编程。
FIDL 支持以下方法类型:
- 双向方法:一种典型的接受可选参数的方法调用,其返回值类型在
->运算符之后定义。双向方法会一直阻塞,直到收到响应。在Echo示例中,EchoString()方法是双向方法。 - 单向方法:立即返回而不等待响应的异步方法调用。未声明返回值类型的方法被视为从客户端到服务器的单向方法。在
Echo示例中,SendString()方法是单向方法。 - 事件:必要时,服务器可以向客户端发送主动发送的消息,称为事件。事件在
->运算符的返回侧声明其方法名称。在Echo示例中,OnString()方法是一个事件。
创建 FIDL 库
FIDL 库将 FIDL 源文件组合在一起。库充当其所包含协议的命名空间,FIDL 源文件可以隐式访问同一库中的所有其他声明。FIDL 源文件必须导入来自其他库的所有声明。
Fuchsia 构建系统提供 fidl() 构建目标,用于将 FIDL 源文件编译为库。库目标的名称必须与每个源文件中的 library 声明一致。请参阅以下 fuchsia.examples 库的 BUILD.gn 示例:
# Import the fidl GN template.
import("//build/fidl/fidl.gni")
# Define a FIDL library target.
fidl("fuchsia.examples") {
# FIDL source files contained in library
sources = [
"echo.fidl",
]
}
在构建时,FIDL 编译器 (fidlc) 前端工具会验证库源文件并将其编译为 JSON 中间表示 (IR)。此 JSON IR 格式是 FIDL 绑定的基础。
生成 FIDL 绑定
组件通过称为 FIDL 绑定的生成代码来使用 FIDL 协议。绑定会将请求和响应编码和解码为 FIDL 消息,并通过底层 IPC 通道传输这些消息。特定于语言的绑定库为这些结构提供封装容器,以便与熟悉的编程惯用语保持一致。
客户端接口(有时称为代理)会在高级别函数调用和 FIDL 消息之间执行转换。在服务器端,绑定会处理传入的请求消息,并通过抽象接口将其传递给组件以供实现。
在构建时,fidlgen 后端工具会根据 fidlc 生成的 JSON IR 库为受支持的编程语言生成绑定。例如,fidlgen_rust 会根据 JSON IR 生成 Rust 绑定。
fidl() 库目标会为每种受支持的语言创建单独的绑定目标。由于 GN 的特性,除非将这些绑定作为依赖项包含在内,否则不会在构建时间生成它们。
请参阅以下示例 BUILD.gn 代码段,其中包含 fuchsia.examples 库的生成的绑定目标:
Rust
deps = [
"fidl/fuchsia.examples:fuchsia.examples_rust",
...
]
C++
deps = [
"fidl/fuchsia.examples:fuchsia.examples",
...
]
练习:Echo FIDL 库
在此部分中,您将定义一个名为 Echo 的新 FIDL 库,其中包含一个将字符串值返回给调用方的单一方法。
首先,为 FIDL 库目标创建新目录:
mkdir -p vendor/fuchsia-codelab/echo-fidl在新项目目录中创建以下文件和目录结构:
//vendor/fuchsia-codelab/echo-fidl
|- BUILD.gn
|- echo.fidl
添加一个名为 echo.fidl 且包含以下内容的新 FIDL 接口文件:
library fidl.examples.routing.echo;
const MAX_STRING_LENGTH uint64 = 64;
@discoverable
closed protocol Echo {
/// Returns the input.
strict EchoString(struct {
value string:<MAX_STRING_LENGTH, optional>;
}) -> (struct {
response string:<MAX_STRING_LENGTH, optional>;
});
};
EchoString 是一种双向方法,可接受可选(可为 null)字符串值,并返回相同的值。
添加一个包含以下内容的 BUILD.gn 文件,以声明库目标:
import("//build/fidl/fidl.gni")
fidl("echo") {
name = "fidl.examples.routing.echo"
sources = [ "echo.fidl" ]
enable_hlcpp = true
}
将库目标添加到 build 配置中:
Rust
fx set workstation_eng.x64 --with vendor/fuchsia-codelab/echo-fidl:echo_rustC++
fx set workstation_eng.x64 --with vendor/fuchsia-codelab/echo-fidl:echo_hlcpp检查 FIDL 绑定
fidl() GN 目标会编译 FIDL 接口并生成额外的 build 目标,以提供各种语言的绑定。如需检查绑定,您必须编译各个目标。
编译 fidl.examples.routing.echo 绑定:
Rust
fx build vendor/fuchsia-codelab/echo-fidl:echo_rustC++
fx build vendor/fuchsia-codelab/echo-fidl:echo_hlcpp使用 GN 找到目标的生成的源文件,并在编辑器中打开这些文件:
Rust
fx gn desc out/default/ vendor/fuchsia-codelab/echo-fidl:echo_rust.actual sourcesC++
fx gn desc out/default/ vendor/fuchsia-codelab/echo-fidl:echo_hlcpp sources浏览这些文件的内容。下面总结了一些关键的生成接口:
Rust
| 接口 | 说明 |
|---|---|
EchoMarker
|
用于打开代理并为给定协议请求流。 |
EchoProxy
|
将协议方法转换为通过 IPC 通道发送的 FIDL 请求消息的异步客户端。 |
EchoSynchronousProxy
|
将协议方法转换为通过 IPC 通道发送的 FIDL 请求消息的同步客户端。 |
EchoRequest
|
用于处理每个协议方法的传入请求的结构化类型。 |
EchoRequestStream
|
用于处理通过 IPC 通道传入的 FIDL 请求消息的流。 |
EchoEchoStringResponder
|
回调,用于将每个代理请求的返回值作为 FIDL 响应消息发送。 |
C++
| 接口 | 说明 |
|---|---|
EchoPtr
|
将协议方法转换为通过 IPC 通道发送的 FIDL 请求消息的异步客户端。 |
EchoSyncPtr
|
将协议方法转换为通过 IPC 通道发送的 FIDL 请求消息的同步客户端。 |
Echo
|
用于服务器组件的抽象类,可用于替换和处理传入的 FIDL 请求。 |
EchoStringCallback
|
回调,用于将每个请求的返回值作为 FIDL 响应消息发送。 |