1.编写hal文件并编译
在hardware/interfaces/目录下创建test文件夹和基版本1.0,这个版本号分为两部分,major.minor。major版本不变得话,只能添加api,不能修改。
创建ITest.hal和types.hal
hardware/interfaces/test/1.0/ITest.hal
package android.hardware.test@1.0;
interface ITest
{
//get led status
get() generates (LedStatus result);
//set led status
set(LedStatus val) generates(int32_t ret);
getBrightnessRange() generates(bool ret,BrightnessRange range);
setBrightnessValue(vec<int32_t> range) generates(bool ret);
on() ;
off() ;
};
hardware/interfaces/test/1.0/types.hal
package android.hardware.test@1.0;
enum LedStatus : uint32_t {
LED_ON,
LED_OFF,
LED_BAD_VALUE,
};
struct BrightnessRange {
uint32_t min;
uint32_t max;
};
添加完后,设置环境变量之后,执行./hardware/interfaces/update-makefiles.sh 会自动生成编译编译脚本,然后在
hardware/interfaces/test/1.0/ 路径下执行mm,会生成所需要得hidl库,接下来我们需要实现hidl interface,供client调用。
2. 实现Hidl Interface
首先实现ITest interface的子类testImpl 得头文件和对应得cpp。
hardware/interfaces/test/1.0/default/testImpl.h
#ifndef ANDROID_HARDWARE_LED_V1_0_LED_H
#define ANDROID_HARDWARE_LED_V1_0_LED_H
#include <android/hardware/test/1.0/ITest.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {
using ::android::hardware::test::V1_0::LedStatus;
using ::android::hardware::test::V1_0::BrightnessRange;
using ::android::hardware::test::V1_0::ITest;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
struct testImpl : public ITest {
public:
testImpl();
Return<LedStatus> get() override ;
Return<int32_t> set(LedStatus val) override;
Return<void> on() override;
Return<void> off() override;
Return<void> getBrightnessRange(getBrightnessRange_cb _hidl_cb) override;
Return<bool> setBrightnessValue(const hidl_vec<int32_t>& range) override;
private:
LedStatus state;
};
extern "C" ITest* HIDL_FETCH_ITest(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace test
} // namespace hardware
} // namespace android
#endif //ANDROID_HARDWARE_LED_V1_0_LED_H
testImpl.cpp
#define LOG_TAG "TestService"
#include <log/log.h>
#include "testImpl.h"
namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {
testImpl::testImpl() {
state = LedStatus::LED_BAD_VALUE;
ALOGE("testImpl Init status:%d", state);
}
Return<void> testImpl::on() {
state = LedStatus::LED_ON;
ALOGE("testImpl on status:%d", state);
return Void();
}
Return<void> testImpl::off() {
state = LedStatus::LED_OFF;
ALOGE("testImpl off status:%d", state);
return Void();
}
Return<LedStatus> testImpl::get() {
return state;
}
Return<int32_t> testImpl::set(LedStatus val) {
if(val == LedStatus::LED_OFF || val == LedStatus::LED_ON)
state = val;
else
return -1;
return 0;
}
Return<void> testImpl::getBrightnessRange(getBrightnessRange_cb _hidl_cb)
{
ALOGE("testImpl getBrightnessRange ");
BrightnessRange range;
range.max = 100;
range.min = 1;
_hidl_cb(true,range);
return Void();
}
Return<bool> testImpl::setBrightnessValue(const hidl_vec<int32_t>& range)
{
ALOGE("testImpl getBrightnessValue ");
auto iter = range.begin();
ALOGE("testImpl getBrightnessValue range.begin: %d",*iter);
iter = range.end();
ALOGE("testImpl getBrightnessValue range.end: %d",*iter);
ALOGE("testImpl getBrightnessValue range.size: %zu",range.size());
return true;
}
ITest* HIDL_FETCH_ITest(const char * /*name*/) {
ALOGE("testImpl HIDL_FETCH_ITest ");
return new testImpl();
}
} // namespace implementation
} // namespace V1_0
} // namespace test
} // namespace hardware
} // namespace android
Android.dp
cc_library_shared {
name: "android.hardware.test@1.0-impl",
defaults: ["hidl_defaults"],
srcs: ["testImpl.cpp"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libhardware",
"liblog",
"libutils",
"android.hardware.test@1.0",
],
}
cc_binary {
name: "android.hardware.test@1.0-service",
init_rc: ["android.hardware.test@1.0-service.rc"],
srcs: ["service.cpp",
"testImpl.cpp"],
shared_libs: [
"liblog",
"libhardware",
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.test@1.0",
],
}
3. 编写hdil service
接下来,使用相应功能填写存根并设置守护进程。可以使用passthrough方式和binder方式,示例:
hardware/interfaces/test/1.0/default/service.cpp
#define LOG_TAG "android.hardware.test@1.0-service"
#include <android/hardware/test/1.0/ITest.h>
#include <hidl/LegacySupport.h>
#include "testImpl.h"
using android::hardware::test::V1_0::ITest;
using android::hardware::test::V1_0::implementation::testImpl;
using android::hardware::defaultPassthroughServiceImplementation;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
int main() {
#if 0
// Passthrough dlopen so方式
return defaultPassthroughServiceImplementation<Itest>();
#else
// Binder 方式
sp<ITest> service = new testImpl();
configureRpcThreadpool(1, true /*callerWillJoin*/);
if(android::OK != service->registerAsService())
return 1;
joinRpcThreadpool();
#endif
}
4. 配置manifest.xml
add the code to the manifest.xm 以至于hwservicemanager 查找到指定的hidl service
About HIDL configures
system/libhidl/manifest.xml
<hal format="hidl">
<name>android.hardware.test</name>
<transport>hwbinder</transport> <!--//hwbinder 或者passthrough (直通模式)-->
<version>1.0</version>
<interface>
<name>ITest</name>
<instance>default</instance>
</interface>
</hal>
5. hidl client端调用
hidl service运行后,可以通过C++和Java两种方式调用,非常方便,通过java直接访问,就省去了jni。
5.1 实现java调用hidl service的例子
将以下内容添加到 Android.mk 中:
LOCAL_JAVA_LIBRARIES += android.hardware.test-V1.0-java
或将以下内容添加到 Android.bp 中:
shared_libs: [
/* … */
"android.hardware.test-V1.0-java",
],
该库还存在静态版:android.hardware.test-V1.0-java-static。
将以下内容添加到您的 Java 文件中:
import android.hardware.test.V1_0.ITest;
...
// retry to wait until the service starts up if it is in the manifest
ITest server = ITest.getService(true /* retry */); // throws NoSuchElementException if not available
server.on();
5.2 实现C++ 调用hidl service的例子
首先将 HAL 库添加到 makefile 中:
Make:LOCAL_SHARED_LIBRARIES += android.hardware.test@1.0
Soong:shared_libs: [ …, android.hardware.test@1.0 ]
接下来,添加 HAL 头文件:
#include <android/hardware/test/1.0/ITest.h>
…
// in code:
sp<ITest> client = ITest::getService();
client->on();
下面是Demo clinet
#define LOG_TAG "TEST_CLINET"
#include <android/hardware/test/1.0/ITest.h>
#include <log/log.h>
using android::hardware::test::V1_0::ITest;
using android::hardware::test::V1_0::LedStatus;
using android::hardware::test::V1_0::BrightnessRange;
using android::hardware::hidl_vec;
using android::sp;
int main(){
// BrightnessRange range;
sp<ITest> service = ITest::getService();
if( service == nullptr ){
ALOGE("Can't find ITest service...");
return -1;
}
ALOGE("ITest ON");
service->on();
ALOGE("ITest OFF");
service->off();
ALOGE("ITest set");
service->set(LedStatus::LED_ON);
ALOGE("ITest get");
LedStatus ret = service->get();
ALOGE("ITest get: %d",ret);
service->getBrightnessRange([](bool ret1,BrightnessRange range){
ALOGE("ITest getBrightnessRange ret: %d",ret1);
ALOGE("ITest getBrightnessRange Max: %d",range.max);
ALOGE("ITest getBrightnessRange Min: %d",range.min);
});
int32_t array[] = {5, 6, 7};
hidl_vec<int32_t> hv1 = std::vector<int32_t>(array, array + 3);
bool ret2 = service->setBrightnessValue(hv1);
ALOGE("ITest getBrightnessValue bool: %d",ret2);
return 0;
}
具体步骤
1. 创建目录
cd hardware/interfaces
mkdir -p test/1.0
2. 定义hal接口Itest.hal
package android.hardware.test@1.0;
interface Itest {
setData(YeData data) generates (YeStatus ret);
getData() generates (YeData ret);
};
定义数据类型types.hal
package android.hardware.test@1.0;
enum YeStatus : int32_t {
SUCCESS = 1,
FAILED,
};
struct YeData {
int32_t x;
int32_t y;
};
3. 根据.hal自动生成impl库的cpp实现
make hidl-gen
在hardware/interfaces/test/1.0目录执行hidl-gen命令:
PACKAGE=android.hardware.test@1.0
LOC= default/impl
hidl-gen -o $LOC -Lc++-impl -r android.hardware:hardware/interfaces $PACKAGE
4. 生成impl的Android.bp
hidl-gen -o default -Landroidbp-impl -r android.hardware:hardware/interfaces $PACKAGE
5. 生成hidl的Android.bp
执行hardware/interfaces/update-makefiles.sh
6. 修改device/fsl/imx8q/XXX/manifest.xml
添加以下代码:
<hal format="hidl">
<name>android.hardware.test</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>Itest</name>
<instance>default</instance>
</interface>
</hal>
7. 编写.rc文件
配置自启动
service vendor.test-1.0 /vendor/bin/hw/android.hardware.test@1.0-service
class hal
user system
group system
8. 添加PRODUCT_PACKAGES
在device/fsl/imx8q/XXX/XXX.mk中新增
打包.so和service到vendor.img
# Yetest HAL
PRODUCT_PACKAGES += \
android.hardware.test@1.0-impl \
android.hardware.test@1.0-service
9. device/fsl/imx8q/XXX/BoardConfig.mk中指定sepolicy路径:
BOARD_SEPOLICY_DIRS += hardware/interfaces/test/sepolicy
10. 在hardware/interfaces/test/sepolicy目录新增test.te:
type test, domain;
type test_exec, exec_type, vendor_file_type, file_type;
hwbinder_use(test);
init_daemon_domain(test)
add_hwservice(test,test_hwservice)
allow test hwservicemanager_prop:file {read open getattr map};
allow test system_file:dir {read open getattr search};
11. hardware/interfaces/test/sepolicy目录下新增file_contexts:
绑定android.hardware.test@1.0-service与test_exec的关系的关键
/(vendor|system/vendor)/bin/hw/android\.hardware\.test@1\.0-service u:object_r:test_exec:s0
/(vendor|system/vendor)/lib(64)?/hw/android\.hardware\.test@1\.0-impl\.so u:object_r:same_process_hal_file:s0
12. 新增harware/interfaces/test/sepolicy/hwservice_contexts:
android.hardware.test::Itest u:object_r:test_hwservice:s0
13. 新增harware/interfaces/test/sepolicy/hwservice.te:
type test_hwservice, hwservice_manager_type;