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
来源:CSDN
作者:Gti-杠猪
链接:https://blog.csdn.net/qq_40083589/article/details/104196016