前言

Android Treble 简介 一文中提到了Android O之后使用Treble的架构,为了解决Android 系统的碎片化问题和提高系统更新的效率,减少了framework 和HAL 的耦合性,进而引出了HIDL 的概念。本文将详细的总结HIDL 的使用。

本文代码基于:Android P

HIDL简介

HIDL 全称为HAL interface definition language(发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。

HIDL 的目标是,框架可以在无需重新构建 HAL 的情况下进行替换。HAL 将由供应商或 SOC 制造商构建,放置在设备的 /vendor 分区中,这样一来,框架就可以在其自己的分区中通过 OTA 进行替换,而无需重新编译 HAL,这也是Project Treble框架设计而诞生的。

HIDL对比与AIDL

相同不同

AIDLHIDL

都是使用Binder 机制进行IPC

都使用service manager进行管控

文件的后缀为 aidl文件的后缀为 hal

适用于框架/应用 之间的IPC

适用于框架/HAL 进程之间的IPC

适用于OEM 进程之间的IPC

使用设备节点为/dev/binder

使用设备节点为/dev/hwbinder

或 /dev/vndbinder

语言实现方式不同(例如数据类型、types.hal等)

HIDL 设计原则

HIDL 的目标是,框架可以在无需重新构建 HAL 的情况下进行替换。HAL 将由供应商或 SOC 制造商构建,放置在设备的 /vendor 分区中,这样一来,框架就可以在其自己的分区中通过 OTA 进行替换,而无需重新编译 HAL。

HIDL 设计在以下方面之间保持了平衡:

互操作性。在可以使用各种架构、工具链和编译配置来编译的进程之间创建可互操作的可靠接口。HIDL 接口是分版本的,发布后不得再进行更改。

效率。HIDL 会尝试尽可能减少复制操作的次数。HIDL 定义的数据以 C++ 标准布局数据结构传递至 C++ 代码,无需解压,可直接使用。此外,HIDL 还提供共享内存接口;由于 RPC 本身有点慢,因此 HIDL 支持两种无需使用 RPC 调用的数据传输方法:共享内存和快速消息队列 (FMQ)。

直观。通过仅针对 RPC 使用 in 参数,HIDL 避开了内存所有权这一棘手问题(请参阅 Android 接口定义语言 (AIDL));无法从方法高效返回的值将通过回调函数返回。无论是将数据传递到 HIDL 中以进行传输,还是从 HIDL 接收数据,都不会改变数据的所有权,也就是说,数据所有权始终属于调用函数。数据仅需要在函数被调用期间保留,可在被调用的函数返回数据后立即清除。

HIDL 类型

Passthrough

兼容之前的HAL 使用方式(在同一个进程)。

要将运行早期版本的 Android 的设备更新为使用 Android O,您可以将惯用的(和旧版)HAL 封装在一个新 HIDL 接口中,该接口将在绑定式模式和同进程(直通)模式提供 HAL。这种封装对于 HAL 和 Android 框架来说都是透明的。

直通模式仅适用于 C++ 客户端和实现。运行早期版本的 Android 的设备没有用 Java 编写的 HAL,因此 Java HAL 自然而然经过 Binder 化。

Binderized

使用Binder 方式进行IPC(在不同进程)。

在使用HIDL 的时候需要有两个软件包,一个是FQName-impl,一个是FQName-service。FQName-impl一般是HAL 实现的部分或者是链接HAL的部分,FQName-service 就是service 端。

当然,为了兼容之前的HAL 旧版本和接口的统一,FQName-service 也可以是简单的直通(passthrough)模式。例如:

int main() {

return defaultPassthroughServiceImplementation();

}

如果是这样的话,需要在FQName-impl 中暴露HIDL_FETCH_*接口,例如:(这里用NFC 为例,HIDL 文件名为INfc.hal)

extern "C" INfc* HIDL_FETCH_INfc(const char* name);

当然,如果采用进程的方式FQName-service 的main 函数修改为:

#define LOG_TAG "android.hardware.cfc@1.0-service"

#include

#include

#include "Nfc.h"

using android::hardware::nfc::V1_0::INfc;

using android::hardware::nfc::V1_0::implementation::Nfc;

using android::hardware::defaultPassthroughServiceImplementation;

using android::hardware::configureRpcThreadpool;

using android::hardware::joinRpcThreadpool;

using android::sp;

int main(int /* argc */, char* /* argv */ []) {

// This function must be called before you join to ensure the proper

// number of threads are created. The threadpool will never exceed

// size one because of this call.

configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);

sp nfc = new Nfc();

if(android::OK != nfc->registerAsService())

return 1; // or handle error

}

// Adds this thread to the threadpool, resulting in one total

// thread in the threadpool. We could also do other things, but

// would have to specify ‘false‘ to willJoin in configureRpcThreadpool.

joinRpcThreadpool();

return 1; // joinRpcThreadpool should never return

}

如果有一个 INfc,您可以调用 sp INfc::getService(string name, bool getStub),以获取对 INfc 实例的访问权限。如果 getStub 为 True,则 getService 会尝试仅在直通模式下打开 HAL。如果 getStub 为 False,则 getService 会尝试找到 Binder 化服务;如果未找到,则它会尝试找到直通式服务。除了在 defaultPassthroughServiceImplementation 中,其余情况一律不得使用 getStub 参数。(搭载 Android O 的设备是完全 Binder 化的设备,因此不得在直通模式下打开服务。)

HIDL 工具 hidl_gen

代码目录:system/tools/hidl

cc_library_host_shared {

name: "libhidl-gen",

defaults: ["hidl-gen-defaults"],

srcs: [

"Annotation.cpp",

"ArrayType.cpp",

"CompoundType.cpp",

"ConstantExpression.cpp",

"DeathRecipientType.cpp",

"DocComment.cpp",

"EnumType.cpp",

"HandleType.cpp",

"HidlTypeAssertion.cpp",

...

在使用的时候可以直接使用out/host/linux-x86/bin/hidl-gen 或者使用:

./build/setenv.sh

lunch

lunch 之后可以直接使用hidl-gen,因为这个时候已经将bin 的目录添加到了环境变量中了

详细hidl-gen 使用可以看另一篇博文:Android HIDL 中 hidl-gen使用

HIDL 代码规范

HIDL 是接口描述语言,只要是编程语言就会涉及到编写的规范,例如文件名、包名、变量、接口、数据类型、版本等等。

详细的代码规范可以看另一篇博文:Android HIDL 编程规范

HIDL 接口与package

HIDL 是围绕接口进行编译的,接口是面向对象的语言使用的一种用来定义行为的抽象类型。每个接口都是软件包的一部分。

例如:

package android.hardware.nfc@1.0;

import INfcClientCallback;

interface INfc {

@entry

@callflow(next={"write", "coreInitialized", "prediscover", "powerCycle", "controlGranted"})

open(INfcClientCallback clientCallback) generates (NfcStatus status);

要使用接口INfc,必须要确定其package以及在interface 下定义所使用的接口。通过Android HIDL 编程规范 得知package的定义是有一定的规范的(由PACKAGE、MODULE、SUBMODULE、VERSION等组成),interface 的定义也有特定的规则。

再例如:nfc 中的types.hal

package android.hardware.nfc@1.0;

@export(name="", value_prefix="HAL_NFC_", value_suffix="_EVT")

enum NfcEvent : uint32_t {

OPEN_CPLT = 0,

CLOSE_CPLT = 1,

POST_INIT_CPLT = 2,

PRE_DISCOVER_CPLT = 3,

REQUEST_CONTROL = 4,

RELEASE_CONTROL = 5,

ERROR = 6

};

types.hal 定义的是需要使用的数据类型,并没有定义interface,这也是types.hal 的特殊之处。

详细内容可以看另一篇博文:Android HIDL 接口和软件包使用

HIDL 中使用的共享库

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

HIDL 中的数据类型

在另一篇博文会详细描述HelloWorld 在HIDL中的使用:Android HIDL 中的数据类型

HIDL 中的函数

在另一篇博文会描述HIDL 中函数的使用:Android HIDL 中的函数

HIDL 的使用

在另一篇博文会详细描述HelloWorld 在HIDL中的使用:Android HIDL 实例

HIDL 生成文件

在编译HIDL 文件,会在out/soong/.interfaces/PACKAGE/MOUDLE/VERSION/下生成对应的文件。例如Android HIDL 实例 中的helloworld 是在hardware/interfaces下创建,所以生成的文件路径为:out/soong/.intermediates/hardware/interfaces/helloworld/1.0

当然实际生成的文件是根据hidl 对应的Android.bp来的,例如在Android.bp 中设定gen_java_constants为true,会生成一个Constants 的JAVA 类。

android.hardware.helloworld@1.0_genc++_headers 目录就是为Client 和impl 准备的头文件。

android.hardware.helloworld@1.0_genc++ 目录为binder 使用的proxy 和 stub类(或者native 中的Bp 和Bn类)

android.hardware.helloworld-V1.0-java 是为Java 调用生成的java lib

android.hardware.helloworld-V1.0-java_gen_java 是为Java 调用生成的对应的Java 类

详细信息看博文:Android HIDL 实例

————————————————

版权声明:本文为CSDN博主「私房菜」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/shift_wwx/java/article/details/86514997

java调用hidl_Android HIDL 详解相关推荐

  1. java调用python接口详解

    在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件(推荐) 调用python脚本中的函数 准备工作 ...

  2. JAVA调用SQL存储过程详解

    1使用不带参数的存储过程 使用 JDBC 驱动程序调用不带参数的存储过程时,必须使用 call SQL 转义序列.不带参数的 call 转义序列的语法如下所示: {call procedure-nam ...

  3. java有返回值的方法回调_java调用回调机制详解

    调用和回调机制 在一个应用系统中, 无论使用何种语言开发, 必然存在模块之间的调用, 调用的方式分为几种: 1.同步调用 同步调用是最基本并且最简单的一种调用方式, 类A的方法a()调用类B的方法b( ...

  4. Java单元测试之JUnit4详解

    2019独角兽企业重金招聘Python工程师标准>>> Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @B ...

  5. Java编程配置思路详解

    Java编程配置思路详解 SpringBoot虽然提供了很多优秀的starter帮助我们快速开发,可实际生产环境的特殊性,我们依然需要对默认整合配置做自定义操作,提高程序的可控性,虽然你配的不一定比官 ...

  6. 你真的弄明白了吗?Java并发之AQS详解

    你真的弄明白了吗?Java并发之AQS详解 带着问题阅读 1.什么是AQS,它有什么作用,核心思想是什么 2.AQS中的独占锁和共享锁原理是什么,AQS提供的锁机制是公平锁还是非公平锁 3.AQS在J ...

  7. Java RMI远程方法调用详解

    Java RMI远程方法调用详解     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51992182 一.Java R ...

  8. Java之toString()方法详解

    Java之toString()方法详解 Java中 toString()方法在Object类中和Intent类中都有定义,作用类似,但显示形式有点区别 一.Object类中toString()方法 t ...

  9. Java中JDBC连接数据库详解

    今天动力节点java学院小编分享的是JDBC连接数据库的相关知识,希望通过看过此文,各位小伙伴对DBC连接数据库有所了解,下面就跟随小编一起来看看JDBC连接数据库的知识吧. 一.JDBC连接数据库概 ...

最新文章

  1. WinForm下ComboBox获取绑定对象集的SelectedValue补充
  2. Unity 好消息,中文版Unity来啦!!!
  3. RHEL6基础之十八Linux中Kill进程的方法
  4. 服务程序增加系统托盘
  5. php浏览器类型检测工具,php检测客户端浏览器类型的简单示例
  6. 牛客题霸 [ 最长回文子串] C++题解/答案
  7. java setlocation_Java Point.setLocation方法代碼示例
  8. 或为红米8A 卢伟冰确认将推出5000mAh新机
  9. CentOS(rsync+crond实现定时备份)
  10. LeetCode 120. 三角形最小路径和(动态规划)
  11. Node.js的异步I/O
  12. RocketDock 安装
  13. smtp服务器组件,本机搭建虚拟SMTP服务器教程
  14. rtmp播放器,使用videojs播放,稳定
  15. 怎么用8uftp上传网站,利用8Uftp上传自己的网页只需8步
  16. 控制系统设计专题(三)——自抗扰控制算法(下)
  17. 软件测试需要掌握哪些技术?
  18. Window10系统启动问题——无法启动问题
  19. AWS免费套餐服务器部署NET CORE网站
  20. 吴恩达机器学习MATLAB代码笔记(1)梯度下降

热门文章

  1. word2010 数学公式/联立方程/大括号内方程组如何左对齐?
  2. 鸿蒙二代好用吗,鸿蒙2.0使用体验_鸿蒙2.0使用感受
  3. 项目组成员总是无法完成任务,咋办?
  4. 占豪收评--天然气荒
  5. 教你快速学习python图像识别入门
  6. 拆解康耐特光学赴港上市:业绩增速有所放缓,持续增长能力存疑
  7. Echarts 折线图间隔显示数据
  8. springboot+教学系统 毕业设计-附源码191733
  9. 关于win10和手机的数据线和蓝牙连接
  10. 看图就懂:为什么L1正则化比L2正则化更容易得到稀疏解?为什么L2正则化可以用于防止过拟合?