简介
在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 [email protected];
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工具生成代码
$ [email protected]
$ 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
#include
#include
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 open() override;
Return close() override;
Return read() override;
Return 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
#include
#include
#include
#include
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);
}
/*在硬件抽象层中定义的硬件访问结构体,参考 */
struct hello_device_t* hello_device = NULL;
// Methods from IHello follow.
Return 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 Hello::close() {
// TODO implement
return Void();
}
Return 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 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
和include
,需要在hardware/interfaces/hello/1.0/default/Android.dp
引入共享库libhardware
和[email protected]
这个是上一篇文章定义的;
编译
$ mmm hardware/interfaces/hello/1.0/default/
以上已经实现了访问硬件抽象层的访问,下面我们需要创建HIDL service服务端,提供给上层访问;
三、 构建HIDL service服务
虽然上一步已经能访问硬件抽象层,有了库,我们还需要构建HDIL服务端供上层使用;
- 1.创建服务入口
hardware/interfaces/hello/1.0/default/service.cpp
文件,代码如下:
#define LOG_TAG "[email protected]"
#include
#include
using android::hardware::hello::V1_0::IHello;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
return defaultPassthroughServiceImplementation();
}
- 2.修改编译脚本,添加对服务的编译
hardware/interfaces/hello/1.0/default/Android.bp
这里主要目的将当前hardware/interfaces/hello/1.0/default
项目定义为cc_binary
可直接可执行的项目,因为service.cpp
是包含main主函数入口的;
cc_library_shared {
name: "[email protected]",
relative_install_path: "hw",
proprietary: true,
srcs: [
"Hello.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"libhardware",
"[email protected]",
],
}
cc_binary {
name: "[email protected]",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
proprietary: true,
srcs: ["service.cpp"],
init_rc: ["[email protected]"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"libhardware",
"[email protected]",
"[email protected]",
],
}
编译成功可执行文件[email protected]
放在/vendor/bin/hw/
目录中;
- 3.创建启动rc脚本
创建rc文件!(rc文件是被init进程访问的)
hardware/interfaces/hello/1.0/default/[email protected]
service hello_service /vendor/bin/hw/[email protected]
class hal
user system
group system
注意:这里定义了hello_service
服务进程所属用户和用户组都是system
,而且启动执行文件位于/vendor/bin/hw/[email protected]
最后HIDL service服务会随着开机一起启动
最后目录结构如下:
、 构建HIDL
- 4.提供外部访问配置修改
为了让服务器被客户端访问到,还需要在device/huawei/angler/manifest.xml
(不同厂商路径不同)添加如下:
android.hardware.hello
hwbinder
1.0
IHello
default
四、编译
$ mmm hardware/interfaces/hello/1.0/default/
最后会生成以下文件:
/vendor/lib64/hw/[email protected]
/vendor/etc/init/[email protected]
/vendor/bin/hw/[email protected]
/system/lib64/[email protected]
注意:在编译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没有启动执行