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 源文件必须import其他库中的所有声明。
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 库
在本部分中,您将定义一个新的 FIDL 库,其中包含一个名为 Echo
的协议,该协议包含一个方法,用于将字符串值返回给调用方。
首先,为 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_rust
C++
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_rust
C++
fx build vendor/fuchsia-codelab/echo-fidl:echo_hlcpp
使用 GN 查找为目标生成的源文件,并在编辑器中打开它们:
Rust
fx gn desc out/default/ vendor/fuchsia-codelab/echo-fidl:echo_rust.actual sources
C++
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 响应消息发送。 |