Android驱动程序编写过程记录
来源:互联网 发布:常见网络中间设备 编辑:程序博客网 时间:2024/04/29 10:26
本文仅仅记录开发Android驱动程序的一个过程,以供以后编写驱动进行参考
第一步:当然就是编写LINUX内核层的驱动程序了,这个很通用的一层,编写后不管是集成在内核中还是单独的ko文件,到最后
系统启动后都需要在dev目录下生成设备节点。
第二步:就是所谓的HAL层,这层代码一般放在hardware/xxx/目录中,这层跟内核中的代码类似,都是C代码,但是该层操作dev
目录下生成的设备节点,同时也为Android层操作做准备,把可以提供给Android层的功能写一遍
该文件需要定义一个结构
struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = KEYLED_HARDWARE_MODULE_ID, .name = "Keypad LED Stub", .author = "INST Wgj", .methods = &led_module_methods,};名字必须是HAL_MODULE_INFO_SYM
HARDWARE_MODULE_TAG也是固定的
KEYLED_HARDWARE_MODULE_ID是自定义的,之后JNI层查找就是根据该ID查找的,这里要注意一点
KEYLED_HARDWARE_MODULE_ID的定义为一个字符串,此字符串定义要与Android.mk中的LOCAL_MODULE定义一致,否则在JNI层
初始化调用hw_get_module函数时会失败,现在做的驱动LOCAL_MODULE := keypadleds.$(TARGET_BOARD_PLATFORM)
那么KEYLED_HARDWARE_MODULE_ID就得定义为“keypadleds”,不能为其他,因为系统查找是根据文件名查找的竟然。。。。
led_module_methods定义,里面包含的是公共方法
static struct hw_module_methods_t led_module_methods = { open: led_device_open};然后呢在open方法中对设备控制结果进行初始化,驱动方法都在此函数中进行赋值
static int led_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){ struct led_control_device_t *tmp_dev; tmp_dev = (struct led_control_device_t *)malloc(sizeof(*tmp_dev)); if (!tmp_dev){ return -EINVAL; } memset(tmp_dev, 0, sizeof(*tmp_dev)); tmp_dev->common.tag = HARDWARE_DEVICE_TAG; tmp_dev->common.version = 0; tmp_dev->common.module = module; tmp_dev->common.close = led_device_close; tmp_dev->set_on = led_on; tmp_dev->set_off = led_off; tmp_dev->get_count = get_count; *device = &tmp_dev->common; if ((led_fd = open(LED_DEVICE, O_RDWR)) == -1){ LOGE("LED open error"); return -EINVAL; } // 打开设备后先读取下LED灯的总数量 ioctl(led_fd, CMD_COUNT, &led_count); return 0;}led_control_device_t结构定义
// 定义一个继承自hw_device_t的结构, 记录本stub操作设备时需要包括的接口
struct led_control_device_t { struct hw_device_t common; // 操作句柄 int fd; // 打开指定序号LED灯 int (*set_on)(struct led_control_device_t *dev, int32_t led); // 关闭指定序号LED灯 int (*set_off)(struct led_control_device_t *dev, int32_t led); // 获取LED灯的数量 int (*get_count)(struct led_control_device_t *dev);};结构以及宏定义都需要定义在一个头文件中,因为JNI层也需要该头文件。。。
到这里HAL层基本就OK了,编译完成后会在system/lib/hw中生成对应的so动态库,JNI层就会操作这个动态库
第三步:编写JNI层
这时候就需要到frameworks目录下了,我为了管理方便在该目录下直接建立了一个专门目录,虽然不符合要求。。。
进入到我的目录,建立个java目录跟jni目录。进入jni目录
将刚才HAL层的头文件建立个超链接引过来
建立个cpp文档,这个文档就是JNI层的具体实现文档,该文档命名也有要求com_xxx_xxx_类名.cpp
在该文档中入口函数为JNI_OnLoad
jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env = NULL;jint result = -1;//ALOGI("JNI_OnLoad LED"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {ALOGE("ERROR: GetEnv failed\n");goto fail;} assert(env != NULL);if (registerMethods(env) != 0) {ALOGE("ERROR: PlatformLibrary native registration failed\n");goto fail;}// success -- return valid version numberresult = JNI_VERSION_1_4;fail:return result;}
registerMethods函数自己写用来实现方法的注册
该文档中对下操作led_control_device_t定义的设备,对led_control_device_t中实现的方法进行包装
然后声明到方法中以供JAVA层调用,如下定义:
static const JNINativeMethod gMethods[] = {{ "_init", "()Z",(void *)instisu_init },{ "_set_on", "(I)Z", (void *)instisu_setOn },{ "_set_off", "(I)Z", (void *)instisu_setOff },{ "_get_count", "()I", (void *)instisu_getCount },};在init函数中有使用hw_get_module(KEYLED_HARDWARE_MODULE_ID, (hw_module_t const**)&module)获取设备
就在这里系统会根据KEYLED_HARDWARE_MODULE_ID去查找HAL层生成的so动态库文件
然后对设备对象进行各种操作
这部分代码需要生成一个运行库以供JAVA层调用,真麻烦。。。
JAVA层不能调用HAL层生成的库而只能用JNI层的库?太深奥。。。
到这里该层就可以进行编译,会在system/lib目录下生成一个so库
第四步:framework中的Sever实现,就是JAVA层了
到第三步新建的目录中,进入java目录,然后新建com....等目录,进入hardware目录中新建IXXXService.aidl文档,在其中
声明接口
interface IXXXService
{
boolean setOn(int led);
boolean setOff(int led);
int getCount();
}
在同级的server目录中,新建XXXServer.java文件
继承IXXXService.Stub
在该类中加载JNI层生成的so库
System.load("/system/lib/libinstisu_runtime.so");
在该类中将JNI层提供的方法包装为JAVA方法。
然后呢既然是系统驱动了,让其他应用可以调用,得需要在/system/etc/permission目录下有相应的xml文档声明才行
如:com.instisu.server.xml
内容
<?xml version="1.0" encoding="utf-8"?><permissions> <library name="com.instisu.server" file="/system/framework/instisu.jar"/></permissions>
该文档可以放到自定义目录的根目录下,然后编写Android.mk
在编写Android.mk时需要注意不能添加LOCAL_SDK_VERSION := current项,否则会出现
cannot find symbol
symbol : class ServiceManager
location: package android.os
import android.os.ServiceManager
之类错误
LOCAL_MODULE 要与xml文档中的file设置一致,否则让人家系统怎么找
至此Android的驱动部分就基本完成了
然而,你编译成功后却会发现你生成的jar文档使用现有的编程工具无法使用,因为已经默认为dex化了,不管Eclipse或者Android studio都无法解析,
其实只要进入target/common/obj/JAVA_LIBRARIES目录中找你相应的xxx_intermediates就可以了,里面的classes.jar即可使用
再然后,在使用Eclipse时你可以直接添加自定义系统库,让刚才的jar文件引入工程,而不需要将改jar文件放到工程目录中。。。。
- Android驱动程序编写过程记录
- Makefile编写过程记录
- 为Android系统编写Linux内核驱动程序
- Ubuntu上为Android编写驱动程序
- Android系统编写Linux内核驱动程序
- 转载只为记录经典之<Linux驱动程序编写演示----编译驱动程序 >
- 步进电机程序编写过程的记录!
- 驱动程序过程
- Android之编写C程序访问Android之驱动程序
- android OpenGl 游戏编写过程
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- Shiro实现用户授权(Authorization)
- 分拣存储2-统计学生每个班级的总分和平均分
- 2016SDAU编程练习二1019
- stm32+lwip的物联网开发——学习过程(1)
- 分类算法-决策树之:id3 算法
- Android驱动程序编写过程记录
- TextView maxWidth maxLength maxEms 区别
- 类的初识与构造函数
- Mybatis的延迟加载
- Android实战开发之ViewPager图片回收处理内存溢出完美解决方案(含Fragment)
- iOS用ASIFormDataRequest实现图片上传
- 核心动画(关键帧动画)
- python常用常用函数
- ACM刷题之HDU————Joseph