Android HIDL (Java)

HAL接口定义语言或HIDL(发音为“hide-l”)是一种接口描述语言(IDL),用于指定HAL与其用户之间的接口。 它允许指定类型和方法调用,并将其收集到接口和包中。 更广泛地说,HIDL是可以独立编译的代码库之间进行通信的系统。
HIDL旨在用于进程间通信(IPC)。

以上是来自Android官方文档。学习或者尝试使用过HIDL的coder一定都看过Android HIDL,所以都会了解到,定义了HIDL接口之后,我们可以用C++和JAVA两种方式去写HIDL接口的实现,大多数的HIDL接口都会用C++去写接口的具体实现,并通过.rc文件来start接口服务,这种实现方式很通用,官网和许多博客有具体介绍,如果你需要在native层写接口实现,那可以移步google去搜索一下。

而JAVA实现方式,一是官网没有特别具体的介绍,二是很少有这种需求也很少有博主用过这种方式,而我在工作中恰好有这样一个需求: 就是要通过HIDL的JAVA实现server端,从而把Android framework的API暴露给native层。
经过一番尝试终于实现了需求,所以想要通过这篇博文记录一下自己的收获和实现过程中遇到的问题。


定义接口文件

首先根据官方文档提供的格式写好自己的.hal接口文件,并通过hild-gen生成相应的Android.bp 和 Android.mk文件。
两个文件会相应build出很重要的C++和JAVA的Shared Library,这两个库是供服务端和客户算使用的。

  • 这里我曾遇到的问题是Android.bp有问题,build不出相应的C++的Shared Library。
    • 解决办法是修改/interfaces/下面的所有Android.bp,确保他们都加了你的新接口的路径(eg. myinterface/1.0),只要有一层缺了该路径,就会导致build不出你要的C++ Library.

如果运行hile-gen时,显示error找不到command, 需要先在/system/tools/下 运行

1
m hidl-gen

JAVA 接口的实现

用JAVA实现接口,有点类似于AIDL的借口实现,我们需要实现一个服务端apk,并在Android开机启动时保证成功调起接口的服务,以便各个客户端使用。

  • 首先有了相应的.bp和.mk文件,就可以得到相应的C++ 和 JAVA的Library,我们需要在JAVA server apk 的makefile 中引入Java library,
  • 其次,server端必须要有一个一直在运行的进程在,所以我们需要一个activity或者service进程来承载整个server端,并且需要在监听到开机广播后启用它,并完成工作:registerAsService() //让我们定义的接口的HwService注册到HwServiceManager中

    • 类似于AIDL,我们同样需要实现类MyInterface extends IMyInterface.Stub,之后Override所有接口方法并实现具体的function。下面是registerAsService()具体例子:

      1
      2
      MyInterface testService = new MyInterface();
      testService.registerAsService("MyTestService");
    • 这里遇到过的问题是Service注册之后 client端偶尔会得到空的Service。因为当时只是试验,所以就随意的在service.onStartCommand()中加了上面两行代码。 解决办法就是要把MyInterface的对象作为Service的成员变量,这样就不会偶尔被回收了…

  • 第三,修改 DEVICE MANIFEST 和 SELINUX POLICY。只有修改过这两项,你的service才允许被注册到HwServiceManager中。Device Manifest 可以参考 VINTF Object Data Link用相同的格式声明你自己的接口。如果你用C++实现server端这一条同样需要被执。

    • 关于SELinux 就不具体介绍了,可以根据相应的SELinux denial logs来修改你的SELinux policy。在这之前可以用下面的命令行跳过SELinux 的拦截。
      1
      adb shell setenforce 0

CLIENT 端测试

Client端不区分JAVA实现的还是C++实现的接口。Client端实现很简单,算是HIDL的优点之一,只要调用

1
2
IMyInterface.getService("MyTestService") //JAVA
IMyInterface::getService("MyTestService") //C++

JAVA Client端同时也需要引用JAVA Library。如果有相应的Callback, 需要像AIDL一样在Client端有一个Callback类 extends ICallback.Stub.

C++ 的Client端 同样的需要加C++的Shared Library.


总结

通过HIDL JAVA server端封装某些framework API,native层就可以通过HIDL接口调用相应的方法,从而调用到framework API了,除了缩短升级时间的优点,就这一个功能也是非常有用的。