传统 Hal 开发笔记4----实现 Hal 模块

目录

|---------------|
| 实现 Hal 模块 |

一、代码编写

接下来就来为上节实现的驱动写一个简单的 HAL 模块。

在 hardware/libhardware/include/hardware 目录下添加 hello_hal.h:

c 复制代码
#ifndef _HARDWARE_HELLO_HAL_H
#define _HARDWARE_HELLO_HAL_H

#include <hardware/hardware.h>

__BEGIN_DECLS

#define HELLO_HAL_API_VERSION HARDWARE_MODULE_API_VERSION(1,0)

#define HELLO_HAL_HARDWARE_MODULE_ID "hello_hal"

#define HELLO_HAL_DEVICE_ID_MAIN "main_hello_hal"

struct hello_hal_device_t;

typedef struct hello_hal_device_t {
    struct hw_device_t common;

    int fd;  // 存储/dev/hello的文件描

    int (*hello_hal_open)(struct hello_hal_device_t* hello_hal_dev);

    int (*hello_hal_read)(struct hello_hal_device_t* hello_hal_dev, char* str);

    int (*hello_hal_write)(struct hello_hal_device_t* hello_hal_dev,const char* str);
} hello_hal_device_t;

static inline int hello_hal_methods_open(const struct hw_module_t* module, hello_hal_device_t** device)
{
    return module->methods->open(module, HELLO_HAL_DEVICE_ID_MAIN, (struct hw_device_t**)device);
}

__END_DECLS

#endif  // _HARDWARE_HELLO_HAL_H

这里的核心是:

  • 实现一个 hello_hal_device_t 结构体,这个结构体用于操作具体的硬件
  • 实现 hello_hal_methods_open 函数,这个函数用于从 hw_module_t 中找到 hello_hal_device_t 结构体实例
    接着在 hardware/libhardware/modules/ 目录下添加 hello_hal 目录,并在 hello_hal 目录下添加源码文件 hello_hal.c:
c 复制代码
#include <hardware/hello_hal.h>
#include <hardware/hardware.h>

#include <cutils/log.h>

#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>


int hello_open (struct hello_hal_device_t* hello_hal_dev __unused) {
    // 打开/dev/hello,fd存入设备结构体
    hello_hal_dev->fd = open("/dev/hello", O_RDWR);
    if (hello_hal_dev->fd == -1) {
        ALOGE("hello_hal: can not open file /dev/hello, errno=%d", errno); // 用ALOGE打印日志
        return -1;
    }
    return 0;
}


int hello_close (struct hw_device_t* dev) {
    hello_hal_device_t* hello_hal_dev = (hello_hal_device_t*)dev;
    if (hello_hal_dev->fd >= 0) {
        close(hello_hal_dev->fd); // 关闭结构体中的fd
    }
    free(hello_hal_dev); // 释放设备结构体内存
    return 0;
}


int hello_read (struct hello_hal_device_t* hello_hal_dev __unused, char* str) {
    char buf[1024] = {0}; // 初始化缓冲区,避免脏数据
    int len = read(hello_hal_dev->fd, buf, sizeof(buf)-1);
    if (len > 0) {
        buf[len] = '\0';
        strcpy(str, buf);
        return len;
    } else if (len == 0) {
        ALOGW("hello_hal: read 0 bytes from /dev/hello");
        return 0;
    } else {
        ALOGE("hello_hal: read failed, errno=%d", errno);
        return -1;
    }
}

int hello_write (struct hello_hal_device_t* hello_hal_dev __unused, const char* str) {
    if (!str) { // 空指针校验
        ALOGE("hello_hal: write str is NULL");
        return -EINVAL;
    }
    int len = strlen(str) + 1;
    len = len < 1024 ? len : 1024;
    int ret = write(hello_hal_dev->fd, str, len);
    if (ret < 0) {
        ALOGE("hello_hal: write failed, errno=%d", errno);
        return -1;
    }
    return ret;
}

// HAL模块的open函数(创建设备实例)
static int hello_hal_open(const hw_module_t* module, const char* id __unused,
                          hw_device_t** device) {
    // 分配设备结构体内存(calloc自动初始化0)
    hello_hal_device_t *hello_hal_dev = calloc(1, sizeof(hello_hal_device_t));
    if (!hello_hal_dev) {
        ALOGE("hello_hal: Can not allocate memory for hello hal device");
        return -ENOMEM;
    }

    // 初始化hw_device_t(HAL框架要求)
    hello_hal_dev->common.tag = HARDWARE_DEVICE_TAG;
    hello_hal_dev->common.module = (hw_module_t *)module;
    hello_hal_dev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);
    hello_hal_dev->common.close = hello_close; // 现在类型匹配

    // 绑定自定义函数指针
    hello_hal_dev->hello_hal_open = hello_open;
    hello_hal_dev->hello_hal_write = hello_write;
    hello_hal_dev->hello_hal_read = hello_read;

    // 输出设备指针给上层
    *device = (hw_device_t *)hello_hal_dev;

    return 0;
}

// HAL模块方法结构体
static struct hw_module_methods_t hello_hal_module_methods = {
    .open = hello_hal_open,
};

// HAL模块入口(必须命名为HAL_MODULE_INFO_SYM)
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = HELLO_HAL_API_VERSION,
    .hal_api_version = HARDWARE_HAL_API_VERSION,
    .id = HELLO_HAL_HARDWARE_MODULE_ID,
    .name = "Default Hello HAL",
    .author = "sixian",
    .methods = &hello_hal_module_methods,
};
  • 声明一个 hw_module_t 结构体实例
  • 声明一个 hw_module_methods_t 结构体实例,其中 open 函数指针指向hello_hal_open
  • hello_hal_open> 会构建一个 hello_hal_device_t 结构体实例,对其成员赋值,核心的成员主要是 hello_hal_open 、hello_hal_write、 hello_hal_read 三个函数指针

二、编译系统配置

接着在 hardware/libhardware/modules/hello_hal 目录下添加 Android.mk

c 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello_hal.default

# HAL module implementation stored in
# hw/<VIBRATOR_HARDWARE_MODULE_ID>.default.so
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := hello_hal.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

接着在 hardware/libhardware/modules/Android.mk 中添加 hello_hal ,这样编译系统才会去编译 hello_hal 模块。

c 复制代码
hardware_modules := \
    camera \
    gralloc \
    sensors \
    hello_hal
include $(call all-named-subdir-makefiles,$(hardware_modules))

接着在 product 配置文件 device/xxxx/xxxx/device.mk 中添加 hello_hal.default so库:

c 复制代码
PRODUCT_PACKAGES := \
    audio.primary.goldfish \
    vibrator.goldfish \
    hello_hal.default \

至此,hal 层任务完工

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui