[置顶] 开发Android硬件抽象层模块接口
编写硬件抽象层模块接口分析
在阅读了“编写Android硬件抽象层相关规范说明”之后,我们应该很熟悉如何去定义和编写硬件抽象层模块接口了。下面即为本人实现的相关代码说明。
我们遵循Android源代码的相关习惯和规则,我想是有原因的;因此,我么也把编写的硬件抽象模块接口文件存放在hardware/libhardware/目录中。具体目录结构为(我的源代码放于Android文件夹中):
$Android/hardware/libhardware/
---Include
---hardware
---helloworld.h
---modules
---helloworld
---helloworld.cpp
---Android.mk
那么下面即为具体的实现代码说明。
头文件helloworld.h实现:
#ifndefANDROID_HELLOWORLD__INTERFACE_H
#defineANDROID_HELLOWORLD_INTERFACE_H
#include<hardware/hardware.h>
___BEGIN_DECLS
//定义模块编号
#defineHELLOWORLD_HARDWARE_MODULE_ID“helloworld”
//定义模块结构体
Structhelloworld_module_t{
Structhw_modult_tcommon;//第一个成员变量必须为 //hw_module_t类型
};
//定义设备编号
#defineHELLOWORLD_HARDWARE_DEVICE_H “helloworld”
//定义设备结构体
Structhelloworld_device_t{
Structhw_module_tcommon;//第一个成员变量必须为该类型
int(*set_val)(structhelloworld_device_t*dev,intval);
Int(*get_val)(structhelloworld_device_t*dev,int*val);
Intfd;
};
__END_DECLS
#endif
这个头文件中的常量和结构体的定义都是按照Android系统的规范来定义的。宏变量HELLOWORLD_HARDWARE_MODULT_ID和HELLOWORLD_HARDWARE_DEVICE_ID分别用来描述欲编写的模块和其对应的设备编号;而结构体变量helloworld_module_t和helloworld_device_t则代表着欲编写的模块结构体和对应的设备描述结构体类型,并且这两个结构体的第一个成员变量类型必须为hw_module_t结构体类型。另外,helloworld_device_t中的其他三个变量的含义分别为:函数指针set_val和get_val用来对欲访问的设别进行写和读的操作,而fd表示打开的设备文件/dev/helloworld的描述符,借助这个描述符,我们可以知道当前打开的设备的状态。
实现文件helloworld.cpp:
#defineLOG_TAG"HelloworldHALStub"
#include<hardware/hardware.h>
#include<fcntl.h>
#include<errno.h>
#include<cutils/log.h>
#include<cutils/atomic.h>
#include<hardware/helloworld.h>
#defineDEVICE_NAME"/dev/helloworld"
#defineMODULE_NAME"helloworld"
#defineMODULE_AUTHOR"xxx@sina.com"
/*
*相关函数方法的定义部分
*/
staticinthelloworld_device_open(conststructhw_module_t*module,constchar*id,structhw_device_t**device);
staticinthelloworld_set_val(structhelloworld_device_t*dev,intval);
staticinthelloworld_get_val(structhelloworld_device_t*dev,int*val);
staticinthelloworld_device_close(structhw_device_t*device);
staticstructhw_module_methods_thelloworld_module_methods={
open:helloworld_device_open
};
structhelloworld_module_tHAL_MODULE_INFO_SYM={
common:{
tag:HARDWARE_MODULE_TAG,
version_major:1,
version_minor:0,
id:helloworld_HARDWARE_MODULE_ID,
name:MODULE_NAME,
author:MODULE_AUTHOR,
methods:&helloworld_module_methods,
}
};
/*
*相关实现部分
*/
/*
*打开设备方法实现
*第一个参数代表与要打开的设备对应的模块
*第二个参数代表着在抽象层中可能多个的设备的唯一标示,即区分打开那个设备
*第三个参数代表想要打开的目标设备
*/
staticinthelloworld_device_open(conststructhw_module_t*module,constchar*id,structhw_device_t**device){
if(!strcmp(id,HELLOWORLD_HARDWARE_DEVICE_ID)){
structhelloworld_device_t*dev;
//为设备文件分配物理空间大小
dev=(structhelloworld_device_t*)malloc(sizeof(structhelloworld_device_t));
if(!dev){
LOGE("failedtoallocspaceforhelloworld_device");
return-EFAULT;
}
memset(dev,0,sizeof(structhelloworld_device_t));//设备驱动信号同步
dev->common.tag=HARDWARE_DEVICE_TAG;//成员变量tag必须为这个值
dev->common.version=0;
dev->common.module=(hw_module_t*)module;
dev->common.close=helloworld_device_close;//调用设备自身函数关闭设备
//操作设备的两个方法
dev->set_val=helloworld_set_val;
dev->get_val=helloworld_get_val;
//判断当前设备是否打开
if((dev->fd=open(DEVICE_NAME,O_RDWR))==-1){
LOGE("failedtoopendevicefile/dev/helloworld-----%s.",strerror(errno));
free(dev);
return-EFAULT;
}
*device=&(dev->common);
LOGI("opendevicefile/dev/helloworldsuccess.");
return0;
}
return-EFAULT;
}
/*
*第一个参数代表欲操作的设备
*第二个参数代表为操作的设备赋予的值
*/
staticinthelloworld_set_val(structhelloworld_device_t*dev,intval){
if(!dev){
LOGE("nulldevpointer.");
return-EFAULT;
}
LOGI("setvalue%dtodevicefile/dev/helloworld.",val);
write(dev->fd,&val,sizeof(val));//调用系统函数,通过对应的设备文件找到欲操作设备, //并将设定的值写入设备中
return0;
}
/*
*第一个参数代表操作的设备
*第二个参数表示从设别获取的值
*/
staticinthelloworld_get_val(structhelloworld_device_t*dev,int*val){
if(!dev){
LOGE("nulldevpointer.");
return-EFAULT;
}
if(!val){
LOGE("nullvalpointer.");
}
read(dev->fd,val,sizeof(*val));//调用系统函数,通过对应的设备文件找到欲操作设备, //并获取值,留给硬件访问服务读取显示
LOGI("getvalue%dfromdevicefile/dev/helloworld.",*val);
return0;
}
/*
*关闭设备,这个函数有设备自身提供调用来关闭对应设备
*唯一参数则代表欲关闭的设备
*/
staticinthelloworld_device_close(structhw_device_t*device){
structhelloworld_device_t*helloworld_device=(structhelloworld_device_t*)device;
if(helloworld_device){
close(helloworld_device->fd);
free(helloworld_device);
}
return0;
}
编译脚本文件Android.mk:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_MODULE_TAGS:=optional
LOCAL_PRELINK_MODULE:=false
LOCAL_SHARED_LIBRARIES:=liblog
LOCAL_SRC_FILES:=helloworld.cpp
LOCAL_MODULE:=helloworld.default
LOCAL_MODULE_PATH:=$(TARGET_OUT_SHARED_LIBRARIES)/hw
include$(BUILD_SHARED_LIBRARY)//代表将编译的文件编译成为动态链接库文件,名 //称为helloworld.default,并保存在/out/target/product/generic/system/lib目录中。
准备好所有文件之后,使用命令:mmm./hardware/libhardware/modules/helloworld/和makesnod进行编译;最后可以得到一个位于/out/target/product/generic/system/lib目录中的helloworld.default.so文件。这时一个动态的链接库文件。
编写完硬件抽象层模块接口之后,接下来就是为这个模块接口编写一个硬件访问服务,这个硬件访问服务是位于框架层,用来为应用程序提供访问设备硬件的服务接口。敬请期待,硬件访问服务的实现!
本人刚创建了一个QQ群,目的是共同研究学习Android,期待兴趣相投的同学加入!!
群号:179914858
更多相关文章
- 海康威视视频监控demo 源码+库文件
- Android studio 添加assets文件夹
- android R 文件生成不了
- 为Android应用程序读取/dev下设备而提权(二)
- Android 实现文件上传功能(upload)
- Android USB HID设备通信controlTransfer 接口参数
- Android清单文件详解(六) ---- 节点的属性
- android switch模块 (耳机检测)
- 面向 Android* 设备的英特尔® USB 驱动程序