aidl使用_FIDL的入门级使用

FIDL(Fuchsia Interface Definition Language)是fuchsia系统上的远程调用机制, 相当于android上的基于binder的AIDL。

fuchsia里很多设计和android,chrome os有相似性, 可以类比学习。

FIDL的主要任务是允许客户端用不同的语言实现 和 服务端交互,底层数据传递时依赖zircon的IPC机制channel。并且通过自动生成代码来简化开发工作。

它包含四个部分:

  • FIDL的数据格式,远程函数的调用涉及两个进程之间的参数传递和返回值接收,参数和返回值可以使基本数据类型也可以是对象,所以怎么序列化和反序列化
  • FIDL语言: 编写.fidl文件,定义远程接口,包括 接口的函数名,传输的参数和返回值。
  • FIDL编译器:对fidl文件进行编译,生成代码
  • FIDL binding:运行时的库,提供FIDL的操作API。支持不同的编程语言有c++/go/rust

我们开发者需要掌握的是 编写FIDL语言保存为.fidl文件,以及熟悉FIDL binding使用

阅读源码中的FIDL实例

参考官方文档 FIDL tutorials,以及源码树里实例, 源码位置比较散,最开始看有点晕。

examples/fidl目录下有部分代码

garnet/examples/fidl下也有相关代码,还涉及到不同语言,不同层次的fidl使用

把这部分所有代码都浏览一遍,最终以garnetexamplesfidl下的 echo为例分析.

实例代码分析

包括编译脚本BUILD.gn,fidl文件,客户端,服务端实例代码. 分别位于

  • garnetexamplesfidlservicesecho.test.fidl : fidl文件,定义远程调用的接口函数EchoString,参数是string,返回值是string

  • garnetexamplesfidlecho_client_cpp: 客户端代码
int 
  • 其中EchoClientApp封装
class 
  • garnetexamplesfidlecho_server_cpp: 服务端代码
int 
  • 编译脚本BUILD.gn
    fidl的编译garnetexamplesfidlservicesBUILD.gn
import("//build/fidl/fidl.gni")
fidl("echo") {
 # TODO(fxb/35879): Remove lint exclusions by fixing known FIDL lint violations in this target
 # 免去lint检查中 string参数长度限制
  excluded_checks = [ "string-bounds-not-specified" ]
  name = "fidl.examples.echo"
  sources = [ "echo.test.fidl" ]
  fuzzers = [
    {
      protocol = "fidl.examples.echo.Echo"
    },
  ]
}
service的编译以及注释,文件在garnetexamplesfidlecho_service_cpp
import("//build/test/test_package.gni")
import("//build/testing/environments.gni")
​
source_set("lib") { #定义lib模块
  sources = [ # 源文件
 "echo_server_app.cc",
 "echo_server_app.h",
  ]
​
  public_deps = [ # 依赖sdk中的fidl和sys模块, 以及自定义的garnetexamplesfidlservicesecho.test.fidl
 "//garnet/examples/fidl/services:echo",
 "//sdk/lib/fidl/cpp",
 "//sdk/lib/sys/cpp",
  ]
}
​
executable("bin") { #可执行文件
  output_name = "echo_server_cpp"
 # 源文件
  sources = [ "echo_server.cc" ]
 # 依赖的系统库 和 上面定义的lib模块
  deps = [
 ":lib",
 "//zircon/public/lib/async-default",
 "//zircon/public/lib/async-loop-cpp",
 "//zircon/public/lib/async-loop-default",
  ]
}
​
package("echo_server_cpp") {# 包
  deps = [ ":bin" ]# 依赖上面的可执行文件bin
  binaries = [# 可执行文件
    {
      name = "echo_server_cpp"
      dest = "echo_server"
    },
  ]
​
  meta = [# 运行时配置文件
    {
      path = rebase_path("../meta/echo_server.cmx")
      dest = "echo_server_cpp.cmx"
    },
  ]
}
  • 客户端的编译脚本在文件在garnetexamplesfidlecho_client_cpp
import("//build/package.gni")
​
source_set("lib") {#定义lib库
  sources = [
 "echo_client_app.cc",
 "echo_client_app.h",
  ]
​
  public_deps = [ 
 # 依赖于自定义的fild文件garnetexamplesfidlservicesecho.test.fidl, 以及sdk中fidl和sys模块
 "//garnet/examples/fidl/services:echo",
 "//sdk/lib/fidl/cpp",
 "//sdk/lib/sys/cpp",
  ]
}
​
executable("bin") { # 定义要编译的二进制
  output_name = "echo_client_cpp"
​
  sources = [ "echo_client.cc" ] # 源文件
​
  deps = [ # 依赖于本文件中的lib库, 自定义的fild文件echo.test.fidl,以及sdk中的fidl,sys模块,以及zircon中的异步事件库
 ":lib",
 "//garnet/examples/fidl/services:echo",
 "//sdk/lib/fidl/cpp",
 "//sdk/lib/sys/cpp",
 "//zircon/public/lib/async-default",
 "//zircon/public/lib/async-loop-cpp",
 "//zircon/public/lib/async-loop-default",
  ]
}
​
package("echo_client_cpp") { #定义包
  deps = [ ":bin" ] # 依赖于上面的bin
​
  binary = "echo_client_cpp" # 可执行文件
​
  meta = [ # 运行时配置文件
    {
      path = rebase_path("../meta/echo_client.cmx")
      dest = "echo_client_cpp.cmx"
    },
  ]
}

编译执行

在源码树里用 fx 设置编译选项添加这两个包。 --with后面接的相对路径, 冒号后面是要编的包名

set core.x64  --with //garnet/examples/fidl/echo_client_cpp:echo_client_cpp --with  //garnet/examples/fidl/echo_server_cpp:echo_server_cpp
rm -f log.txt 

运行

首先在fuchsia的shell里查 两个包的url

然后运行client,用run命令 接参数 url

不需要手动启动服务端,因为客户端去连接服务时,系统会把服务启动起来. 用 fx log看下log

手动实现一个FIDL实例

光看不练假把式, 我们手动自己实现一个FIDL实例.

为了方便,直接复用exampleshello_word这个工程.

编写fidl文件

在hello_world目录下编写如下的call.fidl文件

FIDL支持四种模式的通信

  • blocking call: client端发送给server端请求,并且阻塞等待server端的回复. 上面的CallString实现了这种类型.
  • fire and forget: client发送给server端请求,不要求回复。上面的SendString是这种类型.
  • callback: client端发送给server端请求,但是不阻塞等待,server会有异步的回复消息,上面的CallString有实现这种类型,后面实例会讲
  • event: cleint不做任何请求,server端会主动通知过来.OnReceiveString是这种类型

我遇到的坑

  • fidl开头一定要加Copyright,按照规则写,否则编译不过
  • namespace要指定,并且以fuchsia开头,namespace不能超过3层

编译fidl

直接修改exampleshello_word下的BUILD.gn, 添加一个fidl模块,写法也是仿照示例

(

编写服务端

编写一个实现Call.fidl里定义的Call的类

class 

服务端主函数

int 

编写客户端

构建脚本BUILD.gn

我把client,server端,fidl的编译都写到一个BUILD.gn文件里.

# Copyright 2019 The Fuchsia Authors. All rights reserved.

编译执行

编译

set core.x64  --with //examples/hello_world/cpp:hello_world_cpp
fx build

运行,先用locate查包的url

分别起两个窗口运行

客户端 收到服务端的回复,通过pinntf打印出来,但是奇怪的是server端的printf输出没有打印到terminal,而是到log里。

printf输出到log的原因分析

怀疑是标准输出流stdout被重定向到 log,应该是async事件库干的,先留个坑,以后在分析。

你可能感兴趣的:(aidl使用)