简介
在android 8.0之前,HAL是一个个的.so库,通过dlpen来打开,库和framework位于同一个进程中;
android系统进入8.0时代之后,framework和hal运行于不同的进程,所有的HAL采用HIDL技术来完成。运行Android8.0的设备必须支持绑定式和直通式HAL:
当前的类型为:
Java -> Jni -> Binder 客户端 ====== Binder 通信 ======> Binder 服务端 -> Hal -> Kernel
这一篇文章则是HIDL中的Binder服务端;
HIDL制作主要流程如下:
1.定义接口文件;
2.使用工具,根据接口文件生成代码;
3.完善接口函数
4.编译
一、HIDL接口文件定义
进入hardware/interfaces/
目录下建立新的接口文件.
首先建立对应的文件夹:
mkdir -p hardware/interfaces/hello/1.0/defaul
并在hardware/interfaces/hello/1.0/defaul
下创建接口描述文件IHello.hal:
package android.hardware.hello@1.0;
interface IHello{
open();
close();
read() generates (int32_t val);
write(int32_t val);
};
hidl-gen工具
Google提供了一些工具来帮助制作HIDL的框架:
在aosp根目录下执行
make hidl-gen
源码中编译生成hidl-gen.注意:编译前需要执行全编译的环境变量加载
使用hidl-gen工具生成代码
$ PACKAGE=android.hardware.hello@1.0
$ LOC=hardware/interfaces/hello/1.0/default/
$ hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
$ hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
执行完后,hardware/interfaces/hello/1.0/default/
会生成三个文件Android.dp
、Hello.cpp
、Hello.h
:
接着使用脚本来更新Makefile:
./hardware/interfaces/update-makefiles.sh
执行完后,hardware/interfaces/hello/1.0
会生成Android.bp
和Android.mk
:
上面生成的Hello.cpp
和Hello.h
是实现接口的关键文件;
二、 硬件访问实现
Hello.h修改为直通式
hardware/interfaces/hello/1.0/default/Hello.h
头文件
#ifndef ANDROID_HARDWARE_HELLO_V1_0_HELLO_H
#define ANDROID_HARDWARE_HELLO_V1_0_HELLO_H
#include <android/hardware/hello/1.0/IHello.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
namespace hello {
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 Hello : public IHello {
// Methods from IHello follow.
Return<void> open() override;
Return<void> close() override;
Return<int32_t> read() override;
Return<void> write(int32_t val) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
// FIXME: most likely delete, this is only for passthrough implementations
extern "C" IHello* HIDL_FETCH_IHello(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace hello
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_HELLO_V1_0_HELLO_H
去掉注释.采用直通模式.
// extern "C" IHello* HIDL_FETCH_IHello(const char* name);
Hello.cpp调用硬件抽象层
hardware/interfaces/hello/1.0/default/Hello.cpp
源文件
#define LOG_TAG "HelloService HIDL"
#include "Hello.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <stdio.h>
namespace android {
namespace hardware {
namespace hello {
namespace V1_0 {
namespace implementation {
/* 通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
static inline int hello_device_open(const struct hw_module_t* module, struct hello_device_t** device) {
return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h> */
struct hello_device_t* hello_device = NULL;
// Methods from IHello follow.
Return<void> Hello::open() {
hello_module_t* module;
if(hello_device) {
ALOGI("Hello JNI: hello_init, device is open, no need to init.");
return Void();
}
ALOGI("Hello JNI: initializing......");
if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**) &module) == 0) {
ALOGI("Hello JNI: hello Stub found.");
if(hello_device_open(&(module->common), &hello_device) == 0) {
ALOGI("Hello JNI: hello device is open.");
return Void();
}
ALOGE("Hello JNI: failed to open hello device.");
return Void();
}
ALOGE("Hello JNI: failed to get hello stub module.");
return Void();
}
Return<void> Hello::close() {
// TODO implement
return Void();
}
Return<int32_t> Hello::read() {
int32_t val = 0;
if(!hello_device) {
ALOGI("Hello JNI: device is not open.");
return val;
}
ALOGI("Hello JNI:get value from device start.");
hello_device->get_val(hello_device, &val);
ALOGI("Hello JNI:get value %d from device.", val);
return val;
}
Return<void> Hello::write(int32_t value) {
int32_t val = value;
ALOGI("Hello JNI: set value %d to device.", val);
if(!hello_device) {
ALOGI("Hello JNI: device is not open.");
return Void();
}
hello_device->set_val(hello_device, val);
return Void();
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
IHello* HIDL_FETCH_IHello(const char* /* name */) {
return new Hello();
}
} // namespace implementation
} // namespace V1_0
} // namespace hello
} // namespace hardware
} // namespace android
这里引用了硬件抽象层的include <hardware/hardware.h>
和include <hardware/hello.h>
,需要在hardware/interfaces/hello/1.0/default/Android.dp
引入共享库libhardware
和android.hardware.hello@1.0
这个是上一篇文章定义的;
编译
$ mmm hardware/interfaces/hello/1.0/default/
以上已经实现了访问硬件抽象层的访问,下面我们需要创建HIDL service服务端,提供给上层访问;
三、 构建HIDL service服务
虽然上一步已经能访问硬件抽象层,有了库,我们还需要构建HDIL服务端供上层使用;
-
1.创建服务入口
hardware/interfaces/hello/1.0/default/service.cpp
文件,代码如下:
#define LOG_TAG "android.hardware.hello@1.0-service"
#include <android/hardware/hello/1.0/IHello.h>
#include <hidl/LegacySupport.h>
using android::hardware::hello::V1_0::IHello;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
return defaultPassthroughServiceImplementation<IHello>();
}
-
2.修改编译脚本,添加对服务的编译
hardware/interfaces/hello/1.0/default/Android.bp
这里主要目的将当前hardware/interfaces/hello/1.0/default
项目定义为cc_binary
可直接可执行的项目,因为service.cpp
是包含main主函数入口的;
cc_library_shared {
name: "android.hardware.hello@1.0-impl",
relative_install_path: "hw",
proprietary: true,
srcs: [
"Hello.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"libhardware",
"android.hardware.hello@1.0",
],
}
cc_binary {
name: "android.hardware.hello@1.0-service",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
proprietary: true,
srcs: ["service.cpp"],
init_rc: ["android.hardware.hello@1.0-service.rc"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"libhardware",
"android.hardware.hello@1.0",
"android.hardware.hello@1.0-impl",
],
}
编译成功可执行文件android.hardware.hello@1.0-service
放在/vendor/bin/hw/
目录中;
-
3.创建启动rc脚本
创建rc文件!(rc文件是被init进程访问的)
hardware/interfaces/hello/1.0/default/android.hardware.hello@1.0-service.rc
service hello_service /vendor/bin/hw/android.hardware.hello@1.0-service
class hal
user system
group system
注意:这里定义了hello_service
服务进程所属用户和用户组都是system
,而且启动执行文件位于/vendor/bin/hw/android.hardware.hello@1.0-service
最后HIDL service服务会随着开机一起启动
最后目录结构如下:
、 构建HIDL
-
4.提供外部访问配置修改
为了让服务器被客户端访问到,还需要在device/huawei/angler/manifest.xml
(不同厂商路径不同)添加如下:
<hal format="hidl">
<name>android.hardware.hello</name>
<transport>hwbinder</transport>
<impl level="generic"></impl>
<version>1.0<version>
<interface>
<name>IHello</name>
<instance>default</instance>
</interface>
</hal>
四、编译
$ mmm hardware/interfaces/hello/1.0/default/
最后会生成以下文件:
/vendor/lib64/hw/android.hardware.hello@1.0-impl.so
/vendor/etc/init/android.hardware.hello@1.0-service.rc
/vendor/bin/hw/android.hardware.hello@1.0-service
/system/lib64/android.hardware.hello@1.0.so
注意:在编译system.img和vendor.img镜像的过程中,如何以上文件没有合入,可以使用adb push的方式验证
问题点:
1.system_servre进程访问HDIL 服务进程 的selinux权限问题
SELinux: avc: denied { find } for interface=android.hardware.hello::IHello pid=865 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_hwservice:s0 tclass=hwservice_manager permissive=0
我们上层framework的system_server
进程没有权限访问default_android_hwservice
服务,可以看这篇文章解决
第一步:打开device/huawei/angler/sepolicy/system_server.te
文件,添加权限
allow system_server default_android_hwservice:hwservice_manager{ find add read}
第二步:打开system/sepolicy/public/domain.te
文件,找到
注释掉这一行
#neverallow * default_android_hwservice:hwservice_manager{add find}
或者可以修改为
neverallow { domain –system_server} default_android_hwservice:hwservice_manager {add find};
参考:https://www.freesion.com/article/945159695/
遗留问题
服务端main没有启动执行