site: https://source.android.com/devices/architecture/hidl-cpp/

Overview

Android O重新架构Android操作系统,在设备独立的Android平台与设备和特定于供应商的代码之间定义了清晰的接口。Android已经用HAL接口的形式定义了许多这样的接口,在 hardware/libhardware 中定义为C头文件。HIDL用稳定的、版本化的接口替换了这些HAL接口,这些接口可以是c++(描述如下)或Java写成的客户端和服务器端HIDL接口。

本节中的页面描述了HIDL接口的c++实现,包括 hidl-gen 编译器自动生成的 HIDL .hal文件的详细信息,这些文件是如何打包的,以及如何将这些文件与使用它们的c++代码集成在一起。

Client & server implementations

HIDL接口具有客户端和服务器实现:

  • HIDL接口的客户端包含调用接口上的方法的代码。
  • 服务器是HIDL接口的实现,它接收来自客户机的调用并返回结果(如果需要)。

在从 libhardware HALs 到 HIDL HALs 的转换过程中,HAL实现成为服务器,调用HAL的过程成为客户端。默认实现可以同时支持passthrough和binder化HALs,并且可以随时间改变:

Creating the HAL client

从在makefile中包含 HAL 库开始:

  • Make: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • Soong: shared_libs: [ …, android.hardware.nfc@1.0 ]

接下来,包含 HAL 头文件:

#include // in code:sp client = IFoo::getService();client->doThing();

创建 HAL 服务端

为了创建 HAL 实现,你必须有代表你 HAL 的 .hal 文件,并在 hidl-gen 中使用 -Lmakefile 或者 -Landroidbp 为 HAL 生成了 makefile( ./hardware/interfaces/update-makefiles.sh 位内部 HAL 文件做了这个操作,是一个很好的参考)。当从 libhardware 转移到HALs时,您可以轻松地使用 c2hal 来完成许多工作。

创建必要的文件来实现您的HAL:

PACKAGE=android.hardware.nfc@1.0LOC=hardware/interfaces/nfc/1.0/default/make hidl-gen -j64hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \    -randroid.hidl:system/libhidl/transport $PACKAGEhidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \    -randroid.hidl:system/libhidl/transport $PACKAGE

为了让HAL在 passthrough 模式中工作(对于 legacy 设备),您必须在 /system/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so 具有 HIDL_FETCH_IModuleName 函数,其中 OPTIONAL_IDENTIFIER 是一个字符串用来标识 passthrough 实现。passthrough 模式的需求自动被上述命令满足,同时创建了 android.hardware.nfc@1.0-impl 目标,但是可以使用任何扩展。例如,android.hardware.nfc@1.0-impl-foo 使用 -foo 来区分自己。

接下来,用功能填写 stubs 并设置一个守护进程。示例守护程序代码(支持passthrough):

#include int main(int /* argc */, char* /* argv */ []) {    return defaultPassthroughServiceImplementation("nfc");}

defaultPassthroughServiceImplementation 将 dlopen() 提供的 -impl 库,并且将它作为一个绑定的服务,示例守护程序代码(纯粹的绑定服务):

int main(int /* argc */, char* /* argv */ []) {    sp nfc = new Nfc();    const status_t status = nfc->registerAsService();    if (status != ::android::OK) {        return 1; // or handle error    }    // join pool or do other things}

这个守护进程应该存活于 PACKAGE + “-service” (例如,android.hardware.nfc@1.0-service),HAL 的指定类 sepolicy 是通过属性 hal_< module>(例如,hal_nfc)。这个属性必须应用于运行特定HAL的守护进程(如果同一个进程服务多个HALs,可以应用多个属性)。

Packages

注意:本节使用 sample.hal 文件来说明HIDL语言构造如何映射到c++。

除了少数例外,HIDL接口包位于 hardware/interfaces 或 vendor/ 目录中。hardware/interfaces 直接映射到 android.hardware 包命名空间;版本是包(不是接口)命名空间下的子目录。

hidl-gen 编译器编译 .hal 文件生成一系列 .h 和 .cpp文件。这些自动生成的文件生成一个连接服务端和客户端的共享库,构建这个共享库的 Android.bp 文件是由 hardware/interfaces/update-makefiles.sh 脚本自动生成的。每次逆天加一个新的包到 hardware/interfaces,或者 添加/移除 .hal 文件 到/自 一个已存在的文件夹,你必须重运行脚本确保共享库更新了。

例如,IFoo.hal 样本文件位于 hardware/interfaces/samples/1.0。样本 IFoo.hal 在 samples 包创建一个 IFoo 接口。

package android.hardware.samples@1.0;interface IFoo {    struct Foo {       int64_t someValue;       handle  myHandle;    };    someMethod() generates (vec);    anotherMethod(Foo foo) generates (int32_t ret);};

Generated files

HIDL包中的自动生成文件链接到一个与包同名的共享库(例如,android.hardware.samples@1.0)。共享库还导出一个头文件 IFoo.h,它可由客户端和服务器端包含。使用 IFoo.hal 接口文件作为 hidl-gen 编译器的输入,binderized模式有以下自动生成的文件:

  • IFoo.h 用一个 C++ 类描述纯粹的 IFoo 接口,它包含 IFoo.hal 文件中 IFoo 接口定义的方法和类型,并在必要的地方转换成 C++类型。不包含实现接口相关的 RPC 机制细节(例如:HwBinder),类的命名空间是包名和版本号,例如 ::android::hardware::samples::IFoo::V1_0。客户端和服务端都包含这个头文件,客户端是为了调用上面的方法,服务端实现了这些方法。
  • IHwFoo.h 头文件包含用于序列化接口中使用的数据类型的函数的声明。开发者不应该直接包含这个头文件(它不包含任何类)。
  • BpFoo.h 从IFoo继承的类,并描述接口的HwBinder代理(客户端)实现。开发人员不应该直接引用这个类。
  • BnFoo.h 一个类,它包含对IFoo实现的引用,并描述接口的 HwBinder stub (服务器端)实现。开发人员不应该直接引用这个类。
  • FooAll.cpp 包含 HwBinder proxy 和HwBinder stub 实现的类。当客户端调用接口方法时,proxy 会自动从客户端整理参数,并将事务发送给绑定内核驱动程序,驱动程序将事务交付给另一端的 stub。

这些文件的结构类似于 aidl-cpp 生成的文件。唯一独立于HIDL使用的RPC机制的自动生成文件是IFoo.h;所有其他文件都绑定到HIDL使用的HwBinder RPC机制。因此,客户端和服务器实现不应该直接引用IFoo以外的任何东西。

Linking to shared libraries

在包中使用任何接口的客户端或服务端必须在以下位置的一个中包含该包的共享库:

  • Android.mk 中:
    LOCAL_SHARED_LIBRARIES += android.hardware.samples@1.0
  • Android.bp 中:
shared_libs: [    /* ... */    "android.hardware.samples@1.0",],

对于特殊的库:

libs method
libhidlbase 包括标准HIDL数据类型。除非您的接口只包含直接映射到c++类型的类型,否则您还必须链接这个库: LOCAL_SHARED_LIBRARIES += libhidlbase
libhidltransport 处理不同RPC/IPC机制的HIDL调用的传输。你必须始终链接这个库: LOCAL_SHARED_LIBRARIES += libhidltransport
libhwbinder 您还必须链接这个库:LOCAL_SHARED_LIBRARIES + = libhwbinder
libfmq 要使用快速消息队列IPC,您还必须链接到这个库:LOCAL_SHARED_LIBRARIES += libfmq

Namespaces

HIDL函数和类型,如 Return< T> 和 Void() 在 ::android::hardware 命名空间中声明。包的c++命名空间由名称和版本决定。例如,1.2 版本的 mypackage 包在 hardware/interfaces 下具有以下特性:

  • C++ 命名空间是 ::android::hardware::mypackage::V1_2
  • 包内的 IMyInterface 的全限制名称是 ::android::hardware::mypackage::V1_2::IMyInterface
  • 包内 types.hal 文件中的 Type 标识为 ::android::hardware::mypackage::V1_2::MyPackageType

Interfaces

在HIDL包中定义的每个接口都在其包的名称空间中有自己的自动生成的c++类。客户端和服务器以不同的方式处理接口:

  • Servers 实现接口
  • 客户端调用接口方法

接口可以通过服务端的名称注册,也可以作为参数传递给 HIDL 定义的方法。例如,框架代码可以提供一个接口来接收来自 HAL 的异步消息,并将该接口直接传递给 HAL,而无需注册它。

Server implementation

实现IFoo接口的服务端必须包含自动生成的IFoo头文件:

#include 

头文件由IFoo接口的共享库自动导出以用来链接。示例 IFoo.hal:

// IFoo.halinterface IFoo {    someMethod() generates (vec);    ...}

IFoo接口的服务端实现的示例框架:

// From the IFoo.h headerusing android::hardware::samples::V1_0::IFoo;class FooImpl : public IFoo {    Return<void> someMethod(foo my_foo, someMethod_cb _cb) {        vec<uint32_t> return_data;        // Compute return_data        _cb(return_data);        return Void();    }    ...};

为了使客户端能够得到服务器接口,您可以:

  • 使用 hwservicemanager 注册接口实现(参见下面的详细信息)
  • 将接口实现作为接口方法的参数传递

在注册接口实现时,hwservicemanager 进程会跟踪在设备上运行的注册的HIDL接口的名称和版本。服务端可以通过名称注册HIDL接口实现,客户机可以通过名称和版本请求服务实现。这个过程服务于HIDL接口 android.hidl.manager@1.0::IServiceManager。

Each auto-generated HIDL interface header file (such as IFoo.h) has a registerAsService() method that can be used to register the interface implementation with the hwservicemanager. The only required argument is the name of the interface implementations as clients will use this name to retrieve the interface from the hwservicemanager later:

::android::sp myFoo = new FooImpl();::android::sp mySecondFoo = new FooAnotherImpl();status_t status = myFoo->registerAsService();status_t anotherStatus = mySecondFoo->registerAsService("another_foo");

The hwservicemanager treats the combination of [package@version::interface, instance_name] as unique to enable different interfaces (or different versions of the same interface) to register with identical instance names without conflicts. If you call registerAsService() with the exact same package version, interface, and instance name, the hwservicemanager drops its reference to the previously registered service and uses the new one.

Client implementation

Just as the server does, a client must #include every interface it refers to:

#include 

A client can obtain an interface in two ways:

  • Through I< InterfaceName>::getService (via the hwservicemanager)

Each autogenerated interface header file has a static getService method that can be used to retrieve a service instance from the hwservicemanager:

// getService will return nullptr if the service can't be foundsp myFoo = IFoo::getService();sp myAlternateFoo = IFoo::getService("another_foo");

Now the client has an an IFoo interface, and can call methods to it as if it were a local class implementation. In reality, the implementation may run in the same process, a different process, or even on another device (with HAL remoting). Because the client called getService on an IFoo object included from version 1.0 of the package, the hwservicemanager returns a server implementation only if that implementation is compatible with 1.0 clients. In practice, this means only server implementations with version 1.n (version x.(y+1) of an interface must extend (inherit from) x.y).

Additionally the method castFrom is provided to cast between different interfaces. This method works by making an IPC call to the remote interface to make sure the underlying type is the same as the type that is being requested. If the requested type is unavailable, then nullptr is returned.

sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService();sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);

Asynchronous callbacks

Many existing HAL implementations talk to asynchronous hardware, which means they need an asynchronous way to notify clients of new events that have occurred. A HIDL interface can be used as an asynchronous callback because HIDL interface functions can take HIDL interface objects as parameters.

Example interface file IFooCallback.hal:

package android.hardware.samples@1.0;interface IFooCallback {    sendEvent(uint32_t event_id);    sendData(hidl_vec data);}

Example new method in IFoo that takes an IFooCallback parameter:

package android.hardware.samples@1.0;interface IFoo {    struct Foo {       int64_t some_value;       Handle my_handle;    };    someMethod(Foo foo) generates (int32_t ret);    another_method() generates (hidl_vec);    register_callback(IFooCallback callback);};

The client using the IFoo interface is the server of the IFooCallback interface; it provides an implementation of IFooCallback:

class FooCallback : public IFooCallback {    Return<void> sendEvent(uint32_t event_id) {        // process the event from the HAL    }    Return<void> sendData(hidl_vec<uint8_t> data) {        // process data from the HAL    }};

It can also simply pass that over an existing instance of the IFoo interface:

sp myFooCallback = new FooCallback();myFoo.registerCallback(myFooCallback);

The server implementing IFoo receives this as an sp< IFooCallback> object. It can store the callback, and call back into the client whenever it wants to use this interface.

Death recipients

As service implementations can run in a different process, it can happen that the process implementing an interface dies while the client stays alive. Any calls on an interface object hosted in a process that has died will fail with a transport error (isOK() will return false). The only way to recover from such a failure is to request a new instance of the service by calling I::getService(). This works only if the process that crashed has restarted and re-registered its services with the servicemanager (which is generally true for HAL implementations).

Instead of dealing with this reactively, clients of an interface can also register a death recipient to get a notification when a service dies. To register for such notifications on a retrieved IFoo interface, a client can do the following:

foo->linkToDeath(recipient, 1481 /* cookie */);

The recipient parameter must be an implementation of the android::hardware::hidl_death_recipient interface provided by HIDL, which contains a single method serviceDied() that will be called from a thread in the RPC threadpool when the process hosting the interface dies:

class MyDeathRecipient : android::hardware::hidl_death_recipient {    virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) {       // Deal with the fact that the service died    }}

The cookie parameter contains the cookie that was passed in with linkToDeath(), whereas the who parameter contains a weak pointer to the object representing the service in the client. With the sample call given above, cookie equals 1481, and who equals foo.

It’s also possible to unregister a death recipient after registering it:

foo->unlinkToDeath(recipient);

wait for update…

更多相关文章

  1. Android输出日志Log类
  2. Android文件或文件夹内容改变监听器(FileObserver)
  3. greenDAO的简单使用(一)
  4. Android性能分析和优化之traces.txt(ANR分析)
  5. Android(安卓)P联网报错Cleartext HTTP traffic to xxx not perm
  6. Android实现截屏,将截图文件保存到本地文件夹
  7. android 模拟器访问本地服务器接口api
  8. Android(安卓)Studio 的菜单栏之 Android(安卓)Studio 与 File
  9. Android(安卓)自定义View 例子一

随机推荐

  1. AndroidStudio3.6.3新版本遇到的坑
  2. Android多媒体开发(3)————使用Android(
  3. 初学Andriod之跑马灯属性设置
  4. android webview 截图快照
  5. activity跳转闪现黑屏
  6. android 输入法出现挤压屏幕
  7. android使用CheckedTextView搭配listview
  8. android ListView SimpleAdapter 带图片
  9. Android--取出SDcard卡上指定后缀名的文
  10. Android(安卓)Studio Gradle相关异常记录