android hal文件的编写

android hal文件的编写,第1张

概述一、hal主体框架解析hal:模板:hardware/libhardware/modules/overlay/如图所示jni与hal层主要数据结构和函数调用:首先jni层通过hw_get_module函数传入LED_MODULE_ID即hal库的字符串名称,来找到hal库并加载它,加载后为pmodule赋值拿到led_hw_module_t结构体实现。然后再通 一、hal主体框架解析

hal:模板:harDWare/libharDWare/modules/overlay/
如图所示jni与hal层主要数据结构和函数调用:


首先jni层通过hw_get_module函数传入LED_MODulE_ID 即hal库的字符串名称,来找到hal库并加载它,加载后为pmodule赋值拿到led_hw_module_t 结构体实现。
然后再通过pmodule->common.methods->open函数给pdevice赋值,拿到led_hw_device_t的结构体实现。
通过拿到对应的库再调用库内部函数来拿到关键结构device。然后就可以对device进行 *** 作了。
hal的开发主要是为了保护厂家私有代码而制定的一个架构。如果不考虑是否保护则直接用jni就可以了。

二、关键结构体源码:
hal:模板:harDWare/libharDWare/modules/overlay/// 模块 *** 作方法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;typedef struct hw_module_t {    /** tag must be initialized to HARDWARE_MODulE_TAG */    uint32_t tag; // 必须初始化成HARDWARE_MODulE_TAG    /** major version number for the module */    uint16_t version_major; // 主版本号: 1    /** minor version number of the module */    uint16_t version_minor; // 此版本号: 0    /** IDentifIEr of module */    const char *ID; // 动态库的文件名字    /** name of this module */    const char *name; // 动态库的简单描述:自定义    /** Author/owner/implementor of the module */    const char *author; // 作者: 自定义    /** Modules methods */    struct hw_module_methods_t* methods; // 方法    /** module's dso */    voID* dso; // 一般不用    /** padding to 128 bytes, reserved for future use */    uint32_t reserved[32-7]; // 保留,一般不用} hw_module_t;// device对象typedef struct hw_device_t {    /** tag must be initialized to HARDWARE_DEVICE_TAG */    uint32_t tag; //必须初始化成:HARDWARE_DEVICE_TAG    /** version number for hw_device_t */    uint32_t version; // 主版本号:1    /** reference to the module this device belongs to */    struct hw_module_t* module; //指向device所在的module对象    /** padding reserved for future use */    uint32_t reserved[12];    /** Close this device */    int (*close)(struct hw_device_t* device);} hw_device_t;

分别对应上面的
1、device结构体包含device *** 作方式

struct led_hw_device_t{ struct hw_device_t common;// 必须是这样的 // 以下为扩展部分 int (*led_on)(voID); int (*led_off)(voID);  };

2、给module结构体赋值;

// 必须有一个HMI变量struct led_hw_module_t HMI ={ common : {  tag : HARDWARE_MODulE_TAG,   version_major : 1,   version_minor : 0,   ID : LED_MODulE_ID,   name : "led hal sample",   author : "wukong",

3、给定module结构体中method的方法结构体

   methods : &my_methods, }};

4、实现method方法结构体中的open方法;

struct hw_module_methods_t my_methods ={ open : led_hal_open};
三、对应的androID.mk的编写
hal : AndroID.mk 的编写;LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SHARED_liBRARIES := \        libcutils#指定目标文件应该安装到哪个路径上LOCAL_MODulE_PATH := $(TARGET_OUT_SHARED_liBRARIES)/hwLOCAL_SRC_fileS := led_hal.c#指定目标动态库文件名,要和代码中的ID保持一致,加个.default后缀LOCAL_MODulE := myled_hal.defaultLOCAL_PRElink_MODulE := falseinclude $(BUILD_SHARED_liBRARY)jni文件的编写:jni调用hal的接口:1, int hw_get_module(const char * ID,const struct hw_module_t * * module)参数1: 动态库文件名,LED_MODulE_ID参数2: 执行模块的指针返回值: 正确为02,调用module中的方法 pModule->common.methods->open();编译jni文件的AndroID.mk的编写;LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)#jni调用hal的时候,需要连接libharDWare==>(hw_get_module)LOCAL_SHARED_liBRARIES := \        libcutils \        libharDWareLOCAL_C_INCLUDES += \        $(JNI_H_INCLUDE)LOCAL_SRC_fileS:= led_jni.cppLOCAL_MODulE:= libled_jniLOCAL_PRElink_MODulE := falseinclude $(BUILD_SHARED_liBRARY)
四、三个问题

1、为什么hal.so --> /system/lib/hw是放在这个目录下?
2、为什么必须有要将moudle定义为HMI变量
3、指定目标动态库文件名,要和代码中的ID保持一致,为什么要加个.default后缀

LOCAL_MODulE := myled_hal.defaulthw_get_module(LED_MODulE_ID, (const struct hw_module_t * * )&pModule); |  snprintf(path, sizeof(path), "%s/%s.default.so","/system/lib/hw", "myled_hal");   ==> "/system/lib/hw/myled_hal.default.so" if (access(path, R_OK)) // 测试文件是否存在 status = load(ID, path, module);     |// load(const char *ID,const char *path, const struct hw_module_t **pHmi)     handle = dlopen(path, RTLD_Now);      const char *sym = "HMI";      hmi = (struct hw_module_t *)dlsym(handle, sym);      *pHmi = hmi;// 必须有一个HMI变量struct led_hw_module_t HMI ={ common : {  tag : HARDWARE_MODulE_TAG,   version_major : 1,   version_minor : 0,   ID : LED_MODulE_ID,   name : "led hal sample",   author : "wukong",   methods : &my_methods, }在hw_get_module中传ID;LED_MODulE_ID

在hw_get_module中传ID;LED_MODulE_ID



所以即使jni文件引用了AndroID.mk里的hal动态库名,hal中仍然要规定一样的ID号;

五、代码编写步骤:


1、定义两个结构体分别为module和device结构体

struct led_hw_module_t{ struct hw_module_t common; // 必须是这样的 // 以下为扩展部分};struct led_hw_device_t{ struct hw_device_t common;// 必须是这样的 // 以下为扩展部分 int (*led_on)(voID); int (*led_off)(voID);  };

2、给module结构体赋值;

// 必须有一个HMI变量struct led_hw_module_t HMI ={ common : {  tag : HARDWARE_MODulE_TAG,   version_major : 1,   version_minor : 0,   ID : LED_MODulE_ID,   name : "led hal sample",   author : "wukong",

3、给定module结构体中method的方法结构体

   methods : &my_methods, }};

4、实现method方法结构体中的open方法;

struct hw_module_methods_t my_methods ={ open : led_hal_open};

5、匹配module结构体指针

int led_hal_open(const struct hw_module_t* module, const char* ID,            struct hw_device_t** device){ LOGD("---^_^ ---%s--\n", __FUNCTION__);

6、 构建mydevice对象

 struct led_hw_device_t *mydev = NulL; mydev = (struct led_hw_device_t *)malloc(sizeof(struct led_hw_device_t)); mydev->common.tag = HARDWARE_DEVICE_TAG; mydev->common.version = 1; mydev->common.module = module; ==>这一步有什么作用?可将module结构体中的信息传递给device对象; mydev->common.close = led_hal_close; mydev->led_on = hal_led_on; mydev->led_off = hal_led_off;

7、打开设备文件 *** 作底层驱动

 fd = open("/dev/led", O_RDWR); if(fd < 0) {  LOGE("open : %s\n", strerror(errno));  return -1; }

8、将构建好的mydevice对象返回给device对象则device可以调用device中定义的方法;

 *device = (struct hw_device_t*)mydev; return 0;}

9、具体构建device对象定义的方法;

int led_hal_close(struct hw_device_t* device){由于open方法中malloc的是led_hw_device_t结构体指针所以要释放也是对应的指针 struct led_hw_device_t *tmp; if(device != NulL) {    在这里将传进来的device还原;  tmp = (struct led_hw_device_t *)device;   后free掉  free(tmp); } if(fd > 0)  close(fd); return 0;}int hal_led_on(voID){ LOGD("---^_^ ---%s--\n", __FUNCTION__); int ret ; ret = ioctl(fd,LED_ON,NulL); if(ret < 0) {  LOGE("ioctl : %s\n", strerror(errno));  return -1; } return 0; }int hal_led_off(voID){ LOGD("---^_^ ---%s--\n", __FUNCTION__); int ret ; ret = ioctl(fd,LED_OFF,NulL); if(ret < 0) {  LOGE("ioctl : %s\n", strerror(errno));  return -1; } return 0;}

在jni层通过实现hw_get_module方法
包含相同的头文件则调用的方法也相同;这也就成了对应的关系了

ret = hw_get_module(LED_MODulE_ID, (const struct hw_module_t * * )&pModule); if(ret == 0) {  LOGD("hw_get_module ok");  if(pModule != NulL)  {可以理解为open之后device对象就有了匹配方法了   pModule->common.methods->open((const struct hw_module_t*)pModule, NulL, (struct hw_device_t**)&pDevice);  } }

即pDevice->led_off(); pDevice->led_off(); pDevice->common.close((struct hw_device_t *)pDevice);
jni中通过module的LED_MODulE_ID定义的字符串匹配hal层的模块匹配到后再调用hal层中的open方法调用设备方法;
其中的null可传入具体的设备号,如果有多个设备的话,即一个模块中集成了多个设备;
有多个ID是否有多个open函数;

jni 中的AdroID.mk文件的编写;

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SHARED_liBRARIES := \        libcutils \ libharDWare    ==>#jni调用hal的时候,需要连接libharDWare==>(hw_get_module)LOCAL_C_INCLUDES += \        $(JNI_H_INCLUDE)LOCAL_SRC_fileS:= led_jni.cppLOCAL_MODulE:= libled_jniLOCAL_PRElink_MODulE := falseinclude $(BUILD_SHARED_liBRARY)hal 文件的AndroID.mk的编写;LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SHARED_liBRARIES := \        libcutilsLOCAL_MODulE_PATH := $(TARGET_OUT_SHARED_liBRARIES)/hwLOCAL_SRC_fileS := led_hal.cLOCAL_MODulE := myled_hal.defaultLOCAL_PRElink_MODulE := falseinclude $(BUILD_SHARED_liBRARY)

库在文件系统中的摆放;

apk--> /system/appjni.so --> /system/lib cp -raf out/target/product/fs100/system/lib/libled_jni.so /opt/fs100_root/system/libhal.so --> /system/lib/hw cp -raf out/target/product/fs100/system/lib/hw/myled_hal.default.so /opt/fs100_root/system/lib/hw
总结

以上是内存溢出为你收集整理的android hal文件的编写全部内容,希望文章能够帮你解决android hal文件的编写所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1028412.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存