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

更多相关文章

  1. Android(安卓)6.0 新特性
  2. Android应用程序模型:应用程序,任务,进程,线程
  3. android 4.4 电池电量管理底层分析(C\C++层)
  4. Android学习笔记---自定义View#01
  5. Android培训班(41)
  6. Rexsee API介绍:Android音频录制,AudioRecorder函数与源码
  7. Android应用程序介绍页面实现 (二)
  8. Android(安卓)ContentResolver使用说明
  9. Android(安卓)Looper用法及原理

随机推荐

  1. Android input输入设备键值从底层到应用
  2. android直接读取项目中的sqlite数据库
  3. 【Flutter】认识目录结构
  4. android UI秘笈
  5. Android 资源,国际化,自适应
  6. 为什么我喜欢android
  7. Android 要注意的内存占用问题
  8. Android中配置和使用Google Map服务
  9. Android WindowManager与窗口管理
  10. 《Android4游戏编程入门经典》读后感