Android五层框架驱动编写

余生长醉 提交于 2020-02-07 04:05:51

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!