Android系统HAL开发实例
<p>1、前言</p><p> Android系统使用HAL这种设计模式,使得上层服务与底层硬件之间的耦合度降低,在文件:</p>
<div class="cnblogs_code">
<pre>AOSP/hardware/libhardware/include/hardware/hardware.h</pre>
</div>
<p>中描述了HAL的编写规范,并且给出了标准接口,本文将通过一个简单的实例讲解HAL的编写。</p>
<p> </p>
<p>2、HAL编写规范</p>
<p>在之前的文章中讲解了两个很重要的数据结构,struct hw_module_t和struct hw_device_t,在其中hw_module_t代表了整个HAL的实现、功能的封装,也是外部应用程序看到的唯一视角,而hw_device_t代表了一个实际的硬件设备,是设备的属性、设备操作的封装,接下来分析HAL的编写规范。</p>
<p>(1)定义代表module的数据结构</p>
<p>以LED HAL模块为例,首先需要定义一个表示LED模块的数据结构led_moduler_t,并且该数据结构遵循以下准则:</p>
<p>(1.1)该结构体中的第一个成员必须是struct hw_module_t;</p>
<p>(1.2)创建一个该数据结构体的变量,并以HAL_MODULE_INFO_SYM为变量名;</p>
<p>(1.3)结构体hw_module_t中的tag成员固定赋值为HARDWARE_MODULE_TAG;</p>
<p>(1.4)结构体hw_module_t中的module_api_version成员代表了HAL模块的API版本,当模块的接口发生改变时,开发人员必须更新该成员;</p>
<p>(1.5)结构体hw_module_t中的id成员是该模块的标识符,其它程序通过该成员来寻找对应HAL得Stub。</p>
<p>实现如下所示:</p>
<div class="cnblogs_code">
<pre>#include <hardware/hardware.h><span style="color: rgba(0, 0, 0, 1)">
typedef </span><span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> led_module {
</span><span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> hw_module_t common;
...
...
} led_module_t;
</span><span style="color: rgba(0, 0, 255, 1)">struct</span> led_module HAL_MODULE_INFO_SYM =<span style="color: rgba(0, 0, 0, 1)"> {
.common </span>=<span style="color: rgba(0, 0, 0, 1)"> {
.tag </span>=<span style="color: rgba(0, 0, 0, 1)"> HARDWARE_MODULE_TAG,
.module_api_version </span>=<span style="color: rgba(0, 0, 0, 1)"> LED_MODULE_API_VERSION_1_0,
.hal_api_version </span>=<span style="color: rgba(0, 0, 0, 1)"> HARDWARE_HAL_API_VERSION,
.id </span>=<span style="color: rgba(0, 0, 0, 1)"> LED_HARDWARE_MODULE_ID,
.name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Defaule Led HAL</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
.author </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hly</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
.methods </span>= &<span style="color: rgba(0, 0, 0, 1)">led_module_methods,
},
...
...
};</span></pre>
</div>
<p>(2)定义代表device的数据结构</p>
<p>通过module并不能实际操作硬件设备,开发者需要将设备的相关属性以及操作封装在代表device的数据结构,该数据结构通常是一系列的函数指针,定义led_device_t结构体,该数据结构遵循以下规则:</p>
<p>(2.1)第一个成员必须是struct hw_device_t;</p>
<p>(2.2)结构体中的hw_device_t的tag成员必须被赋值为HARDWARE_DEVICE_TAG。</p>
<p>实现如下所示:</p>
<div class="cnblogs_code">
<pre>typedef <span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> led_device {
</span><span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> hw_device_t common;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> (*get_led_state)(<span style="color: rgba(0, 0, 255, 1)">struct</span> led_device *dev, <span style="color: rgba(0, 0, 255, 1)">char</span> **<span style="color: rgba(0, 0, 0, 1)">state);
</span><span style="color: rgba(0, 0, 255, 1)">int</span> (*set_led_state)(<span style="color: rgba(0, 0, 255, 1)">struct</span> led_device *dev, <span style="color: rgba(0, 0, 255, 1)">char</span> *<span style="color: rgba(0, 0, 0, 1)">state);
...
...
} led_device_t;</span></pre>
</div>
<p>(3)实现open函数</p>
<p>当其它的应用程序使用HAL模块的步骤通常是:</p>
<p>首先通过hw_get_module()函数获得指定HAL模块的hw_module_t的引用,然后调用hw_module_t->methods->open函数或得hw_device_t的引用,最后,通过device下的函数指针来操作设备。</p>
<p>open函数指针位于hw_module_methods_t结构体中,该函数的实现方法在不同的HAL模块中实现也较为类似,大体步骤为:</p>
<p>(3.1)为led_device_t结构分配内存空间;</p>
<p>(3.2)对hw_device_t类型的common成员进行赋值;</p>
<p>(3.3)对封装的结构体中的函数指针进行赋值;</p>
<p>(3.4)将分配空间的led_device_t的指针通过hw_device_t **device返回。</p>
<p>实现如下所示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> led_device_open(<span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">struct</span> hw_module_t *<span style="color: rgba(0, 0, 0, 1)">module,
</span><span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">char</span> *id, <span style="color: rgba(0, 0, 255, 1)">struct</span> hw_device_t **<span style="color: rgba(0, 0, 0, 1)">device)
{
</span><span style="color: rgba(0, 0, 255, 1)">struct</span> led_device *<span style="color: rgba(0, 0, 0, 1)">dev;
dev </span>= <span style="color: rgba(0, 0, 255, 1)">malloc</span>(<span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> led_device));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">dev) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Failed to malloc memory</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">ENOMEM;
}
memset(dev, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(0, 0, 255, 1)">sizeof</span><span style="color: rgba(0, 0, 0, 1)">(led_device));
dev</span>->common.tag =<span style="color: rgba(0, 0, 0, 1)"> HARDWARE_DEVICE_TAG;
dev</span>->common.version =<span style="color: rgba(0, 0, 0, 1)"> MODULE_API_VERSION_1_0;
dev</span>->common.module = (<span style="color: rgba(0, 0, 255, 1)">struct</span> hw_module_t *<span style="color: rgba(0, 0, 0, 1)">)module;
dev</span>->get_led_state =<span style="color: rgba(0, 0, 0, 1)"> get_led_state;
dev</span>->set_led_state =<span style="color: rgba(0, 0, 0, 1)"> set_led_state;
...
...
...
</span>*device = (<span style="color: rgba(0, 0, 255, 1)">struct</span> hw_device_t *<span style="color: rgba(0, 0, 0, 1)">)dev;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>(4)实现device的具体操作接口</p>
<p>每个HAL模块的实现都比较类似,对于device下的操作方法,则要按照具体的设备进行实现,每一类设备都是不尽相同的,需要掌握Linux应用层中文件操作、进程管理、信号处理、多线程编程和网络编程等相关技术。</p>
<p> </p>
<p>3、实例讲解</p>
<p> 实现一个ledctrl的HAL模块:</p>
<p>首先在安卓源码下的hardware/libhardware/include/hardware目录下创建ledctrl.h文件,代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#ifndef ANDROID_LEDCTRL_INTERFACE_H
</span><span style="color: rgba(0, 0, 255, 1)">#define</span> ANDROID_LEDCTRL_INTERFACE_H<span style="color: rgba(0, 0, 0, 1)">
#include </span><hardware/hardware.h><span style="color: rgba(0, 0, 0, 1)">
__BEGIN_DECLS
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 定义模块ID </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">#define</span> LEDCTRL_HARDWARE_MODULE_ID "ledctrl"
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 硬件模块结构体 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> ledctrl_module_t {
</span><span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> hw_module_t common;
};
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 硬件接口结构体 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> ledctrl_device_t {
</span><span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> hw_device_t common;
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> fd;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> (*set_state)(<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *dev, <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">char</span> *<span style="color: rgba(0, 0, 0, 1)">state);
</span><span style="color: rgba(0, 0, 255, 1)">int</span> (*get_state)(<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *dev, <span style="color: rgba(0, 0, 255, 1)">char</span> **<span style="color: rgba(0, 0, 0, 1)">state);
};
__END_DECLS
</span><span style="color: rgba(0, 0, 255, 1)">#endif</span></pre>
</div>
<p>然后在安卓源码的hardware/libhardware/modules目录下,新建ledctrl目录,并添加ledctrl.c文件,代码实现如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">#define</span> LOG_TAG "ledctrl_hw_default"<span style="color: rgba(0, 0, 0, 1)">
#include </span><stdlib.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><errno.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><<span style="color: rgba(0, 0, 255, 1)">string</span>.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><<span style="color: rgba(0, 0, 255, 1)">malloc</span>.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><sys/types.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><sys/stat.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><fcntl.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><unistd.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><cutils/log.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><hardware/hardware.h><span style="color: rgba(0, 0, 0, 1)">
#include </span><hardware/ledctrl.h>
<span style="color: rgba(0, 0, 255, 1)">#define</span> DEVICE_NAME "/sys/class/leds/led-red/brightness"
<span style="color: rgba(0, 0, 255, 1)">#define</span> MODULE_NAME "ledctrl"
<span style="color: rgba(0, 0, 255, 1)">#define</span> MODULE_AUTHOR "HLY"
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 设备访问接口 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ledctrl_set_state(<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *dev, <span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">char</span> *<span style="color: rgba(0, 0, 0, 1)">state)
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span> ret = -<span style="color: rgba(0, 0, 0, 1)">EINVAL;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(128, 0, 128, 1)">0</span> == strcmp(state, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">enable</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)) {
ret </span>= write(dev->fd, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret != <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: failed to enable led device</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> exit;
}
ALOGI(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: successed to enable led device</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
ret </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(128, 0, 128, 1)">0</span> == strcmp(state, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">disable</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)) {
ret </span>= write(dev->fd, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">0</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret != <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: failed to close led device</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> exit;
}
ALOGI(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: successed to disable led device</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
ret </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: not define the led device state</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
exit:
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ret;
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ledctrl_get_state(<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *dev, <span style="color: rgba(0, 0, 255, 1)">char</span> **<span style="color: rgba(0, 0, 0, 1)">state)
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> ret,value;
</span><span style="color: rgba(0, 0, 255, 1)">char</span> *buf = <span style="color: rgba(0, 0, 255, 1)">malloc</span>(<span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">char</span>) * <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">);
memset(buf, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">char</span>) * <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">);
ret </span>= read(dev->fd, buf, <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret < <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: failed to read led device</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> exit;
}
value </span>=<span style="color: rgba(0, 0, 0, 1)"> atoi(buf);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (value == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
</span>*state = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">disable</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">else</span>
*state = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">enable</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
ALOGD(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">value = %d, led_state = %s</span><span style="color: rgba(128, 0, 0, 1)">"</span>, value, *<span style="color: rgba(0, 0, 0, 1)">state);
exit:
</span><span style="color: rgba(0, 0, 255, 1)">free</span><span style="color: rgba(0, 0, 0, 1)">(buf);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ret;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 设备的打开和关闭接口 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ledctrl_device_close(<span style="color: rgba(0, 0, 255, 1)">struct</span> hw_device_t *<span style="color: rgba(0, 0, 0, 1)">device)
{
</span><span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *dev = (<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *<span style="color: rgba(0, 0, 0, 1)">)device;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (dev) {
close(dev</span>-><span style="color: rgba(0, 0, 0, 1)">fd);
</span><span style="color: rgba(0, 0, 255, 1)">free</span><span style="color: rgba(0, 0, 0, 1)">(dev);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ledctrl_device_open(<span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">struct</span> hw_module_t *<span style="color: rgba(0, 0, 0, 1)">module,
</span><span style="color: rgba(0, 0, 255, 1)">const</span> <span style="color: rgba(0, 0, 255, 1)">char</span> *id, <span style="color: rgba(0, 0, 255, 1)">struct</span> hw_device_t **<span style="color: rgba(0, 0, 0, 1)">device)
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> fd;
</span><span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_device_t *<span style="color: rgba(0, 0, 0, 1)">dev;
dev </span>= <span style="color: rgba(0, 0, 255, 1)">malloc</span>(<span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> ledctrl_device_t));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">dev) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: failed to malloc memory</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">ENOMEM;
}
memset(dev, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> ledctrl_device_t));
dev</span>->common.tag =<span style="color: rgba(0, 0, 0, 1)"> HARDWARE_DEVICE_TAG;
dev</span>->common.version = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
dev</span>->common.module = (<span style="color: rgba(0, 0, 255, 1)">struct</span> hw_module_t *<span style="color: rgba(0, 0, 0, 1)">)module;
dev</span>->common.close =<span style="color: rgba(0, 0, 0, 1)"> ledctrl_device_close;
fd </span>=<span style="color: rgba(0, 0, 0, 1)"> open(DEVICE_NAME, O_RDWR);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (fd == -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">) {
ALOGE(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ledctrl: failed to open device file</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">free</span><span style="color: rgba(0, 0, 0, 1)">(dev);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> fd;
}
dev</span>->fd =<span style="color: rgba(0, 0, 0, 1)"> fd;
dev</span>->set_state =<span style="color: rgba(0, 0, 0, 1)"> ledctrl_set_state;
dev</span>->get_state =<span style="color: rgba(0, 0, 0, 1)"> ledctrl_get_state;
</span>*device = &dev-><span style="color: rgba(0, 0, 0, 1)">common;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 模块方法表 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">struct</span> hw_module_methods_t ledctrl_module_methods =<span style="color: rgba(0, 0, 0, 1)"> {
.open </span>=<span style="color: rgba(0, 0, 0, 1)"> ledctrl_device_open,
};
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 模块实例变量 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">struct</span> ledctrl_module_t HAL_MODULE_INFO_SYM =<span style="color: rgba(0, 0, 0, 1)"> {
.common </span>=<span style="color: rgba(0, 0, 0, 1)"> {
.tag </span>=<span style="color: rgba(0, 0, 0, 1)"> HARDWARE_MODULE_TAG,
.version_major </span>= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">,
.version_minor </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
.id </span>=<span style="color: rgba(0, 0, 0, 1)"> LEDCTRL_HARDWARE_MODULE_ID,
.name </span>=<span style="color: rgba(0, 0, 0, 1)"> MODULE_NAME,
.author </span>=<span style="color: rgba(0, 0, 0, 1)"> MODULE_AUTHOR,
.methods </span>= &<span style="color: rgba(0, 0, 0, 1)">ledctrl_module_methods,
},
};</span></pre>
</div>
<p>主要是HAL模块的实现方法,sysfs中的brightness文件为leds-gpio设备的属性文件,通过对该属性文件的读写操作,能实现led类设备的点亮与熄灭,另外还需要实现编译的Android.mk文件,代码如下:</p>
<div class="cnblogs_code">
<pre># Android.mk <span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> ledctrl hal module
LOCAL_PATH :</span>= $(call my-<span style="color: rgba(0, 0, 0, 1)">dir)
include $(CLEAR_VARS)
LOCAL_MODULE_PATH :</span>= $(TARGET_OUT_SHARED_LIBRARIES)/<span style="color: rgba(0, 0, 0, 1)">hw
LOCAL_SHARED_LIBRARIES :</span>=<span style="color: rgba(0, 0, 0, 1)"> liblog libcutils
LOCAL_SRC_FILES :</span>=<span style="color: rgba(0, 0, 0, 1)"> ledctrl.c
LOCAL_MODULE :</span>= ledctrl.<span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">
LOCAL_MODULE_TAGS :</span>=<span style="color: rgba(0, 0, 0, 1)"> optional
include $(BUILD_SHARED_LIBRARY)</span></pre>
</div>
<p>将该ledctrl模块编译为动态库,因此,最后生成的文件应该是ledctrl.default.so。</p>
<p> </p>
<p>4、编译测试</p>
<p> 对上面编写的HAL模块进行编译测试:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">$ cd AOSP
$ mmm hardware</span>/libhardware/modules/ledctrl<br>$ make snod</pre>
</div>
<p>将Android系统的system.img镜像重新打包后,使用fastboot命令烧写到system分区,并使用adb登入到终端,查看对应得动态库是否已经存在:</p>
<div class="cnblogs_code">
<pre># cd /system/lib/<span style="color: rgba(0, 0, 0, 1)">hw
# </span><span style="color: rgba(0, 0, 255, 1)">ls</span></pre>
</div>
<p>如下:</p>
<p><img src="https://img2018.cnblogs.com/common/1625033/201911/1625033-20191111220650045-1325888515.png"></p>
<p> </p>
<p>5、小结</p>
<p>本篇文章主要对HAL库的编写规则进行了简单的描述,并简单介绍了一个简单的HAL例子实现过程。</p><br><br>
来源:https://www.cnblogs.com/liangliangge/p/11823592.html
頁:
[1]