首页 > 其他分享 >HAL层代码编写注意事项

HAL层代码编写注意事项

时间:2024-11-20 09:40:23浏览次数:1  
标签:HAL hw module hal 注意事项 device 编写 my

基本架构

#include <hardware/hardware.h>
#include <fcntl.h>
#include <cutils/log.h>

//HAL规定不能直接使用hw_module_t结构体
//因此需要在hw_module_t外再套一层结构体,这也是HAL要求的
struct my_module_t
{
    //hw_module_t结构体表示HAL模块的基本信息,成员变量可以任意起,
    //但hw_module_t结构体必须是led_module_t结构体的第一个成员,因为可以直接拿地址进行类型转换
    struct hw_module_t hw_module;
}
//自定义的结构体,该结构体的第1个成员变量的类型必须是hw_ device_t
//在该结构体中还需要定义控制设备的函数指针

struct my_device_t{
    struct hw_device_t hw_device;
    int (*自己的A函数指针成员)(my_device_t dev,int32_t i);

}

//为HAL模块定义一个ID,需要通过这个ID来查找HAL模块
#define XXX_HARDWARE_MODULE_ID "xxx_hal"


int A函数(my_device_t dev,int32_t i){
    //……
}

static int 自己的open函数(const struct hw_module_t* module,const char* name,struct hw_device_t** device){
    struct my_device_t *dev;
    dev=(struct my_control_device_t*)malloc(sizeof(*dev));
    memset(dev,0,sizeof(*dev));
    dev->hw_device.tag=HARDWARE_DEVICE_TAG;
    //
    dev->hw_device.version=0;
    dev->hw_device.module=0;
    dev->hw_device.close=自己的close函数;
    dev->自己的A函数指针成员=A函数;
    *device=(hw_device_t*)dev;
    //一些初始化操作……
    return 0;
}


static struct hw_module_methods_t module_methods={
    .open= 自己的open函数,
}


struct my_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = 1,
    .hal_api_version = HARDWARE_HAL_API_VERSION,
    .id = XXX_HARDWARE_MODULE_ID,
    .name = "Example Hardware Module",
    .author = "Example Author",
    .methods = &module_methods,
};

hw_module_t是最先使用到的,然后通过hw_module_t.methods找到hw_module_methods_t.open函数,并调用该
函数。这个open函数相当于HAL模块的入口。一般会在这个函数里打开设备文件、初始化hw_device_t结构体以及一些控制硬件设备的函数

系统如何找到HAL_MODULE_INFO_SYM?

https://blog.csdn.net/badbayyj/article/details/115826477

Android.mk

编写完成后,还需要个Android.mk文件。
模板如下。

LOCAL PATH :$(call my-dir)
include $(SCLEAR VARS)

LOCAL_PRELINK_MODULE := faise
LOCAL_MODULE_PATH :=$(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES :=XXX_hal.c
LOCAL_MODULE :=XXX_hal.default
LOCAL_MODULE_TAGS :=eng
include $(BUILD_SHARED_LIBRARY)

使用mm编译后,将生成的.default.so文件push到板子的/system/lib/hw文件夹下即可使用,或者将其release到对应文件夹,打包生成image,烧录进去。

HAL Service

单单有.so库是不行的,还需要一个服务端来调用这个.default.so文件。
如果该Service是由JAVA调用的话,这个Service的对外接口要写成JNI函数。在安卓中的audio hal的server是采用一些IPC手段来编写的,并不是直接被JAVA调用。所以以下仅仅是个人笔记,可以不看。后续有机会会补充audio hal的结构。
JNI的模板如下:


#include<对应的hal.h>

//my_device_t结构体会通过open方法返回
struct my_device_t* my_hal_device=NULL;
//JNI函数
static jboolen 函数A(JNIEnv* env,jboject this,jint i)
{
    //如果未成功获取my_device_t,直接返回
    if(my_hal_device==Null)
    {
        return -1;
    }else
    {
        //调用HAL层函数
        return my_hal_device->自己的A函数指针成员(my_hal_device,i);
    }
}

static inline int my_hal_open(const struct hw_module_t* module,
                                struct my_device_t** device)
{
    //调用my_module_t.hw_module.mothods.open函数进行一些初始化工作
    //open函数会获取my_device_t结构体
    return module->methods->open(module,XXX_HARDWARE_MODULE_ID,
                                (struct hw_device_t**)device);
}
//JNI,在该方法中,会通过XXX_HARDWARE_MODULE_ID来找到对应的HAL模块。
//并通过my_hal_open来获取my_device_t结构体
static jboolean my_init(JNIEnv *env,jclass class)
{
    my_module_t* module;
    if(hw_get_module_open(&module->hw_module,&my_hal_device)==0)
    {
        return 0;
    }
}
//定义JNI函数的映射
static const JNINativeMethod methods[]=
{
    {"_init","()Z",(void*)my_init},
    {"_set_on"}//todo
    
}

//将JNI程序库与java类绑定
int register_my_hal_jni(JNIEnv* env)
{
    //必须由该类调用当前的JNI程序库
    static const char* const kClassName="mobile/";//todo
    jclass clazz;
    //获取HalService类的jclass对象
    clazz=env->FindClass(kClassName);
    if(clazz==NULL)
    {
        return -1;
    }
    //调用RegisterNatives方法将函数(到JAVA类中就成为方法了)注册到MyHalService类中
    //其中sizeof(methods)/sizeof(methods[0])是计算methods数组长度
    //RegisterNatives方法的定义:jint RegisterNatives(jclass clazz,const JNINativemethod*)
    //methods,jint nMethods)
    //最后一个参数nMethods表示要映射的函数(方法)数量,也就是methods数组长度
    if(env->RegisterNatives(clazz,methods,sizeof(methods)/sizeof(methods[0]))!=JNI_OK)
    {
        return -1;
    }
    return 0;//成功
}


//系统在成功装载JNI共享库后,会自动调用JNI_OnLoad函数,改函数一般用于初始化JNI模块
jint JNI_OnLoad(JavaVM* vm,void* reserved)
{
    JNIEnv *env=NULL;
    jint reselt=-1;
    //获取JNIEnv结构体的指针,(还可以在这里判断一下J2SE版本)
    //来说明当前模块对J2SE版本的要求。
    if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
    {
        return -1;
    }
    //将java类与JNI函数绑定
    register_my_hal_jni(env);
    //返回JNI_VERSION_1_4,表明只能运行在对应版本以上java
    return JNI_VERSION_1_4;
}

HAL模块的存放路径和命名规则

HAL模块的存放路径和命名规则在Android系统中是经过精心设计的,以确保系统能够正确加载和使用这些模块。

存放路径

HAL模块的库文件(通常是.so文件)存放在以下两个路径之一:

  • /system/lib/hw
  • /vendor/lib/hw

hw_get_module函数会首先在/system/lib/hw目录中查找HAL模块的库文件。如果在该目录中未找到,则会继续在/vendor/lib/hw目录中查找。

命名规则

HAL模块库文件的命名规则是:ID.suffix.so

  • ID:通过hw_get_module函数的id参数指定。例如,led_hal。
  • suffix:后缀,通过属性文件指定。如果没有在属性文件中找到suffix,则使用默认的suffix,即default。
    例如,假设ID是led_hal,那么库文件名可能是:led_hal.default.so(默认情况)、led_hal.abc.so(如果属性文件中定义了abc作为suffix)

属性文件

Android系统的属性文件用于定义各种系统属性和配置。HAL模块的suffix就是通过这些属性文件来确定的。以下是Android系统中用于定义属性的四个主要文件:

  • /default.prop
  • /system/build.prop
  • /system/default.prop
  • /data/local.prop

Android在启动时会自动加载这些属性文件。如果在多个属性文件中定义了相同的Key和Value,那么只会使用第一个被读取的Key。例如:如果在/default.prop文件中定义了ro.product.board的值为abc,而在/system/build.prop文件中定义了ro.product.board的值为xyz,那么hw_get_module函数会将/default.prop文件中的abc作为HAL模块库文件的后缀,而不会再读取/system/build.prop文件中的xyz。因此,HAL模块的库文件名将是led_hal.abc.so。

属性文件的定义

上述四个属性文件的定义可以在以下文件中找到:/working/android2.3.4_src/bionic/libc/include/sys/_system_properties.h
打开_system_properties.h文件后,可以看到定义了四个宏,分别对应上述四个属性文件。

标签:HAL,hw,module,hal,注意事项,device,编写,my
From: https://www.cnblogs.com/chenshao107/p/18461438

相关文章

  • #渗透测试#SRC漏洞挖掘#网络运维# 黑客脚本编写05之字符串运算符与逻辑运算
    免责声明本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章阅读。                            ......
  • 什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?
    友元函数定义友元函数是在类中声明的非成员函数,它可以访问类的私有(private)和保护(protected)成员。友元函数虽然不是类的成员函数,但它被授予了访问类内部成员的特殊权限。声明方式在类的定义中,使用friend关键字来声明友元函数。classMyClass{private:intprivateDat......
  • STM32(hal库)中,为什么DMA没有MSP函数?
            在STM32HAL库中,DMA(直接存储器访问)并没有像其他某些外设(如USART、SPI等)那样拥有专门的MSP(MCUServicesPackage)初始化函数,这主要是由于DMA的特性和HAL库的设计哲学所决定的。        首先,需要明确的是,MSP函数通常是由STM32CubeMX工具为特定的外设生成......
  • 汇编语言-实验10编写子程序
    名称:show_str功能,在指定的位置,用指定的颜色,显示一个用0结束的字符串。参数:(dh)行号。(dl)列号,(cl)颜色ds:si指向字符串首地址返回无应用举例:8行3列,用绿色显示data中的字符串代码如下:assumecs:codedatasegmentdb'Welcometomasm!',0dataendscodesegmentstart:movdh,8......
  • 将 EX4 TO MQ4 的注意事项和方法
    将`.ex4`文件转换为`.mq4`文件本质上涉及反编译`.ex4`文件,这是一个需要注意的重要问题,1**正确的处理方法**  如果您有修改`.ex4`的需要,可以尝试以下方法:  -**联系开发者**:联系原作者,获取`.mq4`源代码或请求他们进行修改。  -**重新开发**:根据需要功......
  • C++中的友元函数和友元类&友元的作用及注意事项
    1.C++中的友元函数和友元类友元函数:友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。类授予它的友元特别的访问权。通常,同一个开发者会出于技术和非技术的原因控制类的友元和成员函数,否则在更新类时,还需要征得其他部分的拥有者的同意。友元函数在定义上和调用......
  • Windows基础及bat蠕虫病毒编写
    常见端口及其服务21ftp23talnet80web80-89都可能443ssl有过心脏滴血漏洞445msb1433mssql1521oracle2082/3主机管理系统登录(国外用的多)2222da虚拟主机管理系统登录(国外较多)3128squid代理默认端口-漫游内网3306mysql3311/2kangle主机管理系统......
  • 【迅为】瑞芯微itop-RK3568开发板Linux+HAL启动测试
    迅为iTOP-RK3568开发板AMP AMPSDK支持Rockchip平台异构多系统AMP(非对称多核架构)的开发软件包,支持Linux(Kernel)、Standalone(Hal)、RTOS(RT-Thread)组合AMP构建形式。可以满足一些特定行业应用,如电力物联网、电网继电保护、电力系统安全控制、工业自动化的需求。     ......
  • 什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?
    友元函数(FriendFunction)定义友元函数是在类定义中用关键字friend声明的非成员函数。它可以访问类的私有(private)和保护(protected)成员。作用和使用场景友元函数主要用于在某些情况下,需要在类的外部函数中访问类的私有或保护成员。例如,在操作符重载中,当需要访问类的私有数......
  • C#编写的日志记录组件 - 开源研究系列文章
          以前编写过一个日志记录组件的博文,这次发布一个修改过的完善版本。 1、项目目录;  2、源码介绍;1)实现;  2)使用;  3、运行界面;  4、使用介绍;参考例子里的代码,或者类库里提供的代码。 ......