HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)

1. 概述
    为了和Android原生代码进行解耦,我在vendor的仓库中创建了一个ingres/interfaces的文件夹,hidl的相关实例都会放到这个目录下实现

    我们接下来准备写一个Native的hal的服务程序,client端为一个Native进程。

1.1 C++层HwBinder架构


 
1.2 HwBinder 通信原理

 
2. hal文件创建及环境准备
2.1 在vendor/ingres/interfaces中创建demo文件夹
    命令:

mkdir -p vendor/ingres/interfaces/demo/1.0/default
 
2.2 创建IDemo.hal文件,填充内容
命令:

vim vendor/ingres/interfaces/demo/1.0/IDemo.hal
写一个接口为getHelloString,传入参数类型为string,返回值generates 也为string类型

code:

package vendor.ingre.demo@1.0;
interface IDemo {
    getHelloString(string name) generates (string result);
};


2.3 给demo配置一个Android.bp
下面的hidl_package_root 用来指向hal的目录,hidl编译时,需要用到该变量

内容如下:

subdirs = [
    "*"
]
 
hidl_package_root {
    name: "vendor.ingres.demo",
    path: "vendor/ingres/interfaces/demo",
}


2.4 编译hidl-gen 工具
命令

./build.sh xxx -m hidl-gen
2.5 hidl-gen相关执行过程
2.5.1 制作一个shell脚本
命令:

vim vendor/ingres/interfaces/demo/update-all.sh
下面这个shell脚本,会生成4个文件:

hal文件对应的Android.bp

hal文件对应的hash--current.txt //哈希是一种旨在防止意外更改接口并确保接口更改经过全面审查的机制

default中demo的代码--Demo.cpp、Demo.

default中demo对应代码的Android.bp

使用hidl-gen工具生成hal的Android.bp、current.txt 、代码和对应的Android.bp

Code:

#!/bin/bash
 
HAL_PACKAGES=(
    "vendor.ingres.demo@1.0"
)
 
 
HAL_PACKAGE_ROOT=vendor.ingres.demo
HAL_PATH_ROOT=vendor/ingres/interfaces/demo
HAL_OUTPUT_CODE_PATH=vendor/ingres/interfaces/demo/1.0/default/
HASH_FILE=$HAL_PATH_ROOT/current.txt
 
for pkg in "${HAL_PACKAGES[@]}"
do
    echo "Generating hash for $pkg interface"
    echo "" >> $HASH_FILE
    hidl-gen -L hash -r $HAL_PACKAGE_ROOT:$HAL_PATH_ROOT -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport $pkg  >> $HASH_FILE
 
    echo "Updating $pkg Android.bp"
    hidl-gen -L androidbp -r $HAL_PACKAGE_ROOT:$HAL_PATH_ROOT -r android.hidl:system/libhidl/transport $pkg
    
    echo "Updating $pkg code's Android.bp"
    hidl-gen -o $HAL_OUTPUT_CODE_PATH -Landroidbp-impl -r $HAL_PACKAGE_ROOT:$HAL_PATH_ROOT -randroid.hidl:system/libhidl/transport $pkg
    echo "Updating $pkg code"
    hidl-gen -o $HAL_OUTPUT_CODE_PATH -Lc++-impl -r $HAL_PACKAGE_ROOT:$HAL_PATH_ROOT -randroid.hidl:system/libhidl/transport $pkg
done


此时的目录层级结构:

demo

├─1.0

│  └─ITestHal.hal

│  └─default

├─update-all.sh

├─Android.bp

2.5.2 执行shell脚本
命令:

./​vendor/ingres/interfaces/demo/update-all.sh
命令执行后,会在/​vendor/ingres/interfaces/demo/1.0中生成Android.bp ,并在/​vendor/ingres/interfaces/demo/1.0/default 中生成源码:Demo.cpp 和Demo.h

此时的层级结构:

demo

├─1.0

│  └─ITestHal.hal

│  └─Android.bp

│  └─default

│       └─Demo.h

│       └─Demo.cpp

│       └─Android.bp

├─update-all.sh

├─Android.bp

2.5.3 编译Hal:
命令:

mmm /​vendor/ingres/interfaces/demo/1.0
生成文件:

1)Android 的jar包,供JAVA层使用

\product\framework\vendor.ingres.demo-V1.0-java.jar
vendor.ingres.demo-V1.0-java-shallow.jar
2)系统库so,供Native层调用- C++

\product\lib\vendor.ingres.demo@1.0.so
\product\lib\vendor.ingres.demo@1.0-adapter-helper.so
\product\lib\vendor.ingres.demo@1.0-vts.driver.so
\product\lib\vendor.ingres.demo@1.0-vts.profiler.so
\product\lib64\vendor.ingres.demo@1.0.so
\product\lib64\vendor.ingres.demo@1.0-adapter-helper.so
\product\lib64\vendor.ingres.demo@1.0-vts.driver.so
\product\lib64\vendor.ingres.demo@1.0-vts.profiler.so
\vendor\lib\vendor.ingres.demo@1.0.so
\vendor\lib\vendor.ingres.demo@1.0-adapter-helper.so
\vendor\lib64\vendor.ingres.demo@1.0.so
\vendor\lib64\vendor.ingres.demo@1.0-adapter-helper.so
3. Demo服务实现
    Android规定,在Android8.0之后,vendor扩展的HAL,都要使用绑定式HAL,因此我们这里采用绑定式的HAL执行。

3.1 Demo的接口实现
3.1.1 Demo.h

由[2.5.2]的脚本自动生成,不需要做特殊处理

// FIXME: your file license if you have one
 
#pragma once

#include <vendor/ingres/demo/1.0/IDemo.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
 
namespace vendor {
namespace ingres {
namespace demo {
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 Demo : public IDemo {
    // Methods from ::vendor::ingres::demo::V1_0::IDemo follow.
    Return<void> getHelloString(const hidl_string& name, getHelloString_cb _hidl_cb) override;
 
    // Methods from ::android::hidl::base::V1_0::IBase follow.
 
};
 
// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" IDemo* HIDL_FETCH_IDemo(const char* name);
 
}  // namespace implementation
}  // namespace V1_0
}  // namespace demo
}  // namespace ingres
}  // namespace vendor
 


3.1.2 Demo.cpp实现
由[2.5.2]的脚本自动生成,不需要做特殊处理

// FIXME: your file license if you have one
 
#include "Demo.h"
 
namespace vendor {
namespace ingres {
namespace demo {
namespace V1_0 {
namespace implementation {
 
// Methods from ::vendor::ingres::demo::V1_0::IDemo follow.
Return<void> Demo::getHelloString(const hidl_string& name, getHelloString_cb _hidl_cb) {
    // TODO implement
    char buf[100];
    ::memset(buf, 0x00, 100);
    ::snprintf(buf, 100, "Hello , %s", name.c_str());
    hidl_string result(buf);
 
    _hidl_cb(result);
    return Void();
}
 
 
// Methods from ::android::hidl::base::V1_0::IBase follow.
 
//IDemo* HIDL_FETCH_IDemo(const char* /* name */) {
    //return new Demo();
//}
//
}  // namespace implementation
}  // namespace V1_0
}  // namespace demo
}  // namespace ingres
}  // namespace vendor


3.1.3 创建服务程序Service.cpp
 

#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <vendor/ingres/demo/1.0/IDemo.h>
 
#include <hidl/LegacySupport.h>
#include "Demo.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using vendor::ingres::demo::V1_0::implementation::Demo;
 
int main() {
    //1.和"dev/hwbinder" 进行通信,设置最大的线程个数为4
    configureRpcThreadpool(4, true);
 
    Demo demo;
    //2.注册服务
    auto status = demo.registerAsService();
    CHECK_EQ(status, android::OK) << "Failed to register demo HAL implementation";
 
    //3.把当前线程加入到线程池
    joinRpcThreadpool();
    return 0;  // joinRpcThreadpool shouldn't exit
}


 
3.1.4 添加demo service启动的rc文件
 

命令: 

vim /​vendor/ingres/interfaces/demo/1.0/default/vendor.ingres.demo@1.0-service.rc
 填充内容:

service vendor_ingres_demo /vendor/bin/hw/vendor.ingres.demo@1.0-service
    class hal
    user  system
    group system


3.1.5修改default的Android.bp
    增加一个进程的编译

cc_binary {
    name: "vendor.ingres.demo@1.0-service",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    proprietary: true,
    init_rc: ["vendor.ingres.demo@1.0-service.rc"],
    srcs: [
           "Service.cpp",
          ],
    shared_libs: [
        "libbase",      
        "liblog",
        "libdl",
        "libutils",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "vendor.ingres.demo@1.0",
        "vendor.ingres.demo@1.0-impl",
    ],
}


3.1.6 配置
为了让服务可以被客户端访问到,需要添加manifest

命令:vim /​vendor/ingres/interfaces/demo/1.0/default/manifest.xml

填充内容:

<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>vendor.ingres.demo</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>IDemo</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>


创建一个 moduleconfig.mk ,把manifest.xml的内容加入到系统的manifext.xml

命令:

vim /​vendor/ingres/interfaces/demo/1.0/default/moduleconfig.mk
填充内容:

$(eval LOCAL_MK_PATH := $(lastword $(MAKEFILE_LIST)))
$(eval DEVICE_MANIFEST_FILE += $(dir $(LOCAL_MK_PATH))manifest.xml)
$(warning DEVICE_MANIFEST_FILE = $(DEVICE_MANIFEST_FILE))
    整个系统版本编译时,最终可以在 /vendor/etc/vintf/manifest.xml中,看到我们这里添加的manifest.xml里面的内容

3.1.7 编译
命令:

mmm /vendor/ingres/interfaces/demo/1.0/default
生成文件:

1)服务进程:

\vendor\bin\hw\vendor.ingres.demo@1.0-service
2)rc文件:

vendor\etc\init\vendor.ingres.demo@1.0-service.rc
3)implement库

\vendor\lib64\hw\vendor.ingres.demo@1.0-impl.so
4.Native层Client进行测试:
Client 层级目录:

hal_demo

cpp

├─hal_demo_test.cpp

└─Android.bp


4.1 创建Client源文件
 

命令:

mkdir -p vendor/ingres/hal_demo/cpp/
vim vendor/ingres/hal_demo/cpp/hal_demo_test.cpp
配置源码:
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <vendor/ingres/demo/1.0/IDemo.h>
#include <hidl/LegacySupport.h>
 
using vendor::ingres::demo::V1_0::IDemo;
using android::sp;
using android::hardware::hidl_string;
 
int main() {
    //1.获取到Demo的服务对象
    android::sp<IDemo> service = IDemo::getService();
    
    if(service == nullptr) {
        printf("Failed to get service\n");
        return -1;
    }
 
    //2.通过服务对象,获取服务的getHelloString() hidl接口实现
    service->getHelloString("IngresGe", [&](hidl_string result) {
                printf("%s\n", result.c_str());
        });
 
    return 0;
}


 
4.2 配置编译环境
 

命令:

vim vendor/ingres/hal_demo/cpp/Android.bp
填充内容:

cc_binary {
    name: "hal_demo_test",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    proprietary: true,
    srcs: [
           "hal_demo_test.cpp",
          ],
    shared_libs: [
        "libbase",      
        "liblog",
        "libdl",
        "libutils",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "vendor.ingres.demo@1.0",
    ],
}


4.3 编译
命令: 

mmm vendor/ingres/hal_demo/cpp/
生成文件:

out\target\product\xxx\vendor\bin\hw\hal_demo_test
4.4 验证方法:
    由于我是单编模块,因此manifest.xml没有重新生成,需要手动把vendor/etc/vintf/ 中的manifest.xml pull到本地,增加如下内容,再push到vendor/etc/vintf/中。

manifest.xml新增内容:

<hal format="hidl">
    <name>vendor.ingres.demo</name>
    <transport>hwbinder</transport>
    <version>1.0</version>
    <interface>
        <name>IDemo</name>
        <instance>default</instance>
    </interface>
    <fqname>@1.0::IDemo/demo</fqname>
</hal>


push 以下文件:

\vendor\bin\hw\hal_demo_test
\product\lib64\vendor.ingres.demo@1.0.so
\vendor\lib64\vendor.ingres.demo@1.0.so
\vendor\bin\hw\vendor.ingres.demo@1.0-service
\vendor\etc\init\vendor.ingres.demo@1.0-service.rc
\vendor\lib64\hw\vendor.ingres.demo@1.0-impl.so


服务端执行:

客户端执行:

输出结果:

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值