配置概述

HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以key-value为主要形式。实现配置代码与驱动代码解耦,便于开发者进行配置管理。HC-GEN(HDF Configuration Generator)是HCS配置转换工具,可以将HDF配置文件转换为软件可读性的文件格式:

  • 在弱性能环境中,转换为配置树宏定义,驱动可调用C代码或宏API获取配置
  • 在高性能环境中,转换为HCB(HDF Configuration Binary)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置

配置使用流程图

HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。

配置语法

HCS 配置语法保留以下关键字

关键字 用途 说明
root 配置根节点 -
include 引用其他HCS配置文件 -
delete 删除节点或属性 只能用于操作include导入的配置树
template 定义模板节点 -
match_attr   用于标记节点的匹配查找属性 解析配置时可以使用该属性的值查找到对应节点

基本结构

HCS 主要分为属性和节点两种结构

属性

属性即最小的配置单位,是一个独立的配置项。

attribute_name = value;
  • attribute_name是字母、数字、下划线的组合必须以字母或下划线开头,字母区分大小写
  • value的可用格式如下
    • 数字常量,支持二进制、八进制、十六进制
    • 字符串,内容使用双引号
    • 节点引用
  • attribute必须以分号结束且属于一个node

节点

节点是一组属性的集合

node_name {
    module = "sample";
    ...
}
  • node_name是字母、数字、下划线的组合
  • 大括号后无需加结束符;
  • root为保留关键字,用于声明配置表的根节点。每个配置必须以root节点开始
  • root节点必须包括module属性,用于表征该配置所属模块
  • 节点中可以增加match_attr属性,其值为全局唯一字符串。当驱动程序在解析配置时可以该属性的值作为参数调用查找接口查找到该节点的属性

数据类型

在属性定义中使用自动数据类型,不显示支持的数据类型如下

  1. 整型:整型长度自动推断,根据实际数据长度给与空间占用类型
  2. 字符串:使用双引号表示
  3. 数组:整型、字符串,不支持混合型。
  4. bool:真假

驱动加载

HDF框架提供把和配置的设备列表匹配成功的驱动程序加载起来的功能,支持按需加载和按序加载两种策略,具体设备的加载策略由配置文件中的preload字段来控制

typedef enum {
    DEVICE_PRELOAD_ENABLE = 0;
    DEVICE_PRELOAD_ENABLE_STEP2 = 1;
    DEVICE_PRELOAD_DISABLE = 2;
    DEVICE_PRELOAD_INVALID
} DevicePreload;

按需加载

  • preload字段配置为0,系统启动过程中默认加载
  • 配置为1,系统快速启动时,则在系统完成之后在加载这一类驱动,否则和0一样
  • 配置为2,系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务 消息机制时,如果驱动服务不存在,HDF框架会尝试加载该驱动

按序加载(默认加载策略)

配置文件中的priority(取值范围0-200)是用来表示host(驱动容器)和驱动的优先级。不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高

异常恢复(用户态驱动)

当驱动服务异常退出时,恢复策略为:

  • preload字段配置0或1 的驱动服务,由启动模块拉起host并重新加载服务
  • preload字段位置为2,需业务模块注册HDF的服务状态监听器,当收到服务退出消息时,业务模块调用LoadDevice重新加载服务。

驱动服务管理

驱动服务是HDF驱动设备对外提供能力的对象,由HDF统一管理。驱动服务主要包含驱动服务的发布与获取。驱动对外发布的策略由配置文件的policy字段控制

typedef enum {
    // 驱动不提供服务
    SERVICE_POLICY_NONE = 0;

    // 驱动对内核发布服务
    SERVICE_POLICY_PUBLIC = 1;
    
    // 驱动对内核态和用户态发布服务
    SERVICE_POLICY_CAPACITY = 2;

    // 驱动服务不对外发布服务,但可以被订阅
    SERVICE_POLICY_FRIENDLY = 3;

    // 驱动私有服务不对外发布服务,也不能被订阅
    SERVICE_POLICY_PRIVATE = 4;

    // 错误的服务策略
    SERVICE_POLICY_INVALID
} ServicePolicy;

使用场景:当驱动需要以接口的形式对外提供能力时,可以使用HDF框架驱动管理服务

接口说明

针对驱动服务管理功能,HDF框架开放以下接口

方法 描述
int32_t (*Bind)(struct HdfDeviceObject *deviceObject) 需要驱动开发者实现Bind函数,将自己的服务接口绑定到HDF框架中。
const struct HdfObject *DevSvcManagerClntGetService(const char *svcName) 获取驱动的服务。

int HdfDeviceSubscribeService( struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback)

订阅驱动服务

驱动消息机制

当用户态应用和内核驱动需求交互,可以使用HDF框架消息实现

消息机制:用户态 <==>内核驱动

方法 描述
struct HdfIoService *HdfIoServiceBind(const char *serviceName); 用户态获取驱动服务,获取之后通过服务的Dispatch方法向驱动发送消息
void HdfIoServiceRecycle(struct HdfIoService *service); 释放驱动服务
int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); 用户态程序注册接收驱动上报事件的操作方法
int32_t HdfDeviceSendEvent(const struct HdfDeviceObject *deviceObject, uint32_t id, const struct HdfSBuf *data) 驱动主动上报事件接口

驱动配置

HDF使用HCS作为配置描述源码,HCS详细介绍配置管理

驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息

    root {
        device_info {
            match_attr = "hdf_manager";
            template host {       // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省。
                hostName = "";
                priority = 100;
                uid = "";         // 用户态进程uid,缺省为空,会被配置为hostName的定义值,即普通用户。
                gid = "";         // 用户态进程gid,缺省为空,会被配置为hostName的定义值,即普通用户组。
                caps = [""];      // 用户态进程Linux capabilities配置,缺省为空,需要业务模块按照业务需要进行配置。
                template device {
                    template deviceNode {
                        policy = 0;
                        priority = 100;
                        preload = 0;
                        permission = 0664;
                        moduleName = "";
                        serviceName = "";
                        deviceMatchAttr = "";
                    }
                }
            }
            sample_host :: host{
                hostName = "host0";    // host名称,host节点是用来存放某一类驱动的容器。
                priority = 100;        // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序。
                caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"];   // 用户态进程Linux capabilities配置。
                device_sample :: device {        // sample设备节点
                    device0 :: deviceNode {      // sample驱动的DeviceNode节点
                        policy = 1;              // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍。
                        priority = 100;          // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序。
                        preload = 0;             // 驱动按需加载字段。
                        permission = 0664;       // 驱动创建设备节点权限
                        moduleName = "sample_driver";      // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。
                        serviceName = "sample_service";    // 驱动对外发布服务的名称,必须唯一。
                        deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。
                    }
                }
            }
        }
    }
  • moduleName:驱动名称
  • serviceName:驱动对外发布服务的名称
  • deviceMatchAttr:驱动私有数据配置关键字,必须和驱动私有数据配置表中的match_attr值一致
  • preload:驱动按需加载字段
  • priority:驱动启动优先级(0-200),值越大优先级越低,默认100,优先级相同不保证device加载顺序
  • policy:驱动发布策略,在驱动服务管理章节

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐