文章目录
注:本文为个人学习记录,可能存在个别或多处错误,欢迎指正和讨论。
参考:
https://www.jianshu.com/p/ca6823b897b5
https://source.android.com/devices/architecture
进行学习。
接android9.0 从driver到APP(2)–hardware
一、 接口描述文件创建
1.1 创建HIDL目录
mkdir -p hardware/interfaces/sample/1.0
1.2 创建接口描述文件sample.hal,
/*
* Copyright (C) 2019 Alex
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.sample@1.0;
interface ISample {
init();
close();
Read(vec<int32_t> val);
Write(int32_t val);
getVal(vec<int32_t> val);
setVal(int32_t val);
};
1.3 生成HAL 相关文件
在Android根目录,使用hidl-gen工具生成HAL 相关文件
hidl-gen -o hardware/interfaces/sample/1.0/default -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.sample@1.0
二 、更新Makefile
然后使用脚本来更新Makefile,自动生成 Android.bp
./hardware/interfaces/update-makefiles.sh
update-makefiles.sh脚本是SDK自带的。
目录结构:
./
├── Android.bp
├── default
│ ├── Sample.cpp
│ └── Sample.h
└── ISample.hal
在1.0的目录的Android.bp内容如下:
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
name: "android.hardware.sample@1.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"ISample.hal",
],
interfaces: [
"android.hidl.base@1.0",
],
gen_java: true,
}
三 、 service.cpp相关
3.1 service.cpp创建
在default目录创建 service.cpp
内容可以从其他文件夹中复制过来再修改:
改完之后的内容如下:
/*
* Copyright (C) 2019 Alex
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.sample@1.0-service"
#include <android/hardware/sample/1.0/ISample.h>
#include <hidl/LegacySupport.h>
using android::hardware::sample::V1_0::ISample;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
return defaultPassthroughServiceImplementation<ISample>();
}
在default 目录创建一个
android.hardware.sample@1.0-service.rc
这个文件是自动启动的时候需要使用。
3.2 Android.bp
default目录没有自动生成Android.bp。
从其他地方拷贝个修改吧
cc_library_shared {
name: "android.hardware.sample@1.0-impl",
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["Sample.cpp"],
cflags: [
"-Wall",
"-Werror",
],
shared_libs: [
"liblog",
"libhardware",
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.sample@1.0",
],
}
cc_binary {
proprietary: true,
defaults: ["hidl_defaults"],
relative_install_path: "hw",
name: "android.hardware.sample@1.0-service",
init_rc: ["android.hardware.sample@1.0-service.rc"],
srcs: ["service.cpp"],
cflags: [
"-Wall",
"-Werror",
],
shared_libs: [
"liblog",
"libdl",
"libutils",
"libhardware",
"libhidlbase",
"libhidltransport",
"android.hardware.sample@1.0",
],
}
四 、client库代码修改
4.1 Sample.cpp代码修改
我们打开HIDL_FETCH的注释,让我们的HIDL使用Passthrough方式去实现
修改后的Sample.cpp:
/*
* Copyright (C) 2019 Alex
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.sample@1.0-impl"
#include <log/log.h>
#include <hardware/hardware.h>
#include <hardware/sample.h>
#include "Sample.h"
namespace android {
namespace hardware {
namespace sample {
namespace V1_0 {
namespace implementation {
Sample::Sample(sample_module_t *module) : mModule(module) {
if (mModule){
if(mModule->sampleInit){
mModule->sampleInit(mModule);
}
}
}
Sample::~Sample() {
if (mModule){
if(mModule->sampleClose){
mModule->sampleClose(mModule);
}
}
delete(mModule);
}
Return<void> Sample::read(read_cb _hidl_cb) {
int32_t param =0;
hidl_vec<int32_t> value;
if(mModule->sampleRead){
mModule->sampleRead(mModule,¶m);
}
value.resize(1);
value[0] = param;
_hidl_cb(value);
return Void();
}
Return<void> Sample::write(int32_t val) {
if(mModule->sampleWrite){
mModule->sampleWrite(mModule,val);
}
return Void();
}
Return<void> Sample::getVal(getVal_cb _hidl_cb) {
int32_t param =0;
hidl_vec<int32_t> value;
if(mModule->sampleGetval){
mModule->sampleGetval(mModule,¶m);
}
value.resize(1);
value[0] = param;
_hidl_cb(value);
return Void();
}
Return<void> Sample::setVal(int32_t val) {
if(mModule->sampleSetval){
mModule->sampleSetval(mModule,val);
}
return Void();
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
ISample* HIDL_FETCH_ISample(const char* /* name */) {
const hw_module_t* hw_module = nullptr;
sample_module_t* sample_module = nullptr;
int err = hw_get_module(SAMPLE_HARDWARE_MODULE_ID, &hw_module);
if (err) {
ALOGE("hw_get_module %s failed: %d", SAMPLE_HARDWARE_MODULE_ID, err);
return nullptr;
}
if (!hw_module->methods || !hw_module->methods->open) {
sample_module = reinterpret_cast<sample_module_t*>(
const_cast<hw_module_t*>(hw_module));
} else {
err = hw_module->methods->open(
hw_module, SAMPLE_HARDWARE_MODULE_ID,
reinterpret_cast<hw_device_t**>(&sample_module));
if (err) {
ALOGE("Passthrough failed to load legacy HAL.");
return nullptr;
}
}
return new Sample(sample_module);
}
} // namespace implementation
} // namespace V1_0
} // namespace sample
} // namespace hardware
} // namespace android
4.2 Sample.h
#ifndef ANDROID_HARDWARE_SAMPLE_V1_0_SAMPLE_H
#define ANDROID_HARDWARE_SAMPLE_V1_0_SAMPLE_H
#include <android/hardware/sample/1.0/ISample.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
namespace sample {
namespace V1_0 {
namespace implementation {
using ::android::hardware::sample::V1_0::ISample;
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 Sample : public ISample {
Sample(sample_module_t* module);
~Sample();
// Methods from ::android::hardware::sample::V1_0::ISample follow.
Return<void> read(read_cb _hidl_cb) override;
Return<void> write(int32_t val) override;
Return<void> getVal(getVal_cb _hidl_cb) override;
Return<void> setVal(int32_t val) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
private:
sample_module_t* mModule;
};
// FIXME: most likely delete, this is only for passthrough implementations
extern "C" ISample* HIDL_FETCH_ISample(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace sample
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_SAMPLE_V1_0_SAMPLE_H
五 、测试代码
测试中先不用关注rc文件和selinux的权限问题,用root权限去手动起service,然后跑测试程序
测试代码如下:
# include <android/hardware/sample/1.0/ISample.h>
# include <hidl/Status.h>
# include <hidl/LegacySupport.h>
# include <utils/misc.h>
# include <hidl/HidlSupport.h>
# include <stdio.h>
using android::hardware::sample::V1_0::ISample;
using android::sp;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using std::vector;
using ISampleV1_0 = ::android::hardware::sample::V1_0::ISample;
static sp<ISampleV1_0> gSampleHalV1_0 = nullptr;
int main(int /* argc */, char** /* argv */)
{
int val_write = 0;
int val_read = 0;
hidl_vec<int32_t> vec_val;
auto cb = [&vec_val](hidl_vec<int32_t> val) {
vec_val = val;
};
gSampleHalV1_0 = ISampleV1_0::getService();
if(gSampleHalV1_0 == nullptr) {
printf("Failed to get service\n");
return -1;
}
val_write = 1024;
gSampleHalV1_0->write(val_write);
gSampleHalV1_0->read(cb);
val_read = vec_val[0];
printf("[gSampleHalV1_0]: read: %d \n",val_read);
val_write = 2048;
gSampleHalV1_0->setVal(val_write);
gSampleHalV1_0->getVal(cb);
val_read = vec_val[0];
printf("[gSampleHalV1_0]: getVal: %d \n",val_read);
return 0;
}
六 、运行测试用例的问题解决
6.1 android.hardware.sample@1.0-service 运行中的问题
尝试拷贝
android.hardware.sample@1.0.so
android.hardware.sample@1.0-adapter-helper.so
到system分区,发现是只读的,remount不成功。
修改dts文件,把system也改为可读的,方便调试。
android.hardware.sample@1.0.so
android.hardware.sample@1.0-adapter-helper.so库拷贝到路径:
/system/lib64/
android.hardware.sample@1.0-service复制到
/vendor/bin/hw
测试程序HalSampleV1_0FuncTest 随便路径。
错误1:
LINK EXECUTABLE "/vendor/bin/hw/android.hardware.sample@1.0-service": library "android.hardware.sample@1.0.so" not found
提示找不到库文件,
尝试修改txt文件:
build/make/target/product/vndk/28.txt
build/make/target/product/vndk/current.txt
增加:
VNDK-core: android.hardware.sample@1.0.so
问题解决。
root权限下运行
# vendor/bin/hw/android.hardware.sample@1.0-service &
打印log:
[1] 1225
console:/ # sample_init[42]: start
[ 434.875720] open sample dev done!
sample_init[61]: success!
6.2 运行测试用例中的问题
运行测试程序:
HalSampleV1_0FuncTest
打印log:
Failed to get service
manifest文件里添加vendor接口的定义:
临时修改out目录的:
vendor/manifest.xml
增加:
</hal>
<hal format="hidl">
<name>android.hardware.sample</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ISample</name>
<instance>default</instance>
</interface>
</hal>
复制到板子上的
/vendor/manifest.xml
运行测试程序:
HalSampleV1_0FuncTest
打印log:
sample_write[109]: start
write [ 175.727455] SAMPLE_IOTEST_SETVAL!
1024
sample_read[86]: start
[[ 175.733711] SAMPLE_IOTEST_GETVAL!
gSampleHalV1_0]: read: 1024
sample_set_val[130]: start
set_val 2048
sample_get_val[152]: start
get value = 2048
[gSampleHalV1_0]: getVal: 2048
执行正确,结束。
疑惑:manifest.xml 的修改尝试过使用 passthrough的配置,跑不起来,不知道差别在哪里?