ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

android访问应用程序第2步:实现hal层

2021-06-07 23:59:40  阅读:247  来源: 互联网

标签:hal struct hw module 应用程序 device android hellotest dev


文章目录


在android系统中会提供hal层,即hardware层来封装对Linux的驱动访问,同时会为上层提供一个统一的硬件接口

1.hardware层概述

1.1 主要数据结构

在hal层,会有以下三个结构体

  • struct hw_module_t
  • struct hw_module_methods_t
  • struct hw_device_t

1.2 上层访问驱动流程

原文:参考Android应用程序访问linux驱动第二步:实现并测试hardware层
使用hw_get_module()方法获取hal层对应的module,函数通过给定模块的ID来寻找硬件模块的动态链接库,找到后使用load()函数打开这个库,并通过一个固定的符号-HAL_MODULE_INFO_SYM寻找hw_module_t结构体,我们会在hw_module_t结构体中会有一个methods属性,指向hw_module_methods_t结构体,这个结构体中会提供一个open方法用来打开模块,在open的参数中会传入一个hw_device_t**的数据结构,这样我们就可以把对模块的操作函数等数据保存在这个hw_device_t结构中,这样,这样用户可以通过hw_device_t来和模块交互。

1.3 Hal伪代码示例

具体的说,我们在上层可以这样调用HAL层的module:

xxx_module_t *module;
hw_get_module(XXXID,(struct hw_module_t **)&module);
以上两步我们就获得了对应ID的 hw_module_t结构体。
struct xxx_device_t *device;
module->methods->open(module,XXXID,(struct hw_device_t **)&device);
这样我们就获得了hw_device_t结构体,通过hw_device_t结构体我们就可以访问HAL层对应的module了。

整个过程可用一张图展示:
在这里插入图片描述

2.实现hal对于驱动的访问

在asop源码目录下hardware/libhardware/modules新建hellotest目录,添加两个文件:hellotest.c 和 Android.mk

2.1 hellotest.c

/******************************************************************************
* @file    	hellotest.c
* @brief   	测试hellotest驱动
* @note    	实现驱动访问相关函数
* @author 	无
* @version 	1.0.0
* @date    	2020-6-05
* 修改记录:
*******************************************************************************/

/******************************************************************************
								  头文件
*******************************************************************************/
#include <hardware/hardware.h>
#include <hardware/hellotest.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>

/******************************************************************************
                                宏定义
*******************************************************************************/

#define DEVICE_NAME 	"/dev/hello"
#define MODULE_NAME		"HelloTest"
#define	MODULE_AUTHOR   "klz"

/* 定义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 hellotest_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int hellotest_device_close(struct hw_device_t *device);
static int hellotest_write_string(struct hellotest_device_t *dev,char *str);
static int hellotest_read_string(struct hellotest_device_t *dev,char **str);

//模块方法结构体
static struct hw_module_methods_t hellotest_module_methods = {
	.open = hellotest_device_open,
};

//模块实例变量
struct hellotest_module_t HAL_MODULE_INFO_SYM = {
	  .common = {
        .tag                    = HARDWARE_MODULE_TAG,
        .module_api_version     = HELLOTEST_HARDWARE_MODULE_API_VERSION_1_0,
        .hal_api_version        = HARDWARE_HAL_API_VERSION,
        .id                     = HELLOTEST_HARDWARE_MODULE_ID,
        .name                   = "hello test",
        .author                 = "The Android Open Source Project",
        .methods                = &hellotest_module_methods,
    }
};

/*******************************************************************************
* @name   	hellotest_device_open
* @brief  	打开驱动
* @param  	const struct hw_module_t* module  [IN] 打开的模块
* @param  	const char* name     			  [IN] 模块ID
* @param  	struct hw_device_t** device       [IN] 从open函数中获取到的hellotest_device_t
* @return 	int                               [OUT] 函数的返回值,0:EOK,-1:Error
*******************************************************************************/
static int hellotest_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
{
	struct hellotest_device_t *dev;
	dev = (struct hellotest_device_t*)malloc(sizeof(struct hellotest_device_t));
	
	if(!dev)
	{
		LOGE("%s,failed to alloc space\n",__FUNCTION__);
		return -EFAULT;
	}
	
	memset(dev,0,sizeof(struct hellotest_device_t));
	
	dev->common.tag = HARDWARE_DEVICE_TAG;
	dev->common.version = 0;
	dev->common.module = (hw_module_t*)module;
	dev->common.close  = hellotest_device_close;  
	dev->write_string  = hellotest_write_string;
	dev->read_string   = hellotest_read_string;
	
	if((dev->fd = open(DEVICE_NAME,O_RDWR)) == -1)
	{
		LOGE("%s,open %s failed\n",__func__,DEVICE_NAME);
		return -EFAULT;
	}
	
	*device = &(dev->common);
	 LOGI("HelloTest: open /dev/hello successfully."); 
	
	return 0;
}

/*******************************************************************************
* @name    	hellotest_device_close
* @brief   	关闭驱动
* @param   	struct hw_device_t** device       [IN] 从open函数中获取到的hellotest_device_t
* @return  	int                               [OUT] 函数的返回值,0:EOK,-1:Error
*******************************************************************************/
static int hellotest_device_close(struct hw_device_t *device)
{
	LOGI("%s\n");
	struct hellotest_device_t *hello_device = (struct hellotest_device_t *)device;
	
	if(hello_device)
	{
		close(hello_device->fd);
		free(hello_device);
	}
	
	return 0;
}

/*******************************************************************************
* @name   	 hellotest_write_string
* @brief  	 向驱动中写入字符串
* @param  	 struct hw_device_t* device      [IN] 要写入的hw_device
* @param  	 char *str                       [IN] 写入的字符串
* @return 	 int                             [OUT] 函数的返回值,0:EOK,-1:Error
*******************************************************************************/
static int hellotest_write_string(struct hellotest_device_t *dev,char *str)
{
	LOGI("%s\n",__func__);
	write(dev->fd,str,sizeof(str));
	return 0;
}

/*******************************************************************************
* @name   	 hellotest_read_string
* @brief  	 从驱动中读取字符串
* @param  	 struct hw_device_t*device	 [IN] 要读取的hw_device
* @param  	 char **str                  [IN] 读取的字符串
* @return 	 int                         [OUT] 函数的返回值,0:EOK,-1:Error
*******************************************************************************/
static int hellotest_read_string(struct hellotest_device_t *dev,char **str)
{
	LOGI("%s\n",__func__);
	read(dev->fd,*str,sizeof(*str));
	return 0;
}

经过上面操作我们可以实现hal层中hw_device_t结构体中的方法操作Linux驱动

2.2 Android.mk

# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellotest.default
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_PROPRIETARY_MODULE := true
LOCAL_SRC_FILES := hellotest.c
LOCAL_C_INCLUDES := hardware/libhardware/include
LOCAL_HEADER_LIBRARIES := libhardware_headers
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-implicit-function-declaration
include $(BUILD_SHARED_LIBRARY)

注意:LOCAL_MODULE 的值为hellotest.default,hellotest一定要加上default,不然使用hw_get_module函数找不到我们的HAL模块。

2.3 hellotest.h

在hardware/libhardware/include/hardware编写头文件hellotest.h

/******************************************************************************
* 文 件 名: hellotest.h  
* 功能描述: 测试hello驱动
* 作    者: 无
* 版 本 号: 1.0.0 
* 修改日期: 2021-6-05
* 修改记录:
*******************************************************************************/

#ifndef ANDROID_HELLO_TEST_H
#define ANDROID_HELLO_TEST_H
#include <hardware/hardware.h> 

__BEGIN_DECLS

/******************************************************************************
                                宏定义
*******************************************************************************/
#define HELLOTEST_HARDWARE_MODULE_ID "hellotest" //ID值,必须,用于上层获取该模块
#define HELLOTEST_HARDWARE_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1,0) //API版本
/******************************************************************************
                              变量与数据结构等定义
*******************************************************************************/

struct hellotest_module_t {
	struct hw_module_t common;
};

struct hellotest_device_t {//硬件接口结构体
	struct hw_device_t common;
	int fd;
	int (*write_string)(struct hellotest_device_t *dev,char *str);
	int (*read_string)(struct hellotest_device_t *dev,char **str);
};

__END_DECLS

#endif

2.4 编译hal模块

直接进入到hardware/libhardware/modules/hellotest目录,执行mm命令进行编译

3.编写测试代码

在hardware/libhardware/tests/目录下新建一个hellotest目录,新增hellotest.c和Android.mk文件:

3.1 hellotest.c

#include <hardware/hardware.h>  
#include <hardware/hellotest.h>  
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

struct hw_module_t * module;
struct hw_device_t * device;

int main(){
    char *read_str;
    char *write_str="hellotest";
    read_str = malloc(100);
   
    if(hw_get_module(HELLOTEST_HARDWARE_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,HELLOTEST_HARDWARE_MODULE_ID,(struct hw_device_t const**)&device)==0)
    {
        printf("open module sucess\n");
    }
    else
    {
        printf("open module error\n");
        return -1;
    }
    struct hellotest_device_t* dev = (struct hellotest_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);
    }
   
   return 0;
}

3.2 测试代码调用流程

先使用hw_get_module函数获得hw_module_t结构体,再调用hw_module_methods_t结构体中的open方法获得hw_device_t结构体,然后使用hw_device_t结构体中的read_string和write_string方法与linux驱动交互,驱动的打开是在hw_module_methods_t结构体中的open方法中做的。

3.3 Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := hellotest
LOCAL_LDLIBS:=  -lhardware
LOCAL_C_INCLUDES := hardware/libhardware/include
			
LOCAL_SRC_FILES := $(call all-subdir-c-files)

include $(BUILD_EXECUTABLE)

然后进入到该目录执行mm命令进行编译

4.测试

  • 把生成的hellotest.default.so文件拷贝到android设备的/system/lib/hw目录下,这需要root权限,没有root权限请自行解决。
  • 获得root权限后会提示/system是一个只读文件系统,所以需要重新挂载为可读可写的文件系统,执行mount -o remount,rw /system 即可。
  • 修改hellotest.default.so文件的的权限为644,执行chmod 644 /system/lib/dw/hellotest.default.so
  • 装载上一节实现的hello.ko驱动:insmod hello.ko
    链接Android应用程序访问linux驱动第一步:实现并测试Linux驱动
  • 把生成的my_test可执行文件拷贝的android设备上,建议push hellotest/data
  • 给my_test文件添加可执行权限. chmod +x hellotest
  • 执行hellotest。 ./hellotest
    打印如下:
get module sucess
open module sucess
read data: hello
write data: hellotest
read data: hellotest

可见,测试成功。
如果有问题,可以使用logcat看下HAL层的打印,看看问题出在什么地方。

标签:hal,struct,hw,module,应用程序,device,android,hellotest,dev
来源: https://blog.csdn.net/weixin_43824344/article/details/117648247

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有