AOSP - 自定义绑定式HAL服务

文章目录[x]
  1. 1:创建自定义HIDL接口
  2. 1.1:创建厂商的HIDL目录
  3. 1.2:编写HIDL接口
  4. 1.3:生成HIDL接口文件的hash
  5. 2:实现HIDL接口(服务端)
  6. 2.1:生成C++文件
  7. 2.2:用Android Studio来开发HAL
  8. 2.3:编写绑定式HAL服务
  9. 2.4:添加HAL服务到目标版本中
  10. 3:验证HAL服务(客户端)
  11. 3.1:编写客户端
  12. 3.2:开启服务端
  13. 3.3:运行客户端

本文将基于AOSP android-10.0.0_r41来创建绑定式HAL服务。并编写可执行文件的客户端进行测试。HIDL的详细语法请参阅官网文档

创建自定义HIDL接口

创建厂商的HIDL目录

首先在AOSP中创建文件夹vendor/melrose/hardware/interfaces用来存放自己定义的HIDL接口,其中melrose为厂商名字。

然后将AOSP下的hareware/interfaces/Android.bp文件拷贝到自己定义的文件夹中:

cp hardware/interfaces/Android.bp vendor/melrose/hardware/interfaces/

修改拷贝后的Android.bp为:

hidl_package_root {
 name: "vendor.melrose.hardware",
 use_current: true,
}

编写HIDL接口

假设我们需要定义一系列的HIDL接口来控制LED灯的打开与关闭,在上面定义好的目录下创建led包和版本号:

vendor/melrose/hardware/interfaces/led/1.0

我们上面定义的HIDL的包名为:vendor.melrose.hardware,并在该文件夹下定义ILed.haltypes.hal两个文件:

package vendor.melrose.hardware.led@1.0;

 

interface ILed{

open() generates(LedStatus status);

close() generates(LedStatus status);

};

接下来我们croot到顶层目录为定义好的HIDL接口生成相应的Android.bp文件。

hidl-gen -L androidbp -r vendor.melrose.hardware:vendor/melrose/hardware/interfaces/ vendor.melrose.hardware.led@1.0

在执行完如上命令后会在vendor/melrose/hardware/interfaces/led/1.0目录中生成对应的Android.bp文件:

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

hidl_interface {
name: "vendor.melrose.hardware.led@1.0",
root: "vendor.melrose.hardware",
product_specific: true,
srcs: [
"types.hal",
"ILed.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
gen_java: true,
}

这样,我们就编写好了对应HIDL接口。

生成HIDL接口文件的hash

在我们确定接口不会进行改动时,我们就需要为编写完成的HIDL接口生成hash,如下命令会将生成的hash写入到vendor/melrose/hardware/interfaces/current.txt中:

hidl-gen -L hash -r vendor.melrose.hardware:vendor/melrose/hardware/interfaces/ vendor.melrose.hardware.led@1.0 -o vendor/melrose/hardware/interfaces/ >> vendor/melrose/hardware/interfaces/current.txt

这个命令会为我们编写的.hal文件生成对应的hash值,如果需要对编写的HIDL进行改动时都应该执行该命令来更新对应文件的hash值。

77e9ae2dc1785296078aac8577b1865e38991bf6ac1dd8210700f467fffd659c vendor.melrose.hardware.led@1.0::types
98b543f5060b0c20f5230d160b967a0d5381a9685ff58b646d6f6bedb3360eda vendor.melrose.hardware.led@1.0::ILed

实现HIDL接口(服务端)

生成C++文件

在编写完成HIDL接口后,一般会实现HIDL接口来控制驱动,我们在vendor/melrose/hardware/interfaces/led/1.0目录下创建default文件夹来生成HIDL对应的C++文件:

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

上面的命令会在default文件夹下生成对应的头文件和cpp文件:

-- led
 `-- 1.0
 |-- Android.bp
 |-- ILed.hal
 |-- default
 | |-- Led.cpp
 | `-- Led.h
 `-- types.hal

C++实现添加Android.bp文件:

hidl-gen -L androidbp-impl -r vendor.melrose.hardware:vendor/melrose/hardware/interfaces/ vendor.melrose.hardware.led@1.0 -o vendor/melrose/hardware/interfac
es/led/1.0/default/

这个命令会为c++实现生成直通式HAL的Android.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.melrose.hardware.led@1.0-impl",
relative_install_path: "hw",
// FIXME: this should be 'vendor: true' for modules that will eventually be
// on AOSP.
proprietary: true,
srcs: [
"Led.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"vendor.melrose.hardware.led@1.0",
],
}

接下来切换到vendor/melrose/hardware/interfaces/led/1.0目录下mm编译该模块来生成中间文件,会在目录out/soong/.intermediates/vendor/melrose/hardware/interfaces/led/1.0下生成各种文件。

default/
 vendor.melrose.hardware.led-V1.0-java/
 vendor.melrose.hardware.led-V1.0-java-shallow/
 vendor.melrose.hardware.led-V1.0-java_gen_java/
 'vendor.melrose.hardware.led@1.0'/
 'vendor.melrose.hardware.led@1.0-adapter'/
 'vendor.melrose.hardware.led@1.0-adapter-helper'/
 'vendor.melrose.hardware.led@1.0-adapter-helper_genc++'/
 'vendor.melrose.hardware.led@1.0-adapter-helper_genc++_headers'/
 'vendor.melrose.hardware.led@1.0-adapter_genc++'/
 'vendor.melrose.hardware.led@1.0-vts.driver'/
 'vendor.melrose.hardware.led@1.0-vts.driver_genc++'/
 'vendor.melrose.hardware.led@1.0-vts.driver_genc++_headers'/
 'vendor.melrose.hardware.led@1.0-vts.profiler'/
 'vendor.melrose.hardware.led@1.0-vts.profiler_genc++'/
 'vendor.melrose.hardware.led@1.0-vts.profiler_genc++_headers'/
 'vendor.melrose.hardware.led@1.0-vts.spec'/
 'vendor.melrose.hardware.led@1.0_genc++'/

然后回到default目录下添加service.cpp,并将Android.bp按照其提示将其修改为绑定式HAL

// FIXME: your file license if you have one

cc_binary {
// 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.melrose.hardware.led@1.0-service",
relative_install_path: "hw",
// FIXME: this should be 'vendor: true' for modules that will eventually be
// on AOSP.
proprietary: true,
srcs: [
"Led.cpp",

"service.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"vendor.melrose.hardware.led@1.0",
],
}

用Android Studio来开发HAL

为了提高开发效率和提高代码的健壮性,我们可以使用Android Studio来对生成的c++文件进行开发:

  • 创建Android C++项目
  • 在CMakeLists添加之前编译hal生成的文件的绝对路径:
add_library( # Sets the name of the library.
native-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
native-lib.cpp
/home/melrose/workspace/aosp/vendor/melrose/hardware/interfaces/led/1.0/default/Led.cpp
/home/melrose/workspace/aosp/vendor/melrose/hardware/interfaces/led/1.0/default/Led.h
/home/melrose/workspace/aosp/vendor/melrose/hardware/interfaces/led/1.0/default/Android.bp
/home/melrose/workspace/aosp/vendor/melrose/hardware/interfaces/led/1.0/default/service.cpp
)
  • Build -> Refresh Linked C++ Projects就可以在IDE中看到我们添加的文件:

解决找不到头文件问题

当在IDE中打开Led.cpp时会提示找不到头文件,接下来我们就一个一个去解决这些问题:

1、<vendor/melrose/hardware/led/1.0/ILed.h>

该头文件位置在之前我们 out/soong/.intermediates/vendor/melrose/hardware/interfaces/led/1.0vendor.melrose.hardware.led@1.0_genc++_headers/gen目录下,只需要将其添加include_directories中重新Refresh即可。

2、#include <hidl/MQDescriptor.h>和#include <hidl/Status.h>

这些头文件位于库libhidl中,具体位置为system/libhidl/base/include下,只需要将其添加include_directories中重新Refresh即可。

3、using ::android::sp

sp类位于StrongPointer.h文件中,目录为system/core/libutils/include下,只需要将其添加include_directories中重新Refresh即可。

include_directories(
 /home/melrose/workspace/aosp/out/soong/.intermediates/vendor/melrose/hardware/interfaces/led/1.0/vendor.melrose.hardware.led@1.0_genc++_headers/gen
 /home/melrose/workspace/aosp/system/libhidl/base/include
 /home/melrose/workspace/aosp/system/libhidl/transport/include
 /home/melrose/workspace/aosp/system/core/libutils/include
)

编写绑定式HAL服务

AndroidStudio配置完成后,就可以对Led.cppservice.cpp进行编辑。

Led.h

#pragma once

#include <vendor/melrose/hardware/led/1.0/ILed.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <android/log.h>
namespace vendor {
namespace melrose {
namespace hardware {
namespace led {
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;

#define LOG_TAG "Melrose"
#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOG_W(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

 

struct Led : public ILed {

public:
Led();
~Led();
static Led* getInstance();
Return<::vendor::melrose::hardware::led::V1_0::LedStatus> open() override;
Return<::vendor::melrose::hardware::led::V1_0::LedStatus> close() override;

private:
static Led* mInstance;
};

 

} // namespace implementation
} // namespace V1_0
} // namespace led
} // namespace hardware
} // namespace melrose
} // namespace vendor

Led.h的头文件中,添加了单例和构造、析构方法。因为使用了log,别忘了在Android.bp添加liblog动态库。

Led.cpp

 

#include "Led.h"

namespace vendor {
namespace melrose {
namespace hardware {
namespace led {
namespace V1_0 {
namespace implementation {

// Methods from ::vendor::melrose::hardware::led::V1_0::ILed follow.
Return<::vendor::melrose::hardware::led::V1_0::LedStatus> Led::open() {
LOG_I("led on");
return ::vendor::melrose::hardware::led::V1_0::LedStatus::ON;
}

Return<::vendor::melrose::hardware::led::V1_0::LedStatus> Led::close() {
LOG_I("led off");
return ::vendor::melrose::hardware::led::V1_0::LedStatus::OFF;
}

Led* Led::mInstance = nullptr;

Led::Led() {
LOG_I("led init");
}

 

Led::~Led() {
LOG_I("led release");
}

 

Led * Led::getInstance() {
if (mInstance == nullptr)
{
mInstance = new Led;
}
return mInstance;
}

 

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

//ILed* HIDL_FETCH_ILed(const char* /* name */) {
//return new Led();
//}
//
} // namespace implementation
} // namespace V1_0
} // namespace led
} // namespace hardware
} // namespace melrose
} // namespace vendor

为了简便,在实现openclose方法时Logcat会打印对应的日志。

service.cpp

#include "Led.h"
#include <hidl/HidlTransportSupport.h>
using namespace vendor::melrose::hardware::led::V1_0;
using namespace vendor::melrose::hardware::led::V1_0::implementation;
using namespace android::hardware;

 

int main(){

//获取Led的强指针
android::sp<ILed> ptr = Led::getInstance();
if (ptr == nullptr){
return 1;
}

//配置线程池,需要添加头文件 system/libhidl/transport/include
configureRpcThreadpool(1,true);

 

//注册成一个服务
auto stat = ptr->registerAsService("led-service");

 

if (stat != android::OK){
LOG_I("start led service failed %d!",stat);
return 1;
}

LOG_I("start led service successful!");

//加入线程池
joinRpcThreadpool();

 

return 0;
}

配置一个绑定式服务只需要4步:

  • 获取Led的强指针
  • 配置线程池
  • 注册成一个服务
  • 加入线程池

 

添加HAL服务到目标版本中

在编写完服务后,我们需要为目标编译HAL服务并将其作为vendor镜像的一部分,在device/generic/goldfish中的manifest.xml中添加hal(interface里面的instance的值为注册服务的名字,默认为default):

<hal format="hidl">
 <name>vendor.melrose.hardware.led</name>
 <transport>hwbinder</transport>
 <version>1.0</version>
 <interface>
 <name>ILed</name>
 <instance>led-service</instance>
 </interface>
 </hal>

接下来,我们需要将之前自定义的厂商的HAL模块和LED模块添加到device/generic/goldfish/vendor.mk中:

PRODUCT_PACKAGES += \
 vendor.melrose.hardware \
 vendor.melrose.hardware.led@1.0-service

在添加完成后,make installclean后并m编译adb shell进入模拟器就可以在目录vendor/bin/hw下看到我们的服务:

验证HAL服务(客户端)

编写客户端

在完成服务端的编写后,可以编写简单的客户端去测试,首先,我们在厂商vendor/melrose下创建tests文件夹并创建对应的路径来放置客户端:

`-- melrose
 |-- hardware
 |   `-- interfaces
 |       |-- Android.bp
 |       |-- current.txt
 |       `-- led
 |           `-- 1.0
 |               |-- Android.bp
 |               |-- ILed.hal
 |               |-- default
 |               |   |-- Android.bp
 |               |   |-- Led.cpp
 |               |   |-- Led.h
 |               |   `-- service.cpp
 |               `-- types.hal
 `-- tests
     `-- hardware
        `-- interfaces
            `-- led
                `-- 1.0

 

执行如下命令来创建客户端的Android.bp:

hidl-gen -L androidbp-impl -r vendor.melrose.hardware:vendor/melrose/hardware/interfaces/ vendor.melrose.hardware.led@1.0 -o vendor/melrose/tests/hardware/interfaces/led/1.0/default/

Android.bp修改为如下:

cc_binary {

name: "vendor.melrose.hardware.led-1.0-test",
relative_install_path: "test",
proprietary: true,
srcs: [
"LedTest.cpp",
],
shared_libs: [

"libhidlbase",
"libhidltransport",
"libutils",
"vendor.melrose.hardware.led@1.0",

],
}

创建对应的LedTest.cpp文件,并将创建的cpp文件和bp文件按照之前的方法添加到AndroidStudio中进行开发编辑:

#include <stdio.h>

#include <vendor/melrose/hardware/led/1.0/ILed.h>

using namespace vendor::melrose::hardware::led::V1_0;
int main(){

android::sp<ILed> led = ILed::getService("led-service");

if (led == nullptr){
printf("Failed to get service\n");
return 1;
}

led->open();

led->close();

return 0;
}

代码逻辑很简单,获取Led服务,并调用它的方法 ;

然后将测试模块添加到device/generic/goldfish/vendor.mk中:

PRODUCT_PACKAGES += \
vendor.melrose.hardware \
vendor.melrose.hardware.led@1.0-service \
vendor.melrose.hardware.led-1.0-test

开启服务端

m编译后运行emulator即可打开模拟器,然后重开终端adb shell进入模拟器,直接执行该命令即可启动服务:

vendor/bin/hw/vendor.melrose.hardware.led@1.0-service

运行客户端

在服务端开启后,另外一个终端adb shell就可以直接运行该命令就能测试:

vendor/bin/test/vendor.melrose.hardware.led-1.0-test

直接运行该命令就可以在Logcat中看到服务端打印的日志。

点赞
  1. dx说道:

    界面很漂亮

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00