Android五层框架驱动编写(完整篇)
zhilu.zhang
zhilu.zhang
发布于 2020-02-06 / 27 阅读 / 0 评论 / 0 点赞

Android五层框架驱动编写(完整篇)

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 <stdio.h>
#include <jni.h>
#include <cutils/log.h>
#include <hardware/hardware.h>
#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;
        */u
        struct 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 JNICALL
JNI_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:=libnative
LOCAL_SRC_FILES:=native.c
LOCAL_MODULE_PATH:=$(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES:=liblog libhardware
include $(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 <cutils/log.h>
#include <hardware/hardware.h>
#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.so
LOCAL_MODULE:=myled.default
LOCAL_SRC_FILES:=hal.c
LOCAL_MODULE_PATH:=$(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES:=liblog
include $(BUILD_SHARED_LIBARY)

5.Linux内核层(C)

文件:led_driver.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mm.h>
#include <asm/io.h>
                //GPF2
#define PAD_LEDCON 0x01c208b4
#define PAD_LEDDAT 0x01c208c4

static struct cdev obj;  //define cdev struct
struct 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);  //点亮led
                        break;
                case 0:
                        writel((readl(pad_dat)|(1<<2)),pad_dat);   //熄灭led
                        break;
                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=arm
export 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) modules
clean:
        make -C $(KERNELDIR) M=$(PWD) clean

obj-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