当前位置:   article > 正文

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

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)?,用于创建输出。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 生成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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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文件。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

例如,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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/255951
推荐阅读
相关标签
  

闽ICP备14008679号