(六十三)HIDL C++ && HIDL Java

时间:2024-04-10 10:04:57

转载:

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

2.https://source.android.com/devices/architecture/hidl-java/#autogen


HIDL C++

Android O 对 Android 操作系统的架构重新进行了设计,以在独立于设备的 Android 平台与特定于设备和供应商的代码之间定义清晰的接口。Android 已经以 HAL 接口的形式(在 hardware/libhardware 中定义为 C 标头)定义了许多此类接口。HIDL 将这些 HAL 接口替换为稳定的带版本接口,它们可以是采用 C++(如下所述)或 Java 的客户端和服务器端 HIDL 接口。

本部分中的几页内容介绍了 HIDL 接口的 C++ 实现,其中详细说明了 hidl-gen 编译器基于 HIDL .hal 文件自动生成的文件,这些文件如何打包,以及如何将这些文件与使用它们的 C++ 代码集成。

客户端和服务器实现

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

HIDL 接口的客户端实现是指通过在该接口上调用方法来使用该接口的代码。
服务器实现是指 HIDL 接口的实现,它可接收来自客户端的调用并返回结果(如有必要)。
在从 libhardware HAL 转换为 HIDL HAL 的过程中,HAL 实现成为服务器,而调用 HAL 的进程则成为客户端。默认实现可提供直通和绑定式 HAL,并可能会随着时间而发生变化:

(六十三)HIDL C++ && HIDL Java

创建 HAL 客户端

首先将 HAL 库添加到 makefile 中:

Make:LOCAL_SHARED_LIBRARIES += [email protected]
Soong:shared_libs: [ …, [email protected] ]
接下来,添加 HAL 头文件:

#include <android/hardware/nfc/1.0/IFoo.h>

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

创建 HAL 服务器

要创建 HAL 实现,您必须具有表示 HAL 的 .hal 文件并已在 hidl-gen 上使用 -Lmakefile 或 -Landroidbp 为 HAL 生成 makefile(./hardware/interfaces/update-makefiles.sh 会为内部 HAL 文件执行这项操作,这是一个很好的参考)。从 libhardware 通过 HAL 传输时,您可以使用 c2hal 轻松完成许多此类工作。

要创建必要的文件来实现您的 HAL,请使用以下代码:

[email protected]
LOC=hardware/interfaces/nfc/1.0/default/
make hidl-gen -j64
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \
    -randroid.hidl:system/libhidl/transport $PACKAGE
为了让 HAL 在直通模式下发挥作用(对于旧版设备),您必须具备 HIDL_FETCH_IModuleName 函数(位于
/system/lib(64)?/hw/[email protected]($OPTIONAL_IDENTIFIER).so 下),其中 $OPTIONAL_IDENTIFIER 是一个标识直通实现的字符串。直通模式要求会通过上述命令自动满足,这些命令也会创建 [email protected] 目标,但是可以使用任何扩展。例如,[email protected] 就是使用 -foo 区分自身。

接下来,使用相应功能填写存根并设置守护进程。守护进程代码(支持直通)示例:

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}
defaultPassthroughServiceImplementation 将对提供的 -impl 库执行 dlopen() 操作,并将其作为绑定式服务提供。守护进程代码(对于纯绑定式服务)示例:

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"(例如 [email protected])中。HAL 的特定类的 sepolicy 是属性 hal_<module>(例如 hal_nfc))。您必须将此属性应用到运行特定 HAL 的守护进程(如果同一进程提供多个 HAL,则可以将多个属性应用到该进程)。





HIDL Java

Android O 对 Android 操作系统的架构重新进行了设计,以在独立于设备的 Android 平台与特定于设备和供应商的代码之间定义清晰的接口。 Android 已经以 HAL 接口的形式(在 hardware/libhardware 中定义为 C 标头)定义了许多此类接口。HIDL 将这些 HAL 接口替换为稳定的带版本接口,可以采用 Java(如下所述),也可以是采用 C++ 的客户端和服务器端 HIDL 接口。

HIDL 接口主要通过本机代码使用,因此 HIDL 专注于自动生成高效的 C++ 代码。不过,HIDL 接口也必须能够直接通过 Java 使用,因为有些 Android 子系统(如 Telephony)很可能具有 Java HIDL 接口。

本部分介绍了 HIDL 接口的 Java 前端,详细说明了如何创建、注册和使用服务,以及使用 Java 编写的 HAL 和 HAL 客户端如何与 HIDL RPC 系统进行交互。

作为客户端

要访问软件包 android.hardware.foo 版本 1.0 中服务名称注册为 foo-bar 的接口 IFoo,请执行以下操作:

添加库:
将以下内容添加到 Android.mk 中:
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

将以下内容添加到 Android.bp 中:
shared_libs: [
    /* … */
    "android.hardware.foo-V1.0-java",
],
该库还存在静态版:android.hardware.foo-V1.0-java-static。
将以下内容添加到您的 Java 文件中:
import android.hardware.foo.V1_0.IFoo;
...
IFoo server = IFoo.getService(); // throws exception if not available
IFoo anotherServer = IFoo.getService("second_impl");
server.doSomething(…);

提供服务

Java 中的框架代码可能需要提供接口才能接收来自 HAL 的异步回调。

警告:请勿用 Java 实现驱动程序 (HAL)。我们强烈建议您用 C ++ 实现驱动程序。

对于软件包 android.hardware.foo 版本 1.0 中的接口 IFooCallback,您可以按照以下步骤用 Java 实现接口。

用 HIDL 定义您的接口。
打开 /tmp/android/hardware/foo/IFooCallback.java 作为参考。
为您的 Java 实现创建一个新模块。
检查抽象类 android.hardware.foo.V1_0.IFooCallback.Stub,然后编写一个新类以将其扩展,并实现抽象方法。

查看自动生成的文件

要查看自动生成的文件,请运行以下命令:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport [email protected]
这些命令会生成目录 /tmp/android/hardware/foo/1.0。对于文件 hardware/interfaces/foo/1.0/IFooCallback.hal,这会生成文件 /tmp/android/hardware/foo/1.0/IFooCallback.java,其中包含 Java 接口、代理代码和存根(代理和存根均与接口吻合)。

-Lmakefile 会生成在构建时运行此命令的规则,允许您包含 android.hardware.foo-V1.0-java(-static)? 并链接到相应文件。您可以在 hardware/interfaces/update-m查看自动生成的文件akefiles.sh 中找到自动为充满接口的项目执行此操作的脚本。 本示例中的路径是相对路径;硬件/接口可能是代码树下的一个临时目录,让您能够先开发 HAL 然后再进行发布。

运行服务

HAL 提供了一个接口 IFoo,它必须通过接口 IFooCallback 对框架进行异步回调。IFooCallback 接口不按名称注册为可检测到的服务;相反,IFoo 必须包含一个诸如 setFooCallback(IFooCallback x) 的方法。

要通过软件包 android.hardware.foo 版本 1.0 设置 IFooCallback,请将 android.hardware.foo-V1.0-java 添加到 Android.mk 中。运行服务的代码为:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service you will be receiving callbacks from.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(); // throws exception if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

接口扩展

假设指定服务在所有设备上实现了接口 IFoo,那么该服务在特定设备上可能会提供在接口扩展 IBetterFoo 中实现的附加功能,即:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};
感知到扩展接口的调用代码可以使用 castFrom() Java 方法将基本接口安全地转换为扩展接口:

IFoo baseService = Foo.getService();
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service only implements the base interface.
}