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

摘要:本节主要来讲解Android10.0 Native层的HIDL服务创建和Native层的Client验证

阅读本文大约需要花费18分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

  1. Android系统架构
  2. Android是怎么启动的
  3. Android 10.0系统启动之init进程
  4. Android10.0系统启动之Zygote进程
  5. Android 10.0 系统启动之SystemServer进程
  6. Android 10.0 系统服务之ActivityMnagerService
  7. Android10.0系统启动之Launcher(桌面)启动流程
  8. Android10.0应用进程创建过程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及启动流程
  10. Android 10.0 PackageManagerService(二)权限扫描
  11. Android 10.0 PackageManagerService(三)APK扫描
  12. Android 10.0 PackageManagerService(四)APK安装流程

《日志系统篇》

  1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
  2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
  4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

《Binder通信原理》

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入门篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
  5. Android10.0 Binder通信原理(五)-Binder驱动分析
  6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework层分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
  11. Android10.0 Binder通信原理(十一)-Binder总结

  《HwBinder通信原理》

  1. HwBinder入门篇-Android10.0 HwBinder通信原理(一)
  2.  HIDL详解-Android10.0 HwBinder通信原理(二)
  3. HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
  4. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)

 

1. 概述

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

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

 

1.1 C++层HwBinder架构

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

 

1.2 HwBinder 通信原理

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

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 [email protected];
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=(
    "[email protected]"
)


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脚本

命令:

./hardware/interfaces/demo/update-all.sh

命令执行后,会在hardware/interfaces/demo/1.0中生成Android.bp ,并在hardware/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 /hardware/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\[email protected]
\product\lib\[email protected]
\product\lib\[email protected]
\product\lib\[email protected]
\product\lib64\[email protected]
\product\lib64\[email protected]
\product\lib64\[email protected]
\product\lib64\[email protected]
\vendor\lib\[email protected]
\vendor\lib\[email protected]
\vendor\lib64\[email protected]
\vendor\lib64\[email protected]

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 
#include 
#include 

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 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 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 
#include 
#include 

#include 
#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 /hardware/interfaces/demo/1.0/default/[email protected]

 填充内容:

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

3.1.5修改default的Android.bp

    增加一个进程的编译

cc_binary {
    name: "[email protected]",
    relative_install_path: "hw",
    defaults: ["hidl_defaults"],
    proprietary: true,
    init_rc: ["[email protected]"],
    srcs: [
           "Service.cpp",
          ],
    shared_libs: [
        "libbase",      
        "liblog",
        "libdl",
        "libutils",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "[email protected]",
        "[email protected]",
    ],
}

3.1.6 配置

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

命令:vim /hardware/interfaces/demo/1.0/default/manifest.xml

填充内容:


    
        vendor.ingres.demo
        hwbinder
        1.0
        
            IDemo
            default
        
    

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

命令:

vim /hardware/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\[email protected]

2)rc文件:

vendor\etc\init\[email protected]

3)implement库

\vendor\lib64\hw\[email protected]

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 
#include 
#include 
#include 

using vendor::ingres::demo::V1_0::IDemo;
using android::sp;
using android::hardware::hidl_string;

int main() {
    //1.获取到Demo的服务对象
    android::sp 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",
        "[email protected]",
    ],
}

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新增内容:


    vendor.ingres.demo
    hwbinder
    1.0
    
        IDemo
        default
    
    @1.0::IDemo/demo

push 以下文件:

\vendor\bin\hw\hal_demo_test
\product\lib64\[email protected]
\vendor\lib64\[email protected]
\vendor\bin\hw\[email protected]
\vendor\etc\init\[email protected]
\vendor\lib64\hw\[email protected]

服务端执行:

客户端执行:

输出结果:

 

我的微信公众号:IngresGe

你可能感兴趣的:(Android取经之路,#,2.进程间通信,Android10.0,hwbinder,binder,hidl,c++)