Android HIDL 官方文档(四)—— 服务与数据转换(Services & Data Transfer)

来源:互联网 发布:linux修改tomcat内存 编辑:程序博客网 时间:2024/06/07 07:14

  • 注册服务
  • 发现服务
  • 服务死亡通知
  • 数据传输
    • 1 回调
    • 2 每次事务的限制
    • 3 方法实现
    • 4 非远程过程调用的数据传输


  • 对应的官方文档地址:HIDL(General) - Services & Data Transfer

This section describes how to register and discover services and how to send data to a service by calling methods defined in interfaces in .hal files.

       这一章节描述了如何注册与发现服务,以及如何通过调用定义在 .hal 文件中的接口向服务发送数据。

1. 注册服务

(Registering services)

HIDL interface servers (objects implementing the interface) can be registered as named services. The registered name need not be related to the interface or package name. If no name is specified, the name “default” is used; this should be used for HALs that do not need to register two implementations of the same interface. For example, the C++ call for service registration defined in each interface is:

       HIDL 接口服务端(实现接口的对象)可被注册为一个命名的服务。注册的名称不需要与接口名或者包名相关。如果没有指定名称,则会使用 default 作为名称。这应使用于不需要注册相同接口的两个已实现的 HALs。举个例子,在每个接口中定义的服务注册的 C++ 调用:

registerAsService();registerAsService("another_foo_service");  // if needed

The version of a HIDL interface is included in the interface itself. It is automatically associated with service registration and can be retrieved via a method call (android::hardware::IInterface::getInterfaceVersion()) on every HIDL interface. Server objects need not be registered and can be passed via HIDL method parameters to another process that will make HIDL method calls into the server.

       一个 HIDL 接口的版本包含在接口本身之中。它自动关联到注册的服务,并且可以通过调用方法 android::hardware::IInterface::getInterfaceVersion() 对每个 HIDL 接口进行检索。服务端对象不需要进行注册,并且它可以通过 HIDL 方法的参数传递给另一个进程,这将使 HIDL 方法调用到服务端。

2. 发现服务

(Discovering services)

Requests by client code are made for a given interface by name and by version, calling getService on the desired HAL class:

       客户端的代码请求是按照给定接口的名称与版本进行的,在所需要的 HAL 类上调用 getService 方法:

sp<V1_1::IFooService> service = V1_1::IFooService::getService();sp<V1_1::IFooService> alternateService = 1_1::IFooService::getService("another_foo_service"); 

Each version of a HIDL interface is treated as a separate interface. Thus, IFooService version 1.1 and IFooService version 2.2 can both be registered as “foo_service” and getService(“foo_service”) on either interface gets the registered service for that interface. This is why, in most cases, no name parameter needs to be supplied for registration or discovery (meaning name “default”).

       一个 HIDL 接口的每个不同的版本分别被视为一个单独的接口。因此,1.1 版本的 IFooService 与 2.2 版本的 IFooService 都可以被注册为 foo_service,并且 getService("foo_service") 方法在任一接口上都可以获得该接口的注册服务。这就是为什么在大多数情况下,不需要为注册或发现提供参数名(此时为 default 情况)。

The Vendor Interface Object also plays a part in the transport method of the returned interface. For an interface IFoo in package android.hardware.foo@1.0, the returned interface by IFoo::getService always use the transport method declared for android.hardware.foo in the device manifest if the entry exists; and if the transport method is not available, nullptr is returned.

       供应商接口对象也在返回接口的传输方法中起到一定的作用。android.hardware.foo@1.0 包中的接口 IFoo,如果条目存在,通过 IFoo::getService 返回的接口常常使用在设备清单中 android.hardware.foo 的传输方法。如果传输方法是不可用的,则会返回空指针。

3. 服务死亡通知

(Service death notifications)

Clients who want to be notified when a service dies can receive death notifications delivered by the framework. To receive notifications, the client must:

  1. Subclass the HIDL class/interface hidl_death_recipient (in C++ code, not in HIDL).
  2. Override its serviceDied() method.
  3. Instantiate an object of the hidl_death_recipient subclass.
  4. Call the linkToDeath() method on the service to monitor, passing in the IDeathRecipient’s interface object.

       需要被通知的客户端在一个服务死亡时,可以收到由框架所交付的死亡通知。为了接收通知,客户端需要满足以下条件:

  • HIDL 类 / 接口 hidl_death_recipient 的子类。(在 C++ 代码中,而非 HIDL)
  • 重写它的 serviceDied() 方法。
  • 实例化一个 hidl_death_recipient 子类对象。
  • 调用服务的方法 linkToDeath() 给监视器,传入 IDeathRecipient 的接口对象。

       伪代码实例(C++ 与 Java 的情况是类似的):

class IMyDeathReceiver : hidl_death_recipient {  virtual void serviceDied(uint64_t cookie,                           wp<IBase>& service) override {    log("RIP service %d!", cookie);  // Cookie should be 42  }};....IMyDeathReceiver deathReceiver = new IMyDeathReceiver();m_importantService->linkToDeath(deathReceiver, 42);

The same death recipient may be registered on multiple different services.

       同样的死亡接收者可以是在不同的服务上注册的。

4. 数据传输

(Data transfer)
Data may be sent to a service by calling methods defined in interfaces in .hal files. There are two kinds of methods:

  • Blocking methods wait until the server has produced a result.
  • Oneway methods send data in only one direction and do not block. If the amount of data in-flight in RPC calls exceeds implementation limits, the calls may either block or return an error indication (behavior is not yet determined).

A method that does not return a value but is not declared as oneway is still blocking.

       通过调用 .hal 文件中定义的接口,数据可以被传输到服务中。有两种类型的方法:

  • 阻塞的方法将会等待服务端产生一个需要的结果。
  • 单向的方法只在一个方向上传输数据,并且不会阻塞。如果 RPC 内部的数据量超过了实现的限制,则本次调用可以阻塞或者返回错误提示(行为未确定)。

       一个没有值返回,但不定义为单向的方法,仍然是阻塞的。

All methods declared in a HIDL interface are called in a single direction, either from the HAL or into the HAL. The interface does not specify which direction it will be called in. Architectures that need calls to originate from the HAL should provide two (or more) interfaces in the HAL package and serve the appropriate interface from each process. The words client and server are used with respect to the calling direction of the interface (i.e. the HAL can be a server of one interface and a client of another interface).

       在 HIDL 接口中声明的所有方法都是单向调用的,无论是从 HAL 调用还是调用到 HAL。接口没有特别指定调用是在哪个方向上的。需要调用源自 HAL 的架构应在 HAL 的包中提供一个或更多的接口,并且从每个进程中提供适当的接口。字段 clientserver 就用于使调用遵守接口的方向(比如一个 HAL 可以是一个接口的 server 同时是另一个接口的 client)。

4.1 回调

(Callbacks)

The word callback refers to two different concepts, distinguished by synchronous callback and asynchronous callback.

       回调这个词指两个不同的概念,它们的区别在于一个是同步回调,另一个是异步回调。

Synchronous callbacks are used in some HIDL methods that return data. A HIDL method that returns more than one value (or returns one value of non-primitive type) returns its results via a callback function. If only one value is returned and it is a primitive type, a callback is not used and the value is returned from the method. The server implements the HIDL methods and the client implements the callbacks.

       同步回调应用于一些需要返回数据的 HIDL 方法。对于一个需要返回超过一个值(或者返回一个非基本类型的值)的 HIDL 方法,它会通过回调函数来返回这些结果数据。如果仅仅需要返回一个值,并且这个值属于基本类型,则不需要回调,直接通过该方法返回即可。服务端实现 HIDL 方法,而客户端则实现回调函数。

Asynchronous callbacks allow the server of a HIDL interface to originate calls. This is done by passing an instance of a second interface through the first interface. The client of the first interface must act as the server of the second. The server of the first interface can call methods on the second interface object. For example, a HAL implementation may send information asynchronously back to the process that is using it by calling methods on an interface object created and served by that process. Methods in interfaces used for asynchronous callback may be blocking (and may return values to the caller) or oneway. For an example, see “Asynchronous callbacks” in HIDL C++.

       异步回调允许一个 HIDL 接口服务端发起调用。这是通过第一个接口传递第二个接口的实例实现的。第一个接口的客户端必须作为第二个接口的服务端。第一接口的服务端可以调用第二接口对象中的方法。举个例子,一个 HAL 实现可以异步地将信息发送回正在使用它的进程,这是通过调用由该进程创建并服务的一个接口来运作的。用于异步回调的接口中的方法可以是阻塞的(并且也可以返回值给调用者),也可以是单向的。在 HIDL C++ 的 Asynchronous callbacks 小节中有比较具体的介绍。

To simplify memory ownership, method calls and callbacks take only in parameters and do not support out or inout parameters.

       为了简化内存所有权,方法的调用与回调只需要参数 in,而不需要 out 或者 inout 参数。

4.2 每次事务的限制

(Per-transaction limits)

Per-transaction limits may be imposed on the amount of data sent in HIDL methods and callbacks. The limits are yet to be determined but may be as small as 4K. Calls exceeding these limits return failure immediately. Another limitation is the resources available to the HIDL infrastructure to handle multiple simultaneous transactions. Multiple transactions can be in-flight simultaneously due to multiple threads or processes sending calls to a process or multiple oneway calls that are not handled quickly by the receiving process.

       对每次事务的限制条件可能会施加到 HIDL 方法或回调中所传输的数据量上。这些限制尚未确定,但可能只会有 4K。当调用超过了这些限制,则会直接返回失败信息。另一个限制是关于处理多个同时事务时的 HIDL 基础结构的可用资源量。多个事务可以同时进行,是因为多个线程或进程向一个进程发送调用,或者多个单向调用未被所接收的进程快速地处理完毕。

In a well-designed interface, exceeding these resource limitations should not happen; if it does, the call which exceeded them may either block until resources become available or signal a transport error. Each occurrence of exceeding per-transaction limits or overflowing HIDL implementation resources by aggregate in-flight transactions is logged to facilitate debugging.

       在一个设计良好的接口中,超过资源限制的这些情况不应发生。如果发生了,则超出这些限制的调用可能会阻塞直到可用资源足够为止,或者发送一个传输错误信号。

4.3 方法实现

(Method implementations)

HIDL generates header files declaring the necessary types, methods, and callbacks in the target language (C++ or Java). The prototype of HIDL-defined methods and callbacks is the same for both client and server code. The HIDL system provides proxy implementations of the methods on the caller side that organize the data for IPC transport, and stub code on the callee side that passes the data into developer implementations of the methods.

       HIDL 生成的目标语言(C++ 或者 Java)头文件中定义了必要的类型,方法与回调。HIDL 定义的方法与回调的原型对于服务端与客户端代码是相同的。HIDL 系统在组织数据进行 IPC 传输的调用端提供了代理的实现,并且在传递数据到开发者实现的方法中的被调用端提供了的代码。

The caller of a function (HIDL method or callback) has ownership of the data structures passed into the function, and retains ownership after the call; in all cases the callee does not need to free or release the storage.

  • In C++, the data may be read-only (attempts to write to it may cause a segmentation fault) and are valid for the duration of the call. The client can deep-copy the data to propagate it beyond the call.
  • In Java, the code receives a local copy of the data (a normal Java object), which it may keep and modify or allow to be garbage-collected.

       函数(HIDL 方法或回调)的调用者拥有对传入的数据结构的所有权,并在调用之后保持这个所有权,在任何情况下被调用者都不需要释放存储空间:

  • 在 C++ 中,这个数据可能是只读(尝试对其写入将导致段错误)的,并且在调用期间是一直有效的。客户端可以对数据进行深复制,以在调用之外传播它。
  • 在 Java 中,代码会接收到数据(一个普通 Java 对象)的本地拷贝,它可以保存和修改,或者允许被垃圾回收机制处理。

4.4 非远程过程调用的数据传输

(Non-RPC data transfer)
HIDL has two ways to transfer data without using an RPC call: shared memory and a Fast Message Queue (FMQ), both supported only in C++.

  • Shared memory. The built-in HIDL type memory is used to pass an object representing shared memory that has been allocated. Can be used in a receiving process to map the shared memory.
  • Fast Message Queue (FMQ). HIDL provides a templated message queue type that implements no-wait message-passing. It does not use the kernel or scheduler in passthrough or binderized mode (inter-device communication will not have these properties). Typically, the HAL sets up its end of the queue, creating an object that can be passed through RPC via a parameter of built-in HIDL type MQDescriptorSync or MQDescriptorUnsync. This object can be used by the receiving process to set up the other end of the queue.
    • Sync queues are not allowed to overflow, and can only have one reader.
    • Unsync queues are allowed to overflow, and can have many readers, each of which must read data in time or lose it.
    • Neither type is allowed to underflow (read from an empty queue will fail), and each type can only have one writer.

       在 RPC 传输方式之外,HIDL 还有两种数据传输的方法:共享内存与快速消息队列,它们都只在 C++ 语言中支持。

  • 共享内存。HIDL 内建的类型 memory 是用于传递一个表示已分配的共享内存的对象的。可以在接收进程中使用它来映射共享内存。
  • 快速消息队列。HIDL 提供了一个实现了不用等待的消息传递的模板消息队列类型。它并没有使用到 Passthrough 模式或者 Binder 化模式(互联设备之间的交互不会拥有这些特性)的内核与调度器。通常,HAL 会设置它的队列的末端,并创建可以通过内置 HIDL 类型 MQDescriptorSyncMQDescripotrUnsync 的参数传递到 RPC 的对象。这个对象可以被接收进程用于设置队列的另一端:
    • 同步队列不允许溢出,且只能有一个读取者。
    • 异步队列允许溢出,可以有多个读者,每个读者必须及时读取或丢弃数据。
    • 两种队列都不允许下溢(对空队列读取将返回失败信息),并且只能有一个写入者。
阅读全文
0 0
原创粉丝点击