Hidl编程实战(一)——定义HAL服务

1. 概述

hidl基本知识可以参考官网
安卓官网-hidl
也讲解了C++和Java实现hidl
本文讲解C++Hal服务的创建

2. 文件的创建

aosp整编过的代码,可以直接choosecombo后使用hidl-gen工具。如果没有整编过,可以单编hidl-gen工具。
hidl-gen工具可以用来协助创建hidl。

Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.

         -h: Prints this menu.
         -L <language>: The following options are available:
            check           : Parses the interface to see if valid but doesn't write any files.
            c++             : (internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.
            c++-headers     : (internal) Generates C++ headers for interface files for talking to HIDL interfaces.
            c++-sources     : (internal) Generates C++ sources for interface files for talking to HIDL interfaces.
            export-header   : Generates a header file from @export enumerations to help maintain legacy code.
            c++-impl        : Generates boilerplate implementation of a hidl interface in C++ (for convenience).
            c++-impl-headers: c++-impl but headers only.
            c++-impl-sources: c++-impl but sources only.
            c++-adapter     : Takes a x.(y+n) interface and mocks an x.y interface.
            c++-adapter-headers: c++-adapter but helper headers only.
            c++-adapter-sources: c++-adapter but helper sources only.
            c++-adapter-main: c++-adapter but the adapter binary source only.
            java            : (internal) Generates Java library for talking to HIDL interfaces in Java.
            java-constants  : (internal) Like export-header but for Java (always created by -Lmakefile if @export exists).
            vts             : (internal) Generates vts proto files for use in vtsd.
            makefile        : (removed) Used to generate makefiles for -Ljava and -Ljava-constants.
            androidbp       : (internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.
            androidbp-impl  : Generates boilerplate bp files for implementation created with -Lc++-impl.
            hash            : Prints hashes of interface in `current.txt` format to standard out.
            function-count  : Prints the total number of functions added by the package or interface.
            dependencies    : Prints all depended types.
         -O <owner>: The owner of the module for -Landroidbp(-impl)?.
         -o <output path>: Location to output files.
         -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.
         -R: Do not add default package roots if not specified in -r.
         -r <package:path root>: E.g., android.hardware:hardware/interfaces.
         -v: verbose output.
         -d <depfile>: location of depfile to write to.

2.1 创建hal接口

三方创建的hal接口一般位于vendor/厂商名/interfaces下,然后每一个hidl模块创建一个子目录。
hal接口需要使用hidl中的数据类型,具体可参照安卓官网

package vendor.vendorname.hardware.hidltest@1.0;

interface ITest {
    add(int32_t a, int32_t b) generates (int32_t result);
};

package指定软件包,interface指定hal接口,接口的全限定名称其实是软件包::接口名。

2.2 hash值写入current.txt

current.txt记录interfaces中所有接口的hash值,hal接口编译的时候会判断hash值,如果hash值改变,就会编译失败。其目的在于不允许改变接口文件,可以升级接口版本,依赖最初的接口版本,然后把新版本接口的hash值插入current.txt文件中,实现版本迭代。

hidl-gen -L hash -r vendor.vendorname.hardware:vendor/vendorname/interfaces vendor.vendorname.hardware.hidltest@1.0 >> interfaces/current.txt

借助hidl-gen工具生成hash值,并写入current.txt文件中,生成的hash值示例如下:

bac86584fe7fb75f0ccf0bc956428031f69074edfac20c4bd4106ccd41514dab vendor.vendorname.hardware.hidltest@1.0::ITest

2.3 创建hal接口的bp文件

借助hidl-gen工具生成hal接口的bp文件

hidl-gen -L androidbp -r vendor.vendorname.hardware:vendor/vendorname/interfaces vendor.vendorname.hardware.hidltest@1.0

生成的Androi.bp文件如下

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

hidl_interface {
    name: "vendor.vendorname.hardware.hidltest@1.0",
    root: "vendor.vendorname.hardware",
    product_specific: true,
    srcs: [
        "ITest.hal",
    ],
    interfaces: [
        "android.hidl.base@1.0",
    ],
    gen_java: true,
}

product_specific: true指定生成的文件在product分区
root指定父路径,一般需要在interfaces路径下添加bp文件
vendor/vendorname/interfaces/Android.bp

hidl_package_root {
    name: "vendor.vendorname.hardware",
    path: "vendor/vendorname/interfaces",
}

subdir = [
    "*",
]

这里指定了hidl的根路径。

2.4 生成C++文件

hidl-gen -o vendor/vendorname/interfaces/hidltest/1.0/default -L c++-impl -r vendor.vendorname.hardware:vendor/vendorname/interfaces vendor.vendorname.hardware.hidltest@1.0

通过-o参数来指定生成文件的目录
在这里插入图片描述
生成了一个头文件和一个源文件
Test.h

// FIXME: your file license if you have one

#pragma once

#include <vendor/vendorname/hardware/hidltest/1.0/ITest.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

namespace vendor {
namespace vendorname {
namespace hardware {
namespace hidltest {
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 Test : public ITest {
    // Methods from ::vendor::vendorname::hardware::hidltest::V1_0::ITest follow.
    Return<int32_t> add(int32_t a, int32_t b) override;

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

};

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

}  // namespace implementation
}  // namespace V1_0
}  // namespace hidltest
}  // namespace hardware
}  // namespace vendorname
}  // namespace vendor

Test.cpp

// FIXME: your file license if you have one

#include "Test.h"

namespace vendor {
namespace vendorname {
namespace hardware {
namespace hidltest {
namespace V1_0 {
namespace implementation {

// Methods from ::vendor::vendorname::hardware::hidltest::V1_0::ITest follow.
Return<int32_t> Test::add(int32_t a, int32_t b) {
    // TODO implement
    //return int32_t {}; 原生生成的
    return a + b;
}


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

//ITest* HIDL_FETCH_ITest(const char* /* name */) {
    //return new Test();
//}
//
}  // namespace implementation
}  // namespace V1_0
}  // namespace hidltest
}  // namespace hardware
}  // namespace vendorname
}  // namespace vendor

可以看到软件包名会转换成namespace,并将hal接口生成了对应的实现,我们可以在实现中进行修改。

2.5 创建源码的bp文件

hidl-gen -o vendor/vendorname/interfaces/hidltest/1.0/default -L androidbp-impl -r vendor.vendorname.hardware:vendor/vendorname/interfaces vendor.vendorname.hardware.hidltest@1.0

同样通过-o指定生成的bp文件跟C++文件在同一个目录
原生的bp文件

// FIXME: your file license if you have one

cc_library_shared {
    // FIXME: this should only be -impl for a passthrough hal.
    // In most cases, to convert this to a binderized implementation, you should:
    // - change '-impl' to '-service' here and make it a cc_binary instead of a
    //   cc_library_shared.
    // - add a *.rc file for this module.
    // - delete HIDL_FETCH_I* functions.
    // - call configureRpcThreadpool and registerAsService on the instance.
    // You may also want to append '-impl/-service' with a specific identifier like
    // '-vendor' or '-<hardware identifier>' etc to distinguish it.
    name: "vendor.vendorname.hardware.hidltest@1.0-impl",
    relative_install_path: "hw",
    // FIXME: this should be 'vendor: true' for modules that will eventually be
    // on AOSP.
    proprietary: true,
    srcs: [
        "Test.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "vendor.vendorname.hardware.hidltest@1.0",
    ],
}

默认是生成so文件的直通式hal,开发绑定式hal需要对此bp文件进行修改

// FIXME: your file license if you have one

cc_binary {
    name: "vendor.vendorname.hardware.hidltest@1.0-service",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    proprietary: true,
    srcs: [
        "Test.cpp",
        "service.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "libcutils",
        "liblog",
        "vendor.vendorname.hardware.hidltest@1.0",
    ],
    init_rc: [
        "vendor.vendorname.hardware.hidltest@1.0-service",
    ]
}

首先是改成cc_binary,让源代码编译成一个可执行文件。更改name,默认是生成直通式hal的impl结尾,结尾改成service。添加defaults导入hidl_defaults定义,里面有hidl相关定义。srcs添加service.cpp,并创建该文件在当前目录,后续介绍。shared_libs添加常用的so依赖。添加init_rc启动文件,后续介绍。
service.cpp

# define LOG_TAG "vendorname"

#include <android/log.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <vendor/vendorname/hardware/hidltest/1.0/ITest.h>
#include <stdio.h>
#include <unistd.h>
#include "Test.h"

using vendor::vendorname::hardware::hidltest::V1_0::ITest;
using vendor::vendorname::hardware::hidltest::V1_0::implementation::Test;
using android::sp;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;

int main() {
    ALOGI("begin vendorname hwbinder service");
    
    sp<ITest> instance = new Test();

    configureRpcThreadpool(1, true);

    android::status_t status = instance->registerAsService();
    if (status != android::OK)
    {
        ALOGE("Could not register vendorname Service!");
        return -1;
    }
    
    while(true) {
        ALOGI("vendorname hal service recycle");
        sleep(1);
    }
    
    joinRpcThreadpool();

    return 0;
}

service.cpp中的main函数是编译出的hal service二进制可执行文件的执行入口。而可执行文件的调用有rc文件负责。
rc文件

service hidltest_service vendor/bin/hw/vendor.vendorname.hardware.hidltest@1.0-service
    class hal
    user system
    group system

系统启动时,会加载读取rc文件,然后service这一行会使系统加载后面路径下的bin文件

3 编译产物

在interfaces目录下mm编译,编译完成后会在out/target/product/{brandname}/vendor生成以下产物
在这里插入图片描述
需要注意的是,整编的时候,并不能打入手机的版本中。需要添加

PRODUCT_PACKAGES += \
    vendor.vendorname.hardware.hidltest@1.0 \
    vendor.vendorname.hardware.hidltest@1.0-service

在device/coral/coral/device.mk中添加自定义mk文件,编译出错
在这里插入图片描述
由此看是编译通过了,需要解决编译无法打入版本的问题,这里看问题是对打进版本包的文件有限制。参考网上的解决方式,在envsetup.sh中添加环境变量

@@ -323,6 +323,8 @@ function setpaths()
     unset ANDROID_TARGET_OUT_TESTCASES
     export ANDROID_TARGET_OUT_TESTCASES=$(get_abs_build_var TARGET_OUT_TESTCASES)

+    export DISABLE_ARTIFACT_PATH_REQUIREMENTS="true"
+
     # needed for building linux on MacOS
     # TODO: fix the path
     #export HOST_EXTRACFLAGS="-I "$T/system/kernel_headers/host_include

如果是真机调试,发现刷机后手机中system下有了接口so文件,但是vendor下还是没有service。以pixel4xl为例,这是因为,真机刷机时需要下载谷歌的驱动,驱动解压到aosp的根目录,会使用一个固定的vendor.img镜像,而非是我们使用aosp编译的aosp镜像。流程如下
解压后的BoardConfig.mk中
device/google/coral/coral/BoardConfig.mk

include device/google/coral/BoardConfig-common.mk

device/google/coral/BoardConfig-common.mk

-include vendor/google_devices/coral/proprietary/BoardConfigVendor.mk

-include的意思是如果文件不存在,也不会报致命错误,而是所有加载完之后再重新检查,如果还是不存在,则报警告
vendor/google_devices/coral/proprietary/BoardConfigVendor.mk

ifneq ($(filter flame,$(TARGET_DEVICE)),)
-include vendor/google_devices/flame/BoardConfigPartial.mk
-include vendor/qcom/flame/BoardConfigPartial.mk
else
-include vendor/google_devices/coral/BoardConfigPartial.mk
-include vendor/qcom/coral/BoardConfigPartial.mk
endif

vendor/google_devices/coral/BoardConfigPartial.mk

BOARD_PREBUILT_VENDORIMAGE := vendor/google_devices/coral/proprietary/vendor.img

对比out目录下的vendor.img和该目录下的vendor.img的md5值,发现一样的。
如果想要定制自己的vendor镜像可参考博文
[Android]基于AOSP源码为Pixel3编译vendor.img
如果是手动加载,此时hal服务已经能够启动
但是对于开机自启动来说,并不能启动,开机加载hal服务的时候,需要给hal服务配置selinux规则,否则会启动失败。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值