Android HIDL 详解

前言

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

HIDL简介

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

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

HIDL对比与AIDL

在这里插入图片描述

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<INfc>();
}

如果是这样的话,需要在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 <android/hardware/nfc/1.0/INfc.h>
#include <hidl/LegacySupport.h>
#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<INfc> 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 中使用的共享库

在这里插入图片描述

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 实例

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android HIDL(Hardware Interface Definition Language)是一种用于定义硬件抽象层(HAL)接口的语言。它旨在提供一个标准化的接口规范,以促进硬件和软件之间的互操作性。 根据官方网站的介绍,Android HIDL允许将早期版本的Android设备升级为使用Android O。通过将传统的HAL封装到新的HIDL接口中,HAL和Android框架之间的通信变得更加透明。这种封装可以在绑定模式和同进程(直通)模式下提供HAL,并具有跨设备兼容性的优势。 Android 8.0引入了Treble项目,旨在重新设计Android操作系统框架,以解决系统版本碎片化问题和复杂的系统更新流程。Treble引入了HIDL作为其核心组件之一,以提供更好的硬件和软件兼容性。 综上所述,Android HIDL是一种用于定义硬件抽象层接口的语言,它在Android O及其后续版本中起到了重要的作用,帮助解决Android系统版本碎片化和系统更新的难题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Android HIDL(1) ---- 概述](https://blog.csdn.net/h_8410435/article/details/126283950)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Android HIDL 详解](https://blog.csdn.net/ismartv_dagou2/article/details/124361229)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值