前言
Android系统开发中硬件抽象层(HAL),它是一组接口和数据类型的定义,用于描述硬件设备的功能和属性,从而实现硬件和软件的解耦。为了方便使用HAL,Android提供了一种专门的语言,叫做HIDL,它是一种基于IDL(接口定义)的语言,可以用于定义HAL接口和数据类型,并生成不同语言和类型的代码文件,如C++、Java、Android.bp等。
本文将介绍两个与HIDL相关的工具:hidl-gen和hidl2aidl。hidl-gen是一个用于生成HIDL代码文件的工具,它可以根据.hal文件中定义的接口和数据类型生成对应的代理类、存根类、回调类等,并提供接口实现和测试的框架和示例代码。hidl2aidl是一个用于转换HIDL代码文件为.aidl文件的工具,它可以根据.hal文件中定义的接口和数据类型生成对应的.aidl文件,并尽可能保持原有的结构和语义。
本文将学习hidl-gen和hidl2aidl的基本用法、生成的代码文件、实现原理、区别和联系等内容,让我们更好地理解和使用这两个工具。
hidl-gen的使用说明
hidl-gen的基本用法
hidl-gen是一个用于生成HIDL代码文件的工具,它可以根据.hal文件中定义的接口和数据类型生成对应的代理类、存根类、回调类等,并提供接口实现和测试的框架和示例代码。hidl-gen接受以下参数:
- -h: 打印这个菜单。 - -L <language>: 可以选择以下选项: - check : 解析接口,检查是否有效,但不写入任何文件。 - c++ : (内部) (已弃用) 生成C++接口文件,用于与HIDL接口通信。 - c++-headers : (内部) 生成C++头文件,用于与HIDL接口通信。 - c++-sources : (内部) 生成C++源文件,用于与HIDL接口通信。 - export-header : 根据@export枚举生成一个头文件,用于维护旧代码。 - c++-impl : 生成HIDL接口的C++实现的模板和示例代码(为了方便)。 - c++-impl-headers: c++-impl,但只有头文件。 - c++-impl-sources: c++-impl,但只有源文件。 - c++-adapter : 将一个x.(y+n)接口转换为一个x.y接口的适配器。 - c++-adapter-headers: c++-adapter,但只有辅助头文件。 - c++-adapter-sources: c++-adapter,但只有辅助源文件。 - c++-adapter-main: c++-adapter,但只有适配器二进制源文件。 - java : (内部) 生成Java库,用于在Java中与HIDL接口通信。 - java-impl : 生成HIDL接口的Java实现的模板和示例代码(为了方便)。 - java-constants : (内部) 类似于export-header,但是针对Java(如果存在@export,则-Lmakefile总是创建)。 - vts : (内部) 生成vts proto文件,用于在vtsd中使用。 - makefile : (已移除) 用于为-Ljava和-Ljava-constants生成makefile。 - androidbp : (内部) 生成Soong bp文件,用于-Lc++-headers、-Lc++-sources、-Ljava、-Ljava-constants和-Lc++-adapter。 - androidbp-impl : 生成-Lc++-impl创建的实现的模板bp文件。 - hash : 将接口的哈希值以`current.txt`格式打印到标准输出。 - function-count : 打印包或接口添加的函数总数。 - dependencies : 打印所有依赖类型。 - inheritance-hierarchy: 将继承类型的层次结构作为一个JSON对象打印出来。 - format : 格式化.hal文件 - -O <owner>: 模块的所有者,用于-Landroidbp(-impl)?. - -o <output path>: 文件输出位置。 - -p <root path>: Android构建根目录,默认为$ANDROID_BUILD_TOP或pwd。 - -R: 如果在-r中没有指定,则不添加默认包根目录。 - -r <package:path root>: 例如,android.hardware:hardware/interfaces. - -v: 输出详细信息。 - -d <depfile>: depfile写入位置。 FQNAME是.hal文件或包名(以@开头)的完全限定名,格式为PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?,用于创建输出。
hidl-gen生成的代码文件
hidl-gen可以根据hardware/interfaces/can_bus/1.0/ICanBus.hal文件生成不同类型的代码文件,以下是一些常用的命令:
- 生成C++头文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Lc++-headers \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree . ├── default │ └── android │ └── hardware │ └── can_bus │ └── 2.0 │ ├── BnHwCanBus.h │ ├── BpHwCanBus.h │ ├── BsCanBus.h │ ├── ICanBus.h │ └── IHwCanBus.h └── ICanBus.hal 5 directories, 6 files
- 生成C++源文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Lc++-sources \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 . ├── default │ └── android │ └── hardware │ └── can_bus │ └── 2.0 │ ├── CanBusAll.cpp └── ICanBus.hal
- 生成C++实现文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Lc++-impl \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree . ├── default │ ├── android │ │ └── hardware │ │ └── can_bus │ │ └── 2.0 │ │ └── CanBusAll.cpp │ ├── CanBus.cpp │ └── CanBus.h └── ICanBus.hal
- 生成Android.bp文件,并将其存放在hardware/interfaces/can_bus/2.0/目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Landroidbp \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree . ├── Android.bp └── ICanBus.hal
- 生成Android.bp实现文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Landroidbp-impl \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree ├── default │ ├── Android.bp └── ICanBus.hal
- 生成Java文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree ├── default │ ├── ICanBus.java └── ICanBus.hal
- 生成Java实现文件,并将其存放在hardware/interfaces/can_bus/2.0/default目录下:
hidl-gen -o hardware/interfaces/can_bus/2.0/default -Ljava-impl \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport \ android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree ├── default │ ├── CanBus.java └── ICanBus.hal
hidl-gen生成代码的实现原理
hidl-gen
使用基于 LLVM 的 Clang 库来解析 .hal
文件并生成 AST。然后它会遍历这个 AST 并使用相应的代码生成器来产生目标代码。(涉及到的非专业词 我也不是很懂,总之 diao)
hidl-gen简化流程:
- 解析命令行参数,获取输出目录、语言类型、依赖和.hal文件信息。
- 创建clang::CompilerInstance对象,管理编译器组件。
- 设定编译器前端动作,使用自定义的HidlFrontendAction类处理AST。
- 对每个.hal文件编译,生成AST。
- 根据参数,创建相应的CodeGenerator对象,如C++头文件生成器。
- 遍历AST节点,生成代码文件并保存到输出目录。
- 释放资源并退出。
hidl2aidl的使用说明
hidl2aidl的基本用法
如果没有这个工具在源代码下执行m hidl2aidl 编译出来就可以了。
hidl2aidl是一个用于将.hal文件转换为.aidl文件的工具,它可以根据.hal文件中定义的接口和数据类型生成对应的.aidl文件,并尽可能保持原有的结构和语义。hidl2aidl接受以下参数:
- -o <output path>:指定输出目录,用于存放生成的.aidl文件。 - -h: 打印这个菜单。 - -p <root path>:指定Android构建根目录,默认为$ANDROID_BUILD_TOP或pwd。 - -R: 如果在-r中没有指定,则不添加默认包根目录。 - -r <package:path root>:指定依赖包的位置,用于解析.hal文件中的import语句。可以有多个-r参数,每个参数表示一个包和一个位置,用冒号分隔。位置可以是相对路径或绝对路径。例如,android.hardware:hardware/interfaces。 - -v: 输出详细信息。 - -d <depfile>:指定depfile写入位置。 FQNAME是.hal文件或包名(以@开头)的完全限定名,格式为PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?,用于转换为.aidl文件。
例如,hidl2aidl可以根据android.hardware.smart_home@2.0包中的所有.hal文件生成.aidl文件,并将其存放在hardware/interfaces/smart_home/2.0/aidl目录下。:
hidl2aidl -o hardware/interfaces/can_bus/2.0/aidl -r android.hardware:hardware/interfaces android.hardware.can_bus@2.0 hardware/interfaces/can_bus/2.0$ tree . ├── aidl │ └── android │ └── hardware │ └── can_bus2 │ ├── conversion.log │ └── ICanBus.aidl
hidl2aidl生成的.aidl文件
hidl2aidl会根据.hal文件中定义的接口和数据类型生成对应的.aidl文件,并尽可能保持原有的结构和语义。例如:
- 如果.hal文件中定义了一个接口ICanBus,并且有四个方法dev_openCan、dev_closeCan、dev_sendCan和dev_receiveCan,则hidl2aidl会生成一个ICanBus.aidl文件,并定义一个ICanBus接口,并且有四个方法dev_openCan、dev_closeCan、dev_sendCan和dev_receiveCan。以下是生成的aidl文件内容:
// FIXME: license file if you have one package android.hardware.can_bus2; interface ICanBus { // Adding return type to method instead of out param int fd since there is only one return value. int dev_openCan(in String canx); // Adding return type to method instead of out param int ret since there is only one return value. int dev_closeCan(in int fd); // Adding return type to method instead of out param int ret since there is only one return value. int dev_sendCan(in int fd, in long canid, in long eff, in long rtr, in int len, in int[] data); // Adding return type to method instead of out param byte[] data since there is only one return value. byte[] dev_receiveCan(in int fd); }
如果复杂一点的hal文件 生成出来的就很离谱 ,我最开始是手写的,发现像复杂的内容完全写不了一点
hidl2aidl转换代码的实现原理
hidl2aidl也是一个基于LLVM的工具,利用clang库解析.hal文件,生成AST,并通过AidlCodeGenerator类生成.aidl文件。
hidl2aidl的流程概述:
- 解析命令行参数,获取输出目录、依赖和.hal文件信息。
- 创建clang::CompilerInstance对象,管理编译器组件。
- 设定编译器前端动作,并使用HidlFrontendAction类处理AST。
- 编译每个.hal文件,生成AST。
- 创建AidlCodeGenerator对象,用于生成.aidl文件。
- 遍历AST节点,生成.aidl文件并保存到输出目录。
- 释放资源并退出。
hidl-gen和hidl2aidl的区别和联系
hidl-gen与hidl2aidl都基于LLVM,使用clang库解析.hal文件生成代码。它们的主要区别是:
- hidl-gen支持生成多种语言的代码(如C++、Java)并提供代理、存根、回调类等,还能生成接口实现和测试框架;
- hidl2aidl仅生成.aidl文件和接口及数据类型定义。
它们的共同点是:
- 两者都服务于Android HIDL开发,帮助我们使用HIDL定义HAL接口和数据类型。
- 根据.hal文件,它们都能生成命名空间、类名等标识符,并解析依赖包。
总结
文章探讨了两个HIDL工具:hidl-gen和hidl2aidl的基础常用方法。这2个工具都是为了帮助我们使用HIDL定义HAL接口和数据类型。它们根据.hal文件生成标识符,并解析依赖包。自动化生成一些代码框架 。
希望本文能为你使用这两工具提供帮助。如有疑问或建议,请留言。谢谢!