1、前言

Android系统使用HAL这种设计模式,使得上层服务与底层硬件之间的耦合度降低,在文件:

AOSP/hardware/libhardware/include/hardware/hardware.h

中描述了HAL的编写规范,并且给出了标准接口,本文将通过一个简单的实例讲解HAL的编写。

2、HAL编写规范

在之前的文章中讲解了两个很重要的数据结构,struct hw_module_t和struct hw_device_t,在其中hw_module_t代表了整个HAL的实现、功能的封装,也是外部应用程序看到的唯一视角,而hw_device_t代表了一个实际的硬件设备,是设备的属性、设备操作的封装,接下来分析HAL的编写规范。

(1)定义代表module的数据结构

以LED HAL模块为例,首先需要定义一个表示LED模块的数据结构led_moduler_t,并且该数据结构遵循以下准则:

(1.1)该结构体中的第一个成员必须是struct hw_module_t;

(1.2)创建一个该数据结构体的变量,并以HAL_MODULE_INFO_SYM为变量名;

(1.3)结构体hw_module_t中的tag成员固定赋值为HARDWARE_MODULE_TAG;

(1.4)结构体hw_module_t中的module_api_version成员代表了HAL模块的API版本,当模块的接口发生改变时,开发人员必须更新该成员;

(1.5)结构体hw_module_t中的id成员是该模块的标识符,其它程序通过该成员来寻找对应HAL得Stub。

实现如下所示:

#include <hardware/hardware.h>

typedef struct led_module {
struct hw_module_t common;
...
...
} led_module_t; struct led_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = LED_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = LED_HARDWARE_MODULE_ID,
.name = "Defaule Led HAL",
.author = "hly",
.methods = &led_module_methods,
},
...
...
};

(2)定义代表device的数据结构

通过module并不能实际操作硬件设备,开发者需要将设备的相关属性以及操作封装在代表device的数据结构,该数据结构通常是一系列的函数指针,定义led_device_t结构体,该数据结构遵循以下规则:

(2.1)第一个成员必须是struct hw_device_t;

(2.2)结构体中的hw_device_t的tag成员必须被赋值为HARDWARE_DEVICE_TAG。

实现如下所示:

typedef struct led_device {
struct hw_device_t common;
int (*get_led_state)(struct led_device *dev, char **state);
int (*set_led_state)(struct led_device *dev, char *state);
...
...
} led_device_t;

(3)实现open函数

当其它的应用程序使用HAL模块的步骤通常是:

首先通过hw_get_module()函数获得指定HAL模块的hw_module_t的引用,然后调用hw_module_t->methods->open函数或得hw_device_t的引用,最后,通过device下的函数指针来操作设备。

open函数指针位于hw_module_methods_t结构体中,该函数的实现方法在不同的HAL模块中实现也较为类似,大体步骤为:

(3.1)为led_device_t结构分配内存空间;

(3.2)对hw_device_t类型的common成员进行赋值;

(3.3)对封装的结构体中的函数指针进行赋值;

(3.4)将分配空间的led_device_t的指针通过hw_device_t **device返回。

实现如下所示:

static int led_device_open(const struct hw_module_t *module,
const char *id, struct hw_device_t **device)
{
struct led_device *dev; dev = malloc(sizeof(struct led_device));
if (!dev) {
ALOGE("Failed to malloc memory");
return -ENOMEM;
}
memset(dev, , sizeof(led_device)); dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = MODULE_API_VERSION_1_0;
dev->common.module = (struct hw_module_t *)module; dev->get_led_state = get_led_state;
dev->set_led_state = set_led_state;
...
...
... *device = (struct hw_device_t *)dev;
return ;
}

(4)实现device的具体操作接口

每个HAL模块的实现都比较类似,对于device下的操作方法,则要按照具体的设备进行实现,每一类设备都是不尽相同的,需要掌握Linux应用层中文件操作、进程管理、信号处理、多线程编程和网络编程等相关技术。

3、实例讲解

实现一个ledctrl的HAL模块:

首先在安卓源码下的hardware/libhardware/include/hardware目录下创建ledctrl.h文件,代码如下:

#ifndef ANDROID_LEDCTRL_INTERFACE_H
#define ANDROID_LEDCTRL_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS /* 定义模块ID */
#define LEDCTRL_HARDWARE_MODULE_ID "ledctrl" /* 硬件模块结构体 */
struct ledctrl_module_t {
struct hw_module_t common;
}; /* 硬件接口结构体 */
struct ledctrl_device_t {
struct hw_device_t common; int fd;
int (*set_state)(struct ledctrl_device_t *dev, const char *state);
int (*get_state)(struct ledctrl_device_t *dev, char **state);
}; __END_DECLS #endif

然后在安卓源码的hardware/libhardware/modules目录下,新建ledctrl目录,并添加ledctrl.c文件,代码实现如下:

#define LOG_TAG "ledctrl_hw_default"

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> #include <cutils/log.h> #include <hardware/hardware.h>
#include <hardware/ledctrl.h> #define DEVICE_NAME "/sys/class/leds/led-red/brightness"
#define MODULE_NAME "ledctrl"
#define MODULE_AUTHOR "HLY" /* 设备访问接口 */
static int ledctrl_set_state(struct ledctrl_device_t *dev, const char *state)
{
int ret = -EINVAL; if ( == strcmp(state, "enable")) {
ret = write(dev->fd, "", );
if (ret != ) {
ALOGE("ledctrl: failed to enable led device");
goto exit;
}
ALOGI("ledctrl: successed to enable led device");
ret = ;
} else if ( == strcmp(state, "disable")) {
ret = write(dev->fd, "", );
if (ret != ) {
ALOGE("ledctrl: failed to close led device");
goto exit;
}
ALOGI("ledctrl: successed to disable led device");
ret = ;
} else
ALOGE("ledctrl: not define the led device state"); exit:
return ret;
} static int ledctrl_get_state(struct ledctrl_device_t *dev, char **state)
{
int ret,value;
char *buf = malloc(sizeof(char) * ); memset(buf, , sizeof(char) * );
ret = read(dev->fd, buf, sizeof(int));
if (ret < ) {
ALOGE("ledctrl: failed to read led device");
goto exit;
} value = atoi(buf);
if (value == )
*state = "disable";
else
*state = "enable";
ALOGD("value = %d, led_state = %s", value, *state); exit:
free(buf);
return ret;
} /* 设备的打开和关闭接口 */
static int ledctrl_device_close(struct hw_device_t *device)
{
struct ledctrl_device_t *dev = (struct ledctrl_device_t *)device; if (dev) {
close(dev->fd);
free(dev);
} return ;
} static int ledctrl_device_open(const struct hw_module_t *module,
const char *id, struct hw_device_t **device)
{
int fd;
struct ledctrl_device_t *dev; dev = malloc(sizeof(struct ledctrl_device_t));
if (!dev) {
ALOGE("ledctrl: failed to malloc memory");
return -ENOMEM;
}
memset(dev, , sizeof(struct ledctrl_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = ;
dev->common.module = (struct hw_module_t *)module;
dev->common.close = ledctrl_device_close; fd = open(DEVICE_NAME, O_RDWR);
if (fd == -) {
ALOGE("ledctrl: failed to open device file");
free(dev);
return fd;
}
dev->fd = fd;
dev->set_state = ledctrl_set_state;
dev->get_state = ledctrl_get_state; *device = &dev->common; return ;
} /* 模块方法表 */
static struct hw_module_methods_t ledctrl_module_methods = {
.open = ledctrl_device_open,
}; /* 模块实例变量 */
struct ledctrl_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = ,
.version_minor = ,
.id = LEDCTRL_HARDWARE_MODULE_ID,
.name = MODULE_NAME,
.author = MODULE_AUTHOR,
.methods = &ledctrl_module_methods,
},
};

主要是HAL模块的实现方法,sysfs中的brightness文件为leds-gpio设备的属性文件,通过对该属性文件的读写操作,能实现led类设备的点亮与熄灭,另外还需要实现编译的Android.mk文件,代码如下:

# Android.mk for ledctrl hal module

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_SRC_FILES := ledctrl.c
LOCAL_MODULE := ledctrl.default
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

将该ledctrl模块编译为动态库,因此,最后生成的文件应该是ledctrl.default.so。

4、编译测试

对上面编写的HAL模块进行编译测试:

$ cd AOSP
$ mmm hardware/libhardware/modules/ledctrl
$ make snod

将Android系统的system.img镜像重新打包后,使用fastboot命令烧写到system分区,并使用adb登入到终端,查看对应得动态库是否已经存在:

# cd /system/lib/hw
# ls

如下:

5、小结

本篇文章主要对HAL库的编写规则进行了简单的描述,并简单介绍了一个简单的HAL例子实现过程。

Android系统HAL开发实例的更多相关文章

  1. Android系统HAL基本概念

    1.前言 Android系统硬件抽象层(Hardware Abstraction Layer),简写为HAL,是连接Android Framework与Linux内核设备驱动的重要桥梁.HAL存在的意 ...

  2. android 百度地图开发实例(转载)

    因为在我的寝室google基站定位返回的数据总是为空,所以换成百度地图,发现百度地图开发起来非常方便,提供了许多有用的工具,地图的加载速度也比google地图快许多. 为了加强记忆,写一点androi ...

  3. Android Studio 蓝牙开发实例——基于Android 6.0

    因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...

  4. PHP+MYSQL会员系统的开发实例教程

    本文通过一个简单的实例完成了完整的PHP+MySQL会员系统功能.是非常实用的一个应用.具体实现步骤如下: 一.会员系统的原理: 登陆-->判断-->保持状态(Cookie或Session ...

  5. Android之AppWidget 开发浅析

    什么是AppWidget AppWidget 即桌面小部件,也叫桌面控件,就是能直接显示在Android系统桌面上的小程序,先看图: 图中我用黄色箭头指示的即为AppWidget,一些用户使用比较频繁 ...

  6. 深入浅出 - Android系统移植与平台开发(七)- 初识HAL

    作者:唐老师,华清远见嵌入式学院讲师. 1. HAL的module与stub HAL(Hardware AbstractLayer)硬件抽象层是Google开发的Android系统里上层应用对底层硬件 ...

  7. Android系统Google Maps开发实例浅析

    Google Map(谷歌地图)是Google公司提供的电子地图服务.包括了三种视图:矢量地图.卫星图片.地形地图.对于Android系统来说,可以利用Google提供的地图服务来开发自己的一些应用. ...

  8. 判断Android系统net和wap接入点的开发实例

    判断Android系统net和wap接入点的开发实例 分类标签: Activity   我们使用Android设备连接网络时,如果是wap接入点就需要设置代理,而电信和移动联通的代理并不相同,移动和联 ...

  9. 深入浅出 - Android系统移植与平台开发(七)- 初识HAL【转】

    本文转载自:http://blog.csdn.net/mr_raptor/article/details/8069588 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   ...

随机推荐

  1. python 提取整个 HTML 节点

    有的时候,需要把整个 HTML 节点原封不动地取下来,也就是包括节点标签.节点内容,甚至也包括内容中的空格.各种特殊符号等等. 假设已获取到页面源码,并将其保存在变量 src 中.则可有代码如下: f ...

  2. asp.net发布后其他电脑部署——未能加载文件或程序集 System.Web.Mvc, Version=2.0.0.0, Culture=neutral,

    本机测试及发布使用正常 在项目中添加了引用但相关dll文件未在bin文件夹中 导致发布后部署其他电脑未能加载程序集 网上说要下载相关内容在部署服务器安装 但怕在服务器安装出现其他问题 所以在项目中重新 ...

  3. Java学习——反射

    Java学习——反射 摘要:本文主要讲述了什么是反射,使用反射有什么好处,以及如何使用反射. 部分内容来自以下博客: https://www.cnblogs.com/tech-bird/p/35253 ...

  4. 倒计时3天!i春秋四周年盛典狂欢,钜惠不停

    六月注定是不平凡的 感恩父亲节 父爱如山亦如海 难忘毕业季 青春无悔不散场 嗨购618 优惠福利送不停 更值得期待的是 在这个不平凡的六月 迎来了i春秋四周年庆典 当周年庆遇到618 会擦出怎样的火花 ...

  5. IPv6地址类型和操作

    IPv6地址的号段划分和前缀表示法: IPv6拥有128位巨大的地址空间,对于那么大的空间,也不是随意的划分,而是使用按照bit位进行号段划分 地址结构图 全局路由前缀 (48位) 子网ID (16位 ...

  6. linux线程绑定cpu

    函数介绍 #define __USE_GNU #include <sched.h> void CPU_ZERO(cpu_set_t *set); void CPU_SET(int cpu, ...

  7. chattr lsattr文件隐藏属性

    chattr [-RV][-v<版本编号>][+/-/=<属性>][文件或目录...] lsattr [-adlRvV][文件或目录...] 改变/显示文件隐藏属性 chatt ...

  8. elasticsearch 集群、节点、索引、分片、副本概念

    原文链接: https://www.jianshu.com/p/297e13045605 集群(cluster): 由一个或多个节点组成, 并通过集群名称与其他集群进行区分 节点(node): 单个 ...

  9. Git的认识与使用

    Git教程 https://www.liaoxuefeng.com/wiki/896043488029600/897271968352576 Git与SVN区别 Git 不仅仅是个版本控制系统,它也是 ...

  10. if,for,异常,random模块,计算圆周率

    一.分支结构 单分支结构 if 一般用于判断选择 score = 95 if score > 90: print('优秀') 双分支结构 if...else age = 20 if age &g ...