Android HAL接口实现

总体结构

如果要实现一个HAL对应native层的接口,必须要明确一下整个结构。
HAL层的代码将会被封装成一个硬件模块,比如sensor.xxx.so的so库,该模块会通过kernel注册,然后在native代码层次调用该系统模块,使用其中的函数,类等等。
native层的实现可以有很多的用途,比如写成java的JNI实现,或则是编译成so库供其他的native层代码使用。

流程图

HAL层实现

HAL函数实现

自己比较熟悉的是Sensor传感器模块,就以这个模块为例。
首先,在libhardware/sensor.h文件中添加想要添加的功能函数的接口。

1
int (*get_val)(struct sensors_poll_device_t *dev,float* data);

然后在HAL层添加注册硬件模块的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct sensors_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: SENSORS_HARDWARE_MODULE_ID,
name: "XXX module",
author: "XXX",
methods: &sensors_module_methods,
dso: NULL,
reserved: {0}
},
get_sensors_list: sensors__get_sensors_list,
};

其中tag: HARDWARE_MODULE_TAG是固定的写法,这样写才能被kernel注册模块时所识别。

之后在HAL添加具体的函数实现

1
2
3
4
5
6
7
8
9
10
11
int sensors_poll_context_t::get_val(float* data){
LOGD("get_val into in HAL......");
int i;
//返回了0-15共16个数字做示例
for(i=0;i<16;i++)
{
data[i]=i;
}
return 0;
}

编译HAL代码成so库

编译的话就需要用到Android.mk文件了,语法不在细讲,需要根据自己的需求去更改。我的示例代码中,会生成一个snesors.xxx.so的库文件,这个so文件放至Android机器的system/lib/hw的文件夹下,就可以被使用了。

Native层实现

Native代码实现

可以新建 xxSensor.cpp和xxSensor.h文件,在cpp文件中实现module的打开。

1
2
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
(hw_module_t const**)&mSensorModule);

然后调用模块中的open函数打开sensor硬件(打开实际上就是传回了一个类,该类实现了HAL层的函数功能等等)

1
err = sensors_open_1(&mSensorModule->common, &mSensorDevice);

之后直接调用mSensorDevice->get_val()就能使用该函数了。
当然,在native层,我们还是封装一下这个调用比较好.

1
2
3
4
5
6
status_t SensorDevice::get_val(float* data){
if (!mSensorDevice) return NO_INIT;
int temp= mSensorDevice->get_val(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),data);
ALOGD("SensorDevice get_val");
return temp;
}

JAVA接口JNI的实现

关于JNI接口的编写,网上有很多同类的教程,我不在此多讲,老罗罗升阳的博客有很详细的讲解分析
在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口

封装成so库供其他的native层代码调用

在native层可以自己新建一个cpp和h文件,在里面直接使用SensorDevice的函数比如

1
2
3
4
5
int mySensor::get_val(float data[16]){
android::SensorDevice& dev(android::SensorDevice::getInstance());
ALOGD("mySensor get_val");
return dev.get_val(data);
}

如果想要封装成直接可以用dlopen打开的so库的话,可以添加一个extern"c"将函数开一个接口

1
2
3
4
5
6
7
extern "C"{
int n_get_val(float data[16])
{
return mySensor.get_val(data);
}
}

最后在mk文件中将自己写的代码编译成so库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=\
mySensor.cpp \
SensorDevice.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
libhardware_legacy \
libutils \
liblog \
libbinder \
libui \
libgui \
libsensorservice
LOCAL_MODULE:=mysensor
include $(BUILD_SHARED_LIBRARY)

其中SRC_FILE要包含自己的cpp文件和引用的cpp文件,SHARED_LIBRARIES文件则包含应用的所有库。
编译生成mysensor.so文件,最后将mysensor.so和mysensor.h给其他人就可以直接在native层使用了。

文章目录
  1. 1. 总体结构
  2. 2. HAL层实现
    1. 2.1. HAL函数实现
    2. 2.2. 编译HAL代码成so库
  3. 3. Native层实现
    1. 3.1. Native代码实现
    2. 3.2. JAVA接口JNI的实现
    3. 3.3. 封装成so库供其他的native层代码调用