Android五层框架驱动编写(完整篇)
16lz
2021-01-25
Android五层框架驱动编写
一、框架介绍
1.应用程序层(java)
应用程序。
2.应用程序框架层(java)
与系统运行库被称为“C库层”相对应,应用程序框架层往往被冠以“JAVA库”的称号。这是因为框架层所提供的组件一般都是以JAVA语言编写而成,他一方面为上层应用程序提供了API接口;另一方面也囊括了不少系统级服务进程的实现,是与Android应用程序开发者关系最直接的一层。
3.系统运行库(C/C++)
这层中包含了支持整个系统正常运行的基础库,由于这些库多数都由C/C++实现,因此也被一些开发人员成为“C库层”,以区别于应用程序框架层。
4.硬件抽象层(C/C++)
(1)通过定义硬件“驱动”的接口来进一步降低Android系统与硬件的耦合度;
(2)由于Linux遵循的是GPL协议,而Android开源项目基于Apache协议,意味着其下的所有驱动都应该开源,这一点对于部分厂商来说无法接受;
5.Linux内核层(C)
Android系统是基于Linux操作系统的,严格来说,它属于Linux操作系统的一个变种。
好处:
(1)避免了与硬件直接打交道;
(2)基于Linux系统的驱动开发可扩展性很强;
二、编程示例
1.应用程序层(java)
文件:LedService.java
public class LedService{ static{ /**jni的调用过程:*1.补全库名*2.补全库的路径*3.dloped打开库*4.dlsym查找成员*/System.loadLibrary("native");}/* 声明native本地方法,然后应用回去jni中寻找本地方法 */public native int java_open();public native int java_ioctl(int which,int status);public native int java_close();public static void main(String args[]){ Hello hello = new Hello();System.out.println(hello.java_open());System.out.println(hello.java_ioctl(1,1));System.out.println(hello.java_close());}}
2.应用程序框架层(java)
3.系统运行库(C/C++)
文件:native.c
#define LOG_TAG "myjni"#include #include #include #include #include "hal.h"/* led_device结构体是hal层自己定义的,此结构体的第一个成员就是结构体就是hw_device_t 结构体 */struct led_device *led;jint c_open(JNIEnv *env, jobject self){ /* 只有涉及native方法的jni转换设计的方法返回值和参数列表转换为jint,jchar等,其余的变量还应遵守c规则 */int ret;/* ******** hw_modile_t 结构体定义 ***********typedef struct hw_module_t {const char *id; //id是stub的身份证号struct hw_module_methods_t* methods; //操作方法} hw_module_t; ******** hw_module_methods_t结构体定义 *********** typedef struct hw_module_methods_t {int (*open)(const struct hw_module_t* module, const char* id,struct hw_device_t** device);} hw_module_methods_t; ********* hw_device_t 结构体定义 *********** typedef struct hw_device_t {struct hw_module_t* module;int (*close)(struct hw_device_t* device);} hw_device_t;*/ustruct hw_module_t * module;struct hw_device_t * device; ALOGI("this is c_open\n");uu /* 通过调用hw_get_module,传入id值“myled” 得到hw_module_t 结构体 module*/ret = hw_get_module("myled",(const struct hw_module_t **)&module);if(ret == 0){ /* hw_module_t 结构体的成员结构体methods的open函数返回一个hw_device_t结构体 */ret = module->methods->open(module,"myled",&device);if(ret == 0){ /* 通过上面函数返回的hw_device_t结构体得到第一个成员hw_device_t 的指针。*将hw_device_t 强转为led_device就得到自定义的led_device结构体的指针了,*从而调用其自定义的hal_open()函数了。*/led = (struct led_device *)device;led->hal_open();}}return 123;}jint c_ioctl(JNIEnv *env, jobject self,jint which,jint status){ ALOGI("this is c_ioctl.\n"); ALOGI("c_ioctl:which = %d,status = %d\n",which,status);led->hal_ioctl(which,status); return 456; }jint c_close(JNIEnv *env, jobject self){ ALOGI("this is c_close.\n");led->hal_close();return 567;}/*在jni.h头文件中定义的typedef struct {char *name; //java中的方法名char *signature; //java中方法所对应的签名void *fnPtr; //c函数的名字} JNINativeMethod;*/JNINativeMethod methods[] = { [0] = { .name = "java_open", //java应用中native声明的方法名.signature = "()I", //jni转换的方法签名.fnPtr = (void *)c_open,//c中对应的函数名},[1] = { .name = "java_ioctl",.signature = "(II)I",.fnPtr = (void *)c_ioctl,},[2] = { .name = "java_close",.signature = "()I",.fnPtr = (void *)c_close,},};/* java遇到native方法会调用JNI_OnLoad */JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){ JNIEnv *env; jclass cls; //1.获取env if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) { return JNI_ERR; /* JNI version not supported */ }//2.找类 cls = (*env)->FindClass(env, "com/hqyj/led_app/LedService"); if (cls == NULL) { return JNI_ERR; }//3.本地方法映射,进行映射绑定(*env)->RegisterNatives(env, cls, methods,sizeof(methods)/sizeof(methods[0])); return JNI_VERSION_1_4;}
文件:Android.mk
LOCAL_PATH:=$(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE:=libnativeLOCAL_SRC_FILES:=native.cLOCAL_MODULE_PATH:=$(LOCAL_PATH)LOCAL_SHARED_LIBRARIES:=liblog libhardwareinclude $(BUILD_SHARED_LIBARY)
4.硬件抽象层(C/C++)
文件:hal.h
#ifndef __HAL_H__#define __HAL_H__struct led_device_t{ struct hw_device_t comm;int (*hal_open)();int (*hal_ioctl)(int which,int status);int (*hal_close)();}#endif
文件:hal.c
#include #include #include "hal.h"int led_hal_open(){ ALOGI("this is led_hal_open");return 0;}int led_hal_ioctl(int which,int status){ ALOGI("this is led_hal_ioctl");return 0;}int led_hal_close(){ ALOGI("this is led_hal_close");return 0;}struct led_device_t led_device = { .hal_open = led_hal_open,.hal_ioctl = led_hal_ioctl,.hal_close = led_hal_close,}int led_open(const struct hw_module_t* module,const char* id,struct hw_device_t** device){ /* 在native函数中通过调用hw_get_module函数,根据传进去的id。*找到结构体 hw_module_t ,通过 hw_module_t 找到 hw_module_methods_t 。*调用 hw_module_methods_t 结构体中的 open 函数 。*open 函数得到hw_device_t 结构体。*led_device_t 结构体中第一个成员就是 hw_device_t 结构体。*所以将 led_device 强转 led_device_t 得到 led_device_t 结构体指针。*从而通过led_device_t结构体访问我们自己定义的led_hal_open,led_hal_ioctl,led_hal_close。*/*device = (struct led_device_t *)&led_device;return 0;}struct hw_module_methods_t method = { .open = led_open,}/* 1.必须命名为HMI */struct hw_module_t HMI = { .id = "myled",.methods = &method,}
文件:Android.mk
LOCAL_PATH:=$(call my-dir)include $(CLEAR_VARS)#2.生成格式为:id.default.soLOCAL_MODULE:=myled.defaultLOCAL_SRC_FILES:=hal.cLOCAL_MODULE_PATH:=$(LOCAL_PATH)LOCAL_SHARED_LIBRARIES:=libloginclude $(BUILD_SHARED_LIBARY)
5.Linux内核层(C)
文件:led_driver.c
#include #include #include #include #include #include #include #include #include #include #include #include //GPF2#define PAD_LEDCON 0x01c208b4#define PAD_LEDDAT 0x01c208c4static struct cdev obj; //define cdev structstruct class *cls;static int major = 0; //主设备号static int minor = 0; //次设备号static int count = 1; //设备的数量dev_t dev; //设备号int i;unsigned int *pad_con = NULL;unsigned int *pad_dat = NULL;static int led_open(struct inode *inode, struct file *filp){ printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;}static ssize_t led_read(struct file *filp, char __user *buffer, size_t size, loff_t *offset){ printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;}static ssize_t led_write(struct file *filp, const char __user *buffer, size_t size, loff_t *offset){ printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;}static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);switch(arg){ case 1: writel((readl(pad_dat)&(~(1<<2))),pad_dat); //点亮ledbreak;case 0:writel((readl(pad_dat)|(1<<2)),pad_dat); //熄灭ledbreak;default :break;}return 0;}static struct file_operations fops = { .owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.unlocked_ioctl = led_ioctl,};static int __init kmmap_init(void){ int ret;struct device *device;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);cdev_init(&obj,&fops);ret = alloc_chrdev_region(&dev,minor,count,"myled");if(ret < 0){ //proc/device设备名printk("register device num fail.\n");goto ERROR1;}major = MAJOR(dev);ret = cdev_add(&obj,dev,count);if(ret < 0){ printk("register to kernel fail.\n");goto ERROR2;}cls = class_create(THIS_MODULE,"myled"); //sys/class下的名字if (IS_ERR(cls)) { ret = PTR_ERR(cls);goto ERROR2;}for(i=minor; i<count; i++){ device = device_create(cls,NULL,MKDEV(major,i),NULL,\"%s%d","myled",i);if (IS_ERR(device)) { ret = PTR_ERR(device);goto ERROR3;} }pad_con = (unsigned int *)ioremap(PAD_LEDCON,4);pad_dat = (unsigned int *)ioremap(PAD_LEDDAT,4);writel(((readl(pad_con)&(~(0xf<<8)))|(1<<8)),pad_con);writel((readl(pad_dat)|(1<<2)),pad_dat);return 0;ERROR3:for(i--; i >= minor; i--){ device_destroy(cls, MKDEV(major, i));}class_destroy(cls);ERROR2:unregister_chrdev_region(dev,count);ERROR1:cdev_del(&obj);return ret;}static void __exit kmmap_exit(void){ printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);for(i = minor; i < count+minor; i++){ device_destroy(cls, MKDEV(major, i));} class_destroy(cls);unregister_chrdev_region(dev,count);cdev_del(&obj);}module_init(kmmap_init);module_exit(kmmap_exit);MODULE_LICENSE("GPL");
文件:Makefile
export ARCH=armexport CROSS_COMPILE:=arm-linux-gnueabi-KERNELDIR:=/home/linux/fspad-733-6.0/lichee/linux-3.4/PWD:=$(shell pwd)all:make -C $(KERNELDIR) M=$(PWD) modulesclean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m:=led_driver.o
注意:
1.必须命名为HMI
#define HAL_MODULE_INFO_SYM HMI#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;/* dlsym打开动态库寻找名为HMI的结构体 */hmi = (struct hw_module_t *)dlsym(handle,sym);
2.生成hal库格式必须为:id.default.so
static const char *variant_key[] = { "ro.hardware", //sun8i "ro.product.board", //exdroid "ro.board.platform", //astar "ro.arch", //Null}
getprop "ro.hardware"可以达到键值对信息sun8i
所以可以命名为:myled.sun8i.so,myled.exdroid.so,myled.astar.so。
最后都无法匹配则寻找:myled.default.so。
为了避免平台相关性所以命名:myled.default.so。
3.库的路径必须/system/lib/hw
更多相关文章
- Android(安卓)6.0 新特性
- Android应用程序模型:应用程序,任务,进程,线程
- android 4.4 电池电量管理底层分析(C\C++层)
- Android学习笔记---自定义View#01
- Android培训班(41)
- Rexsee API介绍:Android音频录制,AudioRecorder函数与源码
- Android应用程序介绍页面实现 (二)
- Android(安卓)ContentResolver使用说明
- Android(安卓)Looper用法及原理