转载:https://source.android.com/devices/architecture/hidl/services?hl=zh-cn
本部分介绍了如何注册和发现服务,以及如何通过调用 .hal
文件内的接口中定义的方法将数据发送到服务。
HIDL 接口服务器(实现接口的对象)可注册为已命名的服务。注册的名称不需要与接口或软件包名称相关。如果没有指定名称,则使用名称“默认”;这应该用于不需要注册同一接口的两个实现的 HAL。例如,在每个接口中定义的服务注册的 C++ 调用是:
registerAsService (); HIDL 接口的版本包含在接口本身中。版本自动与服务注册关联,并可通过每个 HIDL 接口上的方法调用 (android::hardware::IInterface::getInterfaceVersion()
) 进行检索。服务器对象不需要注册,并可通过 HIDL 方法参数传递到其他进程,相应的接收进程会向服务器发送 HIDL 方法调用。
客户端代码按名称和版本请求指定的接口,从而对所需的 HAL 类调用 getService
:
每个版本的 HIDL 接口都会被视为单独的接口。因此,IFooService
版本 1.1 和 IFooService
版本 2.2 都可以注册为“foo_service”,并且两个接口上的 getService("foo_service")
都可获取该接口的已注册服务。因此,在大多数情况下,注册或发现服务均无需提供名称参数(也就是说名称为“默认”)。
供应商接口对象还会影响所返回接口的传输方法。对于软件包 [email protected]
中的接口IFoo
,IFoo::getService
返回的接口始终使用设备清单中针对 android.hardware.foo
声明的传输方法(如果相应条目存在的话);如果该传输方法不存在,则返回 nullptr。
想要在服务终止时收到通知的客户端会接收到框架传送的终止通知。要接收通知,客户端必须:
hidl_death_recipient
(位于 C++ 代码中,而非 HIDL 中)归入子类。serviceDied()
方法。hidl_death_recipient
子类的对象。linkToDeath()
方法以进行监控,从而传递 IDeathRecipient
的接口对象。伪代码示例(C++ 和 Java 类似):
class IMyDeathReceiver : hidl_death_recipient {同一终止接收方可能已在多个不同的服务上注册。
可通过调用 .hal
文件内的接口中定义的方法将数据发送到服务。具体方法有两类:
不返回值但未声明为 oneway
的方法仍在阻塞。
在 HIDL 接口中声明的所有方法都是单向调用,要么从 HAL 发出,要么到 HAL。该接口没有指定具体调用方向。需要从 HAL 发起调用的架构应该在 HAL 软件包中提供两个(或更多个)接口并从每个进程提供相应的接口。对于接口的调用方向,我们使用字词“客户端”和“服务器”来表示(即 HAL 可以是一个接口的服务器,也可以是另一个接口的客户端)。
“回调”一词指的是两个不同的概念,可通过“同步回调”和“异步回调”进行区分。
“同步回调”在返回数据的一些 HIDL 方法中使用。返回多个值(或返回非基元类型的一个值)的 HIDL 方法会通过回调函数返回其结果。如果只返回一个值且该值是基元类型,则不使用回调且该值从方法中返回。服务器实现 HIDL 方法,而客户端实现回调。
“异步回调”允许 HIDL 接口的服务器发起调用。通过第一个接口传递第二个接口的实例即可完成此操作。第一个接口的客户端必须作为第二个接口的服务器。第一个接口的服务器可以在第二个接口对象上调用方法。例如,HAL 实现可以通过在由该进程创建和提供的接口对象上调用方法来将信息异步发送回正在使用它的进程。用于异步回调的接口中的方法可以是阻塞(并且可能将值返回到调用程序),也可以是 oneway
。要查看相关示例,请参阅 HIDL C++ 中的“异步回调”。
要简化内存所有权,方法调用和回调只能选择 in
参数,并且不支持 out
或 inout
参数。
每事务限制可能会强制限制在 HIDL 方法和回调中发送的数据量。具体限制尚不确定,但可能小至 4K。超出这些限制的调用会立即返回失败。另一个限制是可供 HIDL 基础架构处理多个同时进行的事务的资源。由于多个线程或进程向一个进程发送调用或者接收进程未能快速处理多个 oneway
调用,因此多个事务可以同时进行。
在设计良好的接口中,不应出现超出这些资源限制的情况;如果超出的话,则超出资源的调用可能会阻塞,直到资源可用或发出传输错误的信号。每当因正在进行的总事务导致出现超出每事务限制或溢出 HIDL 实现资源的情况时,系统都会记录下来以方便调试。
HIDL 生成以目标语言(C++ 或 Java)声明必要类型、方法和回调的标头文件。客户端和服务器代码的 HIDL 定义方法和回调的原型是相同的。HIDL 系统提供调用程序端(整理 IPC 传输的数据)的方法代理实现,并将代码存根到被调用程序端(将数据传递到方法的开发者实现)。
函数的调用程序(HIDL 方法或回调)拥有对传递到该函数的数据结构的所有权,并在调用后保留所有权;被调用程序在所有情况下都无需释放存储。
HIDL 在不使用 RPC 调用的情况下通过两种方法来转移数据:共享内存和快速消息队列 (FMQ),只有 C++ 同时支持这两种方法。
memory
用于传递表示已分配的共享内存的对象。 可以在接收进程中使用,以映射共享内存。MQDescriptorSync
或 MQDescriptorUnsync
的参数通过 RPC 传递的对象。接收进程可使用此对象设置队列的另一端。
有关 FMQ 的更多详情,请参阅快速消息队列 (FMQ)。