上一篇文章已经写了led驱动,这篇文章我们再封装HAL层
1.在源码hardware/libhardware/include/hardware/目录下增加test_led_hal.h
内容如下
#ifndef TEST_LED_HAL_H
#define TEST_LED_HAL_H
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define LED_HARDWARE_MODULE_ID "test_led"
//HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
//见hardware.h中的hw_module_t定义的说明,xxx_module_t的第一个成员必须是hw_module_t类型,其次才是模块的一此相关信息,当然也可以不定义,
//这里就没有定义模块相关信息
struct led_module_t {
struct hw_module_t common;
/* support API for LEDServices constructor */
};
//自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作
//见hardware.h中的hw_device_t的说明,要求自定义xxx_device_t的第一个成员必须是hw_device_t类型,其次才是其它的一些接口信息.
struct led_control_device_t {
struct hw_device_t common;
/* supporting control APIs go here */
int (*led_set_on)(struct led_control_device_t *dev);
};
#endif
2.在源码hardware\libhardware\modules目录下建一个目录test_led,再在该目录下面创建两个文件test_led_hal.c、Android.mk 内容分别如下:
#define LOG_TAG "LedStub"
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <sys/ioctl.h>
#include <hardware/test_led_hal.h>
#define LED_ON 0x4800
//硬件led的设备描述符 。你也可以用led_control_device_t结构中定义的fd
int fd;
static int led_device_close(struct hw_device_t* device) {
struct led_control_device_t* ctx = (struct led_control_device_t*) device;
if (ctx) {
free(ctx);
}
close(fd);
return 0;
}
static int led_set_on(struct led_control_device_t *dev) {
//FIXME: do system call to control gpio led
LOGI("led_set_on");
ioctl(fd, LED_ON, NULL);
return 0;
}
static int led_device_open(const struct hw_module_t* module, const char* name,
struct hw_device_t** device) {
struct led_control_device_t* dev = (struct led_control_device_t*) malloc(
sizeof(struct led_control_device_t)); //动态分配空间
if (!dev) {
LOGE("TestLed Stub: failed to alloc space");
return -EFAULT;
}
memset(dev, 0, sizeof(struct led_control_device_t));
//对dev->common的内容赋值,
dev->common.tag = HARDWARE_DEVICE_TAG; //必须为这个值
dev->common.version = 0;
dev->common.module = (hw_module_t*) module;
dev->common.close = led_device_close;
// 初始化控制 API
dev->led_set_on = led_set_on; //实例化支持的操作
//打开硬件设备
if ((fd = open("/dev/testLed2", O_RDWR)) == -1) {
LOGI("open error");
free(dev);
return -EFAULT;
} else {
LOGI("open ok\n");
}
//将实例化后的led_control_device_t地址返回给jni层 ,这样jni层就可以直接调用API方法了
*device = (struct hw_device_t *) (&(dev->common));
return 0;
}
static struct hw_module_methods_t led_module_methods = {
open: led_device_open
};
//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。
const struct led_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG, //必须为 HARDWARE_MODULE_TAG
version_major: 1,
version_minor: 0,
id: LED_HARDWARE_MODULE_ID,
name: "led HAL module",
author: "kk",
methods: &led_module_methods,//实现了一个open的方法供jni层调用, 从而实例化led_control_device_t
},
/* supporting APIs go here */
};
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test_led.default
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES := liblog libcutils lm -llog
# set shared libary out path
#TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib/hw
LOCAL_MODULE_PATH :=$(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SRC_FILES := test_led_hal.c
include $(BUILD_SHARED_LIBRARY)
3.重新编译,生成HAL层接口。APP可以直接通过jni代码调用HAL,也可以再封装一层SystemServer,SystemServer调用HAL,然后APP通过AIDL调用SystemServer
4.以下为jni调用的部分例子代码:com_android_server_test_led.cpp
#define LOG_TAG "LedService"
#include "utils/Log.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include "test_led_hal.h"
namespace android {
static led_control_device_t *sLedDevice = 0;
static led_module_t* sLedModule = 0;
static jint led_setOn(JNIEnv* env, jobject thiz) {
ALOGE("%s E", __func__);
if (sLedDevice) {
sLedDevice->led_set_on(sLedDevice); //调用hal层的注册的方法
} else {
ALOGE("sLedDevice is null");
}
return 0;
}
/** helper APIs */
static inline int led_control_open(const struct hw_module_t* module,
struct led_control_device_t** device) {
ALOGE("%s E ", __func__);
return module->methods->open(module, LED_HARDWARE_MODULE_ID,
(struct hw_device_t**) device);
//这个过程非常重要,jni通过LED_HARDWARE_MODULE_ID找到对应的stub
}
//hw_get_module获得一个hw_module_t结构体 ,调用 module->methods->open(module, device_name, &device) 获得一个hw_device_t结构体,并且把hw_device_t结构体转换为设备自定义的结构体
static jint led_init(JNIEnv *env, jclass clazz) {
led_module_t const * module;
ALOGE("%s E ", __func__);
if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**) &module)
== 0) {
//根据LED_HARDWARE_MODULE_ID找到hw_module_t,参考hal层的实现
ALOGE("get Module OK");
sLedModule = (led_module_t *) module;
if (led_control_open(&module->common, &sLedDevice) != 0) {
//通过hw_module_t找到led_control_device_t
ALOGE("led_init error");
return -1;
}
}
ALOGE("led_init success");
return 0;
}
//Framework层调用的映射,第一个参数为jni暴露给java的方法,第三个参数为jni层的方法,即为一个函数指针
//第二个参数:“()” 中的字符表示参数,后面的则代表返回值。例如”()V” 就表示void * Fun();
// “(II)V” 表示 void Fun(int a, int b);
// “(II)I” 表示 int addInt(int a, int b);
// "()Ljava/lang/String;" 表示String getStr();
static const JNINativeMethod gMethods[] = { { "led_init", "()I",
(void*) led_init }, { "set_on", "()I", (void*) led_setOn }, };
int register_android_server_TestLedService(JNIEnv* env) {
//注意:必须和你Framework层的service类名相同
// static const char* const kClassName = "com/android/server/test_led";
//或者jni暴露给java层的类所在路径相同,这里因为不做成SystemServer,所以名字可以修改为com/test/hardware/TestLed,只需要在app保护一个类com.test.hardware.TestLed.java即可,
static const char* const kClassName = "com/test/hardware/TestLed";
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
ALOGE("Can't find class %s\n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK) {
ALOGE("Failed registering methods for %s\n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}
/*
*
* java调用 System.loadLibrary触发该函数。因为在这里我们直接集成到libandroid_servers.so,所以这个函数不使用
*/
//jint JNI_OnLoad(JavaVM* vm, void* reserved) {
//
// JNIEnv* env = NULL;
// ALOGE("JNI_OnLoad");
//
// //从JavaVM获取JNIEnv,一般使用1.4的版本
// if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
// ALOGE("ERROR: GetEnv failed\n");
// return -1;
// }
//
// if (env == NULL) {
//
// ALOGE("ERROR: env is NULL\n");
// return -1;
// }
//
// if (register_android_server_TestLedServi(env) != 0) { //注册你的JNINativeMethod
// ALOGE("ERROR: PlatformLibrary native registration failed\n");
// return -1;
// }
// //这里很重要,必须返回版本,否则加载会失败
// return JNI_VERSION_1_4;
//}
}