摘要:本节主要来讲解Android10.0 Native层的HIDL服务创建和Native层的Client验证
[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析
[Android取经之路] 系列文章:
《系统启动篇》
- Android系统架构
- Android是怎么启动的
- Android 10.0系统启动之init进程
- Android10.0系统启动之Zygote进程
- Android 10.0 系统启动之SystemServer进程
- Android 10.0 系统服务之ActivityMnagerService
- Android10.0系统启动之Launcher(桌面)启动流程
- Android10.0应用进程创建过程以及Zygote的fork流程
- Android 10.0 PackageManagerService(一)工作原理及启动流程
- Android 10.0 PackageManagerService(二)权限扫描
- Android 10.0 PackageManagerService(三)APK扫描
- Android 10.0 PackageManagerService(四)APK安装流程
《日志系统篇》
- Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
- Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
- Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
- Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现
《Binder通信原理》:
- Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
- Android10.0 Binder通信原理(二)-Binder入门篇
- Android10.0 Binder通信原理(三)-ServiceManager篇
- Android10.0 Binder通信原理(四)-Native-C\C++实例分析
- Android10.0 Binder通信原理(五)-Binder驱动分析
- Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
- Android10.0 Binder通信原理(七)-Framework binder示例
- Android10.0 Binder通信原理(八)-Framework层分析
- Android10.0 Binder通信原理(九)-AIDL Binder示例
- Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
- Android10.0 Binder通信原理(十一)-Binder总结
《HwBinder通信原理》
- HwBinder入门篇-Android10.0 HwBinder通信原理(一)
- HIDL详解-Android10.0 HwBinder通信原理(二)
- HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
- HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
- HwServiceManager篇-Android10.0 HwBinder通信原理(五)
- Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
- Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
- JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
- JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
- HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
- HwBinder原理总结-Android10.0 HwBinder通信原理(十一)
《编译原理》
- 编译系统入门篇-Android10.0编译系统(一)
- 编译环境初始化-Android10.0编译系统(二)
- make编译过程-Android10.0编译系统(三)
- Image打包流程-Android10.0编译系统(四)
- Kati详解-Android10.0编译系统(五)
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
服务端执行:
客户端执行:
输出结果:
我的微信公众号:IngresGe