此篇文章接上一篇hidl,我们来实现hal层
hal层官方解释系统硬件抽象层,理解为kernel的代理层,他的存在屏蔽了不同硬件设备的差异,根据提供的访问标准,就可以对不同的硬件进行操作,也为不同的厂商隐藏了驱动的核心功能,比如一些算法
抽象层命名
硬件抽象层以模块的形式来管理各个硬件访问接口。每一个硬件模块都对应有一个动态链接库文件,动态链接库文件的命名要符合一定的规范。
那么该如何命名呢?
源码中硬件抽象层模块的命名定义在aosp/hardware/libhardware/hardware.c文件中,我们可以阅读下该文件,了解下加载的过程,就能明白我们文件该如何命名了
hw_get_module()---->hw_get_module_by_class() --→load()
hw_get_module_by_class(){
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/
/* First try a property specific to the class and possibly instance */
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
if (property_get(prop_name, prop, NULL) > 0) {
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Loop through the configuration variants looking for a module */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Nothing found, try the default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
}
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
通读代码我们可以看出加载过程会先读取variant_keys定义的四个系统属性,并检查对应的文件是否存在,如果存在,就load这个硬件抽象模块,如果四个属性对应的文件都不存在,那么就会找含“default“文件加载,比如led.default.so(<MODULE_ID>.default.so)。硬件抽象层模块命名规范为“<MODULE_ID>.variant.so”, MODULE_ID表示模块id,一般我们取自己模块属性比较直观的名称,比如led,
模块接口
在硬件抽象层中,实现一个模块主要涉及三个定义结构:
- struct hw_module_t
- struct hw_module_methods_t
- struct hw_device_t
1,hal层的模块都要自定义一个hal模块结构体,便于区分不同的模块,并且成员类型必须包含hw_module_t。例:
typedef struct bear_module {
struct hw_module_t common;
} bear_module_t;
2.实现自定义hal模块,变量名必须为HAL_MODULE_INFO_SYM
bear_module_t HAL_MODULE_INFO_SYM={
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = BEAR_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = BEAR_HARDWARE_MODULE_ID,
.name = "bear HAL module",
.author = "fht",
.methods = &bearpi_module_methods,
},
};
3,“HARDWARE_MODULE_TAG”用来标识一个硬件抽象层模块,结构体成员tag的值必须为HARDWARE_MODULE_TAG('H'<<24|'W'<<16|'M'<<8|'T')。
4,hw_module_t结构体成员变量methods定义了一个硬件抽象层模块的操作方法列表,类型为我们上面介绍的hw_module_methods_t。
在aosp/hardware/libhardware/include/hardware/hardware.h中介绍hw_module_methods_t结构体只有一个成员变量,如下面内容
typedef struct hw_module_methods_t {
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
open是一个函数指针,用来打开硬件抽象层模块中的控制的硬件设备,参数介绍
- module----要打开的硬件设备所在的模块
- id-----------要打开的硬件设备的ID
- device-----已经打开的硬件设备
5, 硬件抽象层中的硬件设备是由所在的hw_module_methods_t提供接口打开,关闭则是hw_device_t提供接口实现,hw_device_t的成员变量close是一个函数指针,被用来关闭硬件设备。
那么硬件抽象层是怎么工作的呢?
hidl访问驱动时,首先系统使用hw_get_module方法获得hardware层对应的module,然后后通过load加载库,并通过固定符号HAL_MODULE_INFO_SYM 寻找到hw_module_t结构体,并通过结构体hw_module_methods_t绑定的open方法打开模块,并将hw_device_t变量作为参数传递,这样我们就可以操作模块间接操作硬件了,用户也就可以实现操作硬件了。
案例实现
实现一个具有事件回调功能的硬件抽象层
一,创建bearpi.h, 路径hardware/libhardware/include/hardware/bearpi.h
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.
*/
#ifndef ANDROID_INCLUDE_HARDWARE_BEAR_PI_H
#define ANDROID_INCLUDE_HARDWARE_BEAR_PI_H
#include <hardware/hardware.h>
#include <hardware/hw_auth_token.h>
#define BEAR_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define BEAR_HARDWARE_MODULE_ID "bearpi" //需要与库名称相同 bearpi.default.so,否则找不到hal
typedef enum bear_msg_type {
BEAR_ERROR = -1,
BEAR_ACQUIRED = 1,
} bear_msg_type_t;
/*
* Bear acquisition info is meant as feedback for the current operation. Anything but
* BEAR_ACQUIRED_GOOD will be shown to the user as feedback on how to take action on the
* current operation. For example, BEAR_ACQUIRED_IMAGER_DIRTY can be used to tell the user
* to clean the sensor. If this will cause the current operation to fail,
* In general, these messages will result in a "Try again" message.
*/
typedef enum bear_acquired_info {
BEAR_ACQUIRED_GOOD = 0,
BEAR_ACQUIRED_PARTIAL = 1, /* sensor needs more data, i.e. longer swipe. */
BEAR_ACQUIRED_INSUFFICIENT = 2, /* image doesn't contain enough detail for recognition*/
BEAR_ACQUIRED_IMAGER_DIRTY = 3, /* sensor needs to be cleaned */
BEAR_ACQUIRED_TOO_SLOW = 4, /* mostly swipe-type sensors; not enough data collected */
BEAR_ACQUIRED_TOO_FAST = 5, /* for swipe and area sensors; tell user to slow down*/
BEAR_ACQUIRED_DETECTED = 6, /* when the finger is first detected. Used to optimize wakeup.
Should be followed by one of the above messages */
BEAR_ACQUIRED_VENDOR_BASE = 1000 /* vendor-specific acquisition messages start here */
} bear_acquired_info_t;
typedef struct bear_acquired {
bear_acquired_info_t acquired_info; /* information about the image */
} bear_acquired_t;
typedef struct bear_msg {
bear_msg_type_t type;
union {
bear_acquired_t acquired;
} data;
} bear_msg_t;
/* Callback function type */
typedef void (*bear_notify_t)(const bear_msg_t *msg); ------------------声明 bear_notfify_t 类型的函数指针
/* 自定义设备结构体 */
typedef struct bear_device {
/**
* Common methods of the fingerprint device. This *must* be the first member
* of fingerprint_device as users of this structure will cast a hw_device_t
* to fingerprint_device pointer in contexts where it's known
* the hw_device_t references a fingerprint_device.
*/
struct hw_device_t common;
/*
* Client provided callback function to receive notifications.
* Do not set by hand, use the function above instead.
*/
bear_notify_t notify;
/*
* Set notification callback:
* Registers a user function that would receive notifications from the HAL
* The call will block if the HAL state machine is in busy state until HAL
* leaves the busy state.
*
* Function return: 0 if callback function is successfuly registered
* or a negative number in case of error, generally from the errno.h set.
*/
int (*set_notify)(struct bear_device *dev, bear_notify_t notify);
uint64_t (*test)(struct bear_device *dev);
int (*set_val)(struct bear_device *dev, int val);
int (*get_val)(struct bear_device *dev, int *val);
} bear_device_t;
/*自定义模块结构体*/
typedef struct bear_module {
/**
* Common methods of the bear module. This *must* be the first member
* of bear_module as users of this structure will cast a hw_module_t
* to bear_module pointer in contexts where it's known
* the hw_module_t references a bear_module.
*/
struct hw_module_t common;
} bear_module_t;
#endif /* ANDROID_INCLUDE_HARDWARE_BEAR_PI_H */
二,创建bearpi module 路径hardware/libhardware/modules/, 在bearpi目录下新建bearpi.c
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 "lemon"
#include <errno.h>
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include <log/log.h>
#include <hardware/bearpi.h>
#include <hardware/hardware.h>
#define DEVICE_NAME "/dev/bearpi"
bear_notify_t gNotify; //定义全局函数指针变量
void set_notify(bear_notify_t notify){
gNotify = notify;
}
static int bearpi_close(hw_device_t *dev){
struct bear_device_t* bear_device = (struct bear_device_t*) dev;
if(bear_device){
close(bear_device->fd);
free(bear_device);
return 0;
}else{
return -1;
}
}
/*设备寄存器读写接口*/
static int bearpi_get_val(struct bear_device* dev, int *val){
if(!dev){
ALOGE("bearpi device null pointer");
return -EFAULT;
}
if(!val){
ALOGE("bearpi val null pointer");
return -EFAULT;
}
read(dev->fd, val, sizeof(*val));
ALOGD(" bearpi get value = &d", *val);
return 0;
}
static int bearpi_set_val(struct bear_device* dev, int val){
if(!dev){
ALOGE("bearpi device null pointer");
return -EFAULT;
}
write(dev->fd, &val, sizeof(val));
ALOGD("bearpi set val success !");
return 0;
}
/*由上文hidl 调用注册回调*/
static int set_notify_callback(struct bear_device __unused *dev, bear_notify_t notify){
dev->notify=notify;
set_notify(notify);
ALOGD("%s",__func__ );
return 0;
}
/*调用test 之后通过函数指针作为回调函数,通知hidl 层,事件结果*/
static uint64_t bearpi_test(struct bear_device __unused *dev){
ALOGD("%s:start ",__func__ );
bear_msg_t msg;
bear_acquired_t acquired;
msg.type = BEAR_ACQUIRED;
acquired.acquired_info = BEAR_ACQUIRED_PARTIAL;
msg.data.acquired = acquired;
gNotify(&msg);
ALOGD("%s: end ",__func__ );
return 0;
}
static int bearpi_open(const hw_module_t* module, const char __unused *id, hw_device_t** device){
if(device == NULL){
ALOGE("NULL device on open");
return -EINVAL;
}
ALOGD("%s: start ",__func__ );
bear_device_t *dev = malloc(sizeof(bear_device_t));
if(!dev){
ALOGE("Failed to alloc space for bearpi");
return -EFAULT;
}
memset(dev, 0, sizeof(bear_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = BEAR_MODULE_API_VERSION_1_0;
dev->common.module = (struct hw_module_t*) module;
dev->common.close = bearpi_close;
dev->test= bearpi_test;
dev->set_notify = set_notify_callback;
dev->notify=NULL;
dev->set_val = bearpi_set_val;
dev->get_val = bearpi_get_val;
if((dev->fd = open(DEVICE_NAME, O_RDWR) == -1)){
ALOGE("Failed to open device /dev/bearpi!!!");
free(dev);
return -EFAULT;
}
*device = (hw_device_t*) dev;
ALOGD("%s: end",__func__ );
return 0;
}
static struct hw_module_methods_t bearpi_module_methods = {
.open = bearpi_open,
};
bear_module_t HAL_MODULE_INFO_SYM={
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = BEAR_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = BEAR_HARDWARE_MODULE_ID,
.name = "bear HAL module",
.author = "lemon",
.methods = &bearpi_module_methods,
},
};
三,创建Android.bp文件
cc_library_shared {
name: "bearpi.default",
relative_install_path: "hw",
//compile_multilib: "64",
proprietary: true,
srcs: ["bearpi.c"],
cflags: ["-Wno-unused-parameter",
"-Wno-unused-const-variable",
"-Wno-unused-variable"],
header_libs: ["libhardware_headers"],
shared_libs: ["liblog"],
}