前言
本节为HAL层模块访问Linux驱动程序,通过打开上一节创建的dev/helloxjq的设备文件来连接HAL和内核驱动程序模块。
一、创建
进入到在hardware/libhardware/include/hardware目录,新建helloxjq.h文件:
#ifndef ANDROID_HELLOXJQ_H
#define ANDROID_HELLOXJQ_H
#include <hardware/hardware.h>
__BEGIN_DECLS
/*定义模块ID,用与上层程序获取该模块*/
#define HELLOXJQ_HARDWARE_MODULE_ID "helloxjq"
/*硬件模块结构体*/
struct helloxjq_module_t {
struct hw_module_t common;
};
/*硬件接口结构体*/
struct helloxjq_device_t {
struct hw_device_t common;
int fd;
int (*write_string)(struct helloxjq_device_t* dev, char *str);
int (*read_string)(struct helloxjq_device_t* dev, char ** str);
};
__END_DECLS
#endif
进入到hardware/libhardware/modules目录,新建helloxjq目录,并添加helloxjq.c文件和Android.mk
Android.mk如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES += \
libcutils libutils liblog
LOCAL_LDLIBS:= -L$(SYSROOT)/usr/lib -llog
LOCAL_SRC_FILES := helloxjq.c
LOCAL_MODULE := helloxjq.default
include $(BUILD_SHARED_LIBRARY)
helloxjq.c内容如下:
#include <hardware/hardware.h>
#include <hardware/helloxjq.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define DEVICE_NAME "/dev/helloxjq"
#define MODULE_NAME "Helloxjqxjq"
#define MODULE_AUTHOR "xjq"
#define LOG_TAG "Helloxjq"
/* 定义LOG */
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__)
/*打开和关闭设备的方法*/
static int helloxjq_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int helloxjq_device_close(struct hw_device_t* device);
/*读写linux驱动的接口*/
static int helloxjq_write_string(struct helloxjq_device_t* dev, char * str);
static int helloxjq_read_string(struct helloxjq_device_t* dev, char **str);
/*模块方法结构体*/
static struct hw_module_methods_t helloxjq_module_methods = {
open: helloxjq_device_open
};
/*模块实例变量*/
struct helloxjq_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: HELLOXJQ_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &helloxjq_module_methods,
}
};
static int helloxjq_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
struct helloxjq_device_t* dev;
dev = (struct helloxjq_device_t*)malloc(sizeof(struct helloxjq_device_t));
if(!dev) {
LOGE("helloxjq: failed to alloc space");
return -EFAULT;
}
memset(dev, 0, sizeof(struct helloxjq_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = helloxjq_device_close;
dev->write_string = helloxjq_write_string;
dev->read_string = helloxjq_read_string;
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
LOGE("helloxjq: open /dev/helloxjq fail-- %s.", strerror(errno));free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("helloxjq: open /dev/helloxjq successfully.");
return 0;
}
static int helloxjq_device_close(struct hw_device_t* device) {
struct helloxjq_device_t* hello_device = (struct helloxjq_device_t*)device;
if(hello_device) {
close(hello_device->fd);
free(hello_device);
}
return 0;
}
static int helloxjq_write_string(struct helloxjq_device_t* dev,char * str) {
LOGI("helloxjq:write string: %s", str);
write(dev->fd, str, sizeof(str));
return 0;
}
static int helloxjq_read_string(struct helloxjq_device_t* dev, char ** str) {
read(dev->fd, *str, sizeof(*str));
LOGI("helloxjq:read string: %s", *str);
return 0;
}
二、修改
-
device_create创建的设备文件默认只有root用户可读写,而hello_device_open一般是由上层APP来调用的,这些APP一般不具有root权限,这时候就导致打开设备文件失败。解决办法很简单,打开Android源代码工程目录下,进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:
/dev/helloxjq 0666 root root
-
将安卓SElinux防火墙关闭,在system/core/init/init.cpp中
static bool selinux_is_enforcing(void)
函数中第一句之前加上return false
。此方法对于公司开发来说,很不安全,如果只是测试,可以这么操作,如果想不关闭防火墙又能访问,可以搜一下相关的权限的博客,讲解的很详细,按照所讲的步骤对源码进行修改即可。
三、编译
mmm hardware/libhardware/modules/ttt/
局部编译
编译完成再打包make systemimage
每次整编的时候,不会编译这个模块,所以make clean后或者修改这个模块的代码后,需要重新编译这个模块后,再整编。
四、验证
编译成功后,就可以在out/target/product/generic/system/lib/hw目录下看到helloxjq.default.so文件了,下载代码后通过ADB能在设备system/lib/hw下看到该模块。但是人不能判断该模块和上一节的驱动模块功能是否正常,因此我们写一个test测试程序验证。
在libhardware文件夹下新建tests文件夹,在tests文件夹下新建hello_testHAL,创建Android.mk文件和test.c文件,
Android.mk文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := my_test
LOCAL_LDLIBS:= -lhardware
LOCAL_SRC_FILES := $(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)
test.c内容如下
#include <hardware/hardware.h>
#include <hardware/helloxjq.h>
#include <fcntl.h>
#include <stdio.h>
struct hw_module_t * module;
struct hw_device_t * device;
int main(int argc, char *argv[]){
char *read_str;
char *write_str="nihao";
read_str = malloc(100);
char *ID = argv[1];
printf("----begin main------\n");
if(hw_get_module(ID,(struct hw_module_t const **)&module)==0){
printf("get module sucess\n");
}else{
printf("get module fail\n");
return -1;
}
if(module->methods->open(module,ID,(struct hw_device_t const**)&device)==0){
printf("open module sucess\n");
}else{
printf("open module error\n");
return -2;
}
struct helloxjq_device_t* dev = (struct helloxjq_device_t *)device;
dev->read_string(dev,&read_str);
if(read_str == NULL){
printf("read error");
}else{
printf("read data: %s\n",read_str);
}
dev->write_string(dev,write_str);
printf("write data: %s\n",write_str);
dev->read_string(dev,&read_str);
if(read_str == NULL){
printf("read error");
}else{
printf("read data: %s\n",read_str);
}
printf("----end main------\n");
return 0;
}
编译测试程序
mmm hardware/libhardware/tests/helloxjq_testHAL/
将在文件夹out/target/product/msm8937_32go/system/bin下生成my_test文件,
在该目录下打开windows终端,将该文件使用adb push到安卓设备system/app/目录下重命名为test,给test赋可执行权限,再运行test,注:运行test 第二个参数为生成的之前生成的xxx.default.so中的xxx。
adb root
adb remount
adb push my_test system/app/test
adb shell
cd system/app
chmod 777 test
./test helloxjq
查看输出结果,查看模块是否正常打开,读取和写入的是否正常。如果都正常,则进入下一节,否则就查看log,具体问题出现在哪儿。