Android HAL深入探索(7)hidl-gen和hidl2aidl的使用详解

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Android HAL深入探索(7)hidl-gen和hidl2aidl的使用详解

前言

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简化流程:

  1. 解析命令行参数,获取输出目录、语言类型、依赖和.hal文件信息。
  2. 创建clang::CompilerInstance对象,管理编译器组件。
  3. 设定编译器前端动作,使用自定义的HidlFrontendAction类处理AST。
  4. 对每个.hal文件编译,生成AST。
  5. 根据参数,创建相应的CodeGenerator对象,如C++头文件生成器。
  6. 遍历AST节点,生成代码文件并保存到输出目录。
  7. 释放资源并退出。

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的流程概述:

  1. 解析命令行参数,获取输出目录、依赖和.hal文件信息。
  2. 创建clang::CompilerInstance对象,管理编译器组件。
  3. 设定编译器前端动作,并使用HidlFrontendAction类处理AST。
  4. 编译每个.hal文件,生成AST。
  5. 创建AidlCodeGenerator对象,用于生成.aidl文件。
  6. 遍历AST节点,生成.aidl文件并保存到输出目录。
  7. 释放资源并退出。

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文件生成标识符,并解析依赖包。自动化生成一些代码框架 。

希望本文能为你使用这两工具提供帮助。如有疑问或建议,请留言。谢谢!

相关文章
|
2月前
|
安全 Android开发
Android HAL 层
Android HAL 层
20 1
|
2月前
|
传感器 IDE 开发工具
RK android13光感适配HAL层调用
RK android13光感适配HAL层调用
75 0
|
2月前
|
安全 编译器 API
Android HAL深入探索(5): 调试HAL报错与解决方案
Android HAL深入探索(5): 调试HAL报错与解决方案
208 1
|
2月前
|
传感器 Java Android开发
Android HAL深入探索(1): 架构概述
Android HAL深入探索(1): 架构概述
207 1
|
2月前
|
编解码 调度 Android开发
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置
71 0
|
2月前
|
Android开发 C++
Android S HAL库的编译
Android S HAL库的编译
21 0
|
2月前
|
Android开发 C++
Android P HAL层添加HIDL实例
Android P HAL层添加HIDL实例
34 0
|
2月前
|
编解码 监控 API
Android HAL深入探索(6): HIDL 添加SELinux 完整调试过程
Android HAL深入探索(6): HIDL 添加SELinux 完整调试过程
278 0
|
Java Android开发
Android10.0(Q) HAL层 light2.0 改动记录及排错过程
Android10.0(Q) HAL层 light2.0 改动记录及排错过程
885 0