首页 > 其他分享 >hidl实现hal

hidl实现hal

时间:2024-05-22 18:08:52浏览次数:25  
标签:hal service 实现 hidl hardware 1.0 android uint32 galaxy

一、前言

正如 Android HIDL 概述 一文中简单的对 HIDL 的演进和新架构下 Framework 与 Hal 层之间的通信做了介绍。但是笔者的目的是想完整的实现从上层 APP 到 hal 之间通信过程,由此可以更加深刻的理解这种机制。

   

二、Binderized Mode (绑定式)简介

从上文介绍,我们知道 绑定模式 是 google 为了向前兼容而定义的一种类型,且 Android 8.0 及后续版本的设备都必须只支持这种模式。这种模式下 Framework 与 Hal 分别位于不同的进程中,其实从具体实现来讲这种模式也更应该被称为 Binder 化的直通式。本文将通过这种方式实现一个 HIDL 服务。

三、环境/工具准备

  • Ubuntu 20.04 TLS
  • Android 源码:Android 9.0,编译烧录详见 Android源码编译烧录
  • hidl-gen 工具:Android 系统自带,需要配置一下环境变量

四、HIDL 实现

本文目的是实现一个具有 加减乘除 运算的 HIDL 服务,命名为 银河一号(GalaxyOne)。HIDL用起来非常简单,在系统源码中的 hardware/interfaces 目录下有很多的 HIDL,我们仿照其他 HIDL 来创建自己的目录:hardware/interfaces/galaxy_one/1.0

4.1 创建 IGalaxyOne.hal 文件

hardware/interfaces/galaxy_one/1.0/IGalaxyOne.hal

这里定义了四种基本的运算:加、减、乘、除,这是上层调用 HAL 的入口,内容如下:

package [email protected];

interface IGalaxyOne{

    //加法
    add(uint32_t a,uint32_t b) generates (uint32_t result);
    //减法
    sub(uint32_t a,uint32_t b) generates (uint32_t result);
    //乘法
    mul(uint32_t a,uint32_t b) generates (uint32_t result);
    //除法
    div(uint32_t a,uint32_t b) generates (uint32_t result);
    
};

4.2 hidl-gen 生成 HIDL 框架

在使用 hidl-gen 之前需要先做两件事:
1、hidl-gen 由 Android 提供,使用之前需要先配置一下系统路径,如我这里所做的:

# vim ~/.bashrc
export PATH=/home/zsk/AOSP/out/soong/host/linux-x86/bin:$PATH

2、Ubuntu 新的终端窗口必须先设定一些 Android 环境变量:

source build/envsetup.sh
lunch aosp_sailfish-userdebug  // lunch mode 根据需求修改
make hidl-gen

配置完成之后在 源码根目录 下执行如下命令:

  [email protected]
  LOC=hardware/interfaces/galaxy_one/1.0/default/
  hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
  hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

命令执行成功之后会发现在 hardware/interfaces/galaxy_one/1.0 目录下多了一个 default 目录,进入之后发现有如下文件:

 

之后执行 update-makefiles.sh 脚本来为 HIDL 生成对应的 Android.bp 文件,此脚本位于 hardware/interfaces 目录下,同样可在源码根目录下执行:

./hardware/interfaces/update-makefiles.sh
 

 

接下来我们需要添加两个空文件:

touch hardware/interfaces/galaxy_one/1.0/default/[email protected]
touch hardware/interfaces/galaxy_one/1.0/default/service.cpp

完成之后,整个工程结构如下所示:

 

4.3 调用流程

上述过程已经将 HIDL 服务所需要的全本文件配置完成,虽然其中很多文件是空的,或者没有具体实现,我们现在先放在一边,先来对整体的调用流程及各个文件的功效略作说明。

 

 

Binder 化直通式
  • Application:指上层应用
  • JNI:指 framework 层,getService 获取 hal 层 service
  • [email protected]:由 IGalaxyOne.hal 生成的接口库,由 hardware/interfaces/galaxy_one/1.0/Android.bp 通过 IGalaxyOne.hal 生成,这样只要这个接口库不变,那么 framework 的更新和 hal 层就隔绝开了
  • [email protected]:设备开机时通过 rc 文件启动此服务
  • galaxy_hal_service:service的名,可通过国 start galaxy_hal_service 启动服务
  • [email protected]:实现库,上层应用的最终调用

关于 Application、JNI 这两层内容会在稍后用两个篇幅去分析,此处暂不理会。现在我们就着这个调用过程将需要的内容补充完成。

4.3.1 接口库生成

[email protected],由 hardware/interfaces/galaxy_one/1.0/Android.bp 通过 IGalaxyOne.hal 生成,Android.bp 文件是在上面一些列命令执行之后生成,而接口库是当我们最终执行编译模块时生成,可以说这个过程不需要我们手动参与,Android.bp 内容如下:

// This file is autogenerated by hidl-gen -Landroidbp.

hidl_interface {
    name: "[email protected]",   //此处设置接口库的名字
    root: "android.hardware",
    vndk: {
        enabled: true,
    },
    srcs: [
        "IGalaxyOne.hal",
    ],
    interfaces: [
        "[email protected]",
    ],
    gen_java: true,
}

4.3.2 实现库生成

[email protected],由 hardware/interfaces/galaxy_one/1.0/default/Android.bp 通过 GalaxyOne.cpp 生成,注意这个 Android.bp 文件是位于 default 目录下,同样的在最后模块编译时生成,原始内容如下:

cc_library_shared {
    name: "[email protected]",
    relative_install_path: "hw",
    proprietary: true,
    srcs: [
        "GalaxyOne.cpp",
    ],
    shared_libs: [    //这里可以添加我们需要的库
        "liblog",     
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
        "libutils",
        "[email protected]",
    ],
}
4.3.3 GalaxyOne.cpp 实现

4.3.2 中,实现库是由 GalaxyOne.cpp 编译而成,现在我们来将此文件补充完成:

GalaxyOne.h:
Binder化直通式,同样需要将 HIDL_FETCH_XXX 打开,至于原因我们在后面会提及

#ifndef ANDROID_HARDWARE_GALAXY_ONE_V1_0_GALAXYONE_H
#define ANDROID_HARDWARE_GALAXY_ONE_V1_0_GALAXYONE_H

#include <android/hardware/galaxy_one/1.0/IGalaxyOne.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <log/log.h>

namespace android {
namespace hardware {
namespace galaxy_one {
namespace V1_0 {
namespace implementation {

using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;

struct GalaxyOne : public IGalaxyOne {
    // Methods from ::android::hardware::galaxy_one::V1_0::IGalaxyOne follow.
    Return<uint32_t> add(uint32_t a, uint32_t b) override;
    Return<uint32_t> sub(uint32_t a, uint32_t b) override;
    Return<uint32_t> mul(uint32_t a, uint32_t b) override;
    Return<uint32_t> div(uint32_t a, uint32_t b) override;

    // Methods from ::android::hidl::base::V1_0::IBase follow.

};

// FIXME: most likely delete, this is only for passthrough implementations
 extern "C" IGalaxyOne* HIDL_FETCH_IGalaxyOne(const char* name);

}  // namespace implementation
}  // namespace V1_0
}  // namespace galaxy_one
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_GALAXY_ONE_V1_0_GALAXYONE_H

GalaxyOne.cpp:

#include "GalaxyOne.h"

namespace android {
namespace hardware {
namespace galaxy_one {
namespace V1_0 {
namespace implementation {

// Methods from ::android::hardware::galaxy_one::V1_0::IGalaxyOne follow.
Return<uint32_t> GalaxyOne::add(uint32_t a, uint32_t b) {
    uint32_t result = a + b;
    ALOGE("GalaxyOne::add  a = %d,b = %d,result = %d",a,b,result);
    return result;
}

Return<uint32_t> GalaxyOne::sub(uint32_t a, uint32_t b) {
    uint32_t result = a - b;
    ALOGE("GalaxyOne::sub  a = %d,b = %d,result = %d",a,b,result);
    return result;
}

Return<uint32_t> GalaxyOne::mul(uint32_t a, uint32_t b) {
    uint32_t result = a * b;
    ALOGE("GalaxyOne::mul  a = %d,b = %d,result = %d",a,b,result);
    return result;
}

Return<uint32_t> GalaxyOne::div(uint32_t a, uint32_t b) {
    uint32_t result = a / b;
    ALOGE("GalaxyOne::div  a = %d,b = %d,result = %d",a,b,result);
    return result;
}

// Methods from ::android::hidl::base::V1_0::IBase follow.
IGalaxyOne* HIDL_FETCH_IGalaxyOne(const char* /* name */) {
    ALOG("galaxy_one service init success....");
    return new GalaxyOne();
}

}  // namespace implementation
}  // namespace V1_0
}  // namespace galaxy_one
}  // namespace hardware
}  // namespace android

4.3.3 模块编译

现在除了需要的 rc 文件没有补充、galaxy-hal-service 服务没有生成外其余均已配置好了,现在进行编译生成对应的库。进入根目录下执行如下命令:(注意是在刚刚执行过的 source build/envsetup.shlunch 的窗口下编译,若是新窗口则需要重新执行这两条命令)

mmm  hardware/interfaces/galaxy_one/1.0

此时应该可以在 out/tartget/product/XXX/vendor/lib64/hwout/tartget/product/XXX/system/lib64/hw 目录下找到 [email protected][email protected] 两个动态库

4.3.4 serice 生成

上面过程将需要的动态库生成完毕,接下来我们需要生成对应的 service 可执行文件,这个过程一共分为三步:

1、在 /default 下的 Android.bp 文件中添加如下内容

cc_binary {
    name: "[email protected]",
    defaults: ["hidl_defaults"],
    relative_install_path: "hw",
    vendor: true,
    srcs: [
        "service.cpp"
    ],
    init_rc: ["[email protected]"],
    shared_libs: [
        "liblog",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
        "libutils",
        "[email protected]",
    ],
}

2、补充 service.cpp 内容

内容很简单,defaultPassthroughServiceImplementation 帮我们自动注册服务:

#define LOG_TAG "[email protected]"
 
#include <android/hardware/galaxy_one/1.0/IGalaxyOne.h>
#include <hidl/LegacySupport.h>
#include "GalaxyOne.h"
 
// Generated HIDL files
using android::hardware::galaxy_one::V1_0::IGalaxyOne;
using android::hardware::galaxy_one::V1_0::implementation::GalaxyOne;
 
using android::hardware::defaultPassthroughServiceImplementation;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
 
int main() {
    return defaultPassthroughServiceImplementation<IGalaxyOne>();
} 

3、补充 rc 文件

注意这里的 galaxy-hal-service 相当于这个服务的别名,系统就是根据这个文件在启动的同时也将这个 service 启动,因此在下面我们手动启动测试时没有什么作用,不过这里先补充完整。

service galaxy-hal-service /vendor/bin/hw/[email protected]
    class hal
    user system
    group system

同样执行 mmm hardware/interfaces/galaxy_one/1.0 命令,完成之后就会得到如下二进制可执行文件:

out/target/product/sailfish/vendor/bin/hw/[email protected]

4.4 client 端

经过一系列过程之后,我们得到了三个产物
1、[email protected]
2、[email protected]
3、[email protected]

现在需要模拟一个客户端来测试调用,因此在 default 目录下新建 test 目录,并新建 client.cpp、Android.bp 文件,具体结构如下:

 

 

client.cpp 内容如下:

#include <android/hardware/galaxy_one/1.0/IGalaxyOne.h>
#include <hidl/Status.h>
#include <log/log.h>

using android::sp;
using android::hardware::galaxy_one::V1_0::IGalaxyOne;
using android::hardware::Return;

int main(){
    android::sp<IGalaxyOne> service = IGalaxyOne::getService();
    if (service == nullptr) {
        ALOGD("faile to get galaxy_one service......");
        return -1;
    }
    ALOGE("success to get galaxy_one service.....");

    uint32_t addResult = service->add(3,4);
    ALOGE("galaxy_one service add: result = %d",(int)addResult);

    uint32_t subResult = service->sub(8,3);
    ALOGE("galaxy_one service sub: result = %d",(int)subResult);

    uint32_t mulResult = service->mul(3,8);
    ALOGE("galaxy_one service mul: result = %d",(int)mulResult);

    uint32_t divResult = service->div(8,2);
    ALOGE("galaxy_one service div: result = %d",(int)divResult);

    return 0;
}

Android.bp 内容如下:

cc_binary {
    name: "galaxy_test",    //表示生成的 client 名称
    srcs: [
        "client.cpp"
    ],
    shared_libs: [
        "liblog",
        "[email protected]",
        "libhidlbase",
        "libhidltransport",
        "libhwbinder",
        "libutils",
    ],
}

mmm hardware/interfaces/galaxy_one/1.0 命令编译之后,可以在 out/target/product/XXX/system/bin 目录下找到 galaxy_test

五、验证服务

5.1 push 设备

现在我们一共得到 4 个产物,使用 adb 命令将其 push 到手机对应目录下:

1、[email protected] ===> /vendor/lib64/hw
2、[email protected] ===> vendor/lib64
3、[email protected] ===> /vendor/bin/hw
4、galaxy_test ===> /system/bin

5、rc ===》 /vendor/etc/init

6、xml ===》/vendor/etc/vintf/manifest/

5.2 修改设备 manifest.xml

HIDL 想要被 framework 获取使用还需要在 manifest.xml 中注册,此在手机 vendor/etc/vintf 下,我们将这个文件 pull 出来添加如下代码之后再 push 原来位置:

    <hal format="hidl">
        <name>android.hardware.galaxy_one</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>IGalaxyOne</name>
            <instance>default</instance>
        </interface>
        <fqname>@1.0::IGalaxyOne/default</fqname>
    </hal>

5.3 运行 service

这里我们手动启动,用于测试

./vendor/bin/hw/[email protected]

5.4 运行 client

./system/bin/galaxy_test

运行成功之后可查看日志,有如下内容则表示服务建立成功:

 apk调用

在out下查找jar

 apk调用:

IGalaxyOne service = null;
        try {
            service = IGalaxyOne.getService(false);
            Log.e("longjiang",service.add(3,5)+"");
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

 

标签:hal,service,实现,hidl,hardware,1.0,android,uint32,galaxy
From: https://www.cnblogs.com/wanglongjiang/p/18206835

相关文章

  • 摸清自定义流程表单开发优点 实现降本增效!
    随着社会竞争压力的增大,很多企业都希望实现降本增效提质的办公效果。那么,借助什么样的软件平台可以让企业在提升市场竞争力的前提下,还能降低开发成本,提高成效?低代码技术平台是目前流行于中小企业办公职场中的平台产品,其中自定义流程表单开发优势特点多、灵活高效、可视化操作界面,......
  • python 实现公众号模板消息推送(亲测有效)
    APPID='xxxxxxxxx'APPSECRET='xxxxxxxxxxxxxx'response=requests.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}'.format(APPID,APPSECRET))ACCESS_TOKEN=response.js......
  • 文件夹加密如何实现?如何保证加密后文件不会被他人查看?
    文件夹加密技术:确保数据安全的关键步骤在我们的数字生活中,个人和企业的敏感信息经常需要通过电子方式存储和传输。为了防止这些信息落入错误的手中,文件夹加密成为了一种重要的数据保护手段。文件夹加密不仅可以防止未授权访问,还能在信息传播过程中保障数据的完整性和机密性。但如......
  • [Unity] 单例基类的实现方式
    Unity单例基类的实现方式游戏开发的过程中我们经常会将各种“Manger”类设为单例,以实现单一资源的全局访问。Unity中的单例一般分为两类,一种是直接继承自Object的普通单例,还有一种是需要继承MonoBehaviour的Mono单例。接下来我将会讲解这两种单例基类的实现方式。注意:由于Unity......
  • 通过 adc 实现一个IO对多个按键读取
    如何实现一个IO对多个按键读取(1)当我们需要实现一个IO对多个按键读取的时候,可以采用如下电路,使用IO口的ADC功能,读取电压值,即可知道哪个按键被按下。(2)旁边加上一个10nf的电容,用于按键消抖......
  • CSS实现梯形
    1、这是结构代码,实现两个体形盒子对称<divclass="container"><divclass="box1"></div><divclass="box2"></div></div>2、这是CSS样式代码.container{width:400px;......
  • 德邦快递携手火山引擎,构建“数据飞轮”实现精准营销
     在快递行业中,数据的复杂性和多样性一直是企业面临的一大挑战。 在近日的采访中,德邦快递谈到通过引入火山引擎数智平台VeDI旗下系列数据产品,解决了长期困扰其营销活动的数据“黑盒”问题,显著提升了用户识别和营销效率,实现了月活用户和下单用户数的跃升。 德邦快递数字......
  • d3 v7树图实现动态边框,新增/编辑兄弟节点、子节点,删除节点和拖拽、缩放,动态边框
    d3版本:v7。PS:在用d3之前需要先了解SVG和CSS相关知识。树图生成部分和部分效果都是用SVG相关标签完成的。 效果图:  全部代码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=devi......
  • 文件系统(四):FAT32文件系统实现原理
    FAT32是从FAT12、FAT16发展而来,目前主要应用在移动存储设备中,比如SD卡、TF卡。隐藏的FAT文件系统现在也有被大量使用在UEFI启动分区中。为使文章简单易读,下面内容特意隐藏了很多实现细节,关于分区、格式化等相关的内容,可以查看之前的文章:文件系统(一):存储介质、原理与架构文件系......
  • 2024.05.09 vue实现
    所花时间(包括上课): 1 h左右代码量(行):  200  左右搏客量(篇):1了解到的知识点: vue2的选项式api备注(其他): <!--components文件中的Person.vue--><template><divclass="person"><h2>姓名:{{name}}</h2><h2>年龄:{......