openharmony5.0中HDF驱动框架源码梳理-服务管理接口

server/2025/3/16 14:06:02/

要想大概了解一个公司,我们可能只需要知道它的运行逻辑即可,例如我们只需要知道它有财务有研发有运营等,财务报销、研发负责产品等即可,但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方法)以及各部门都包含哪些关键人员(子对象)以及他们的职责(子对象方法),根据这个逻辑我大概整理了openharmony 5.0的HDF框架中包含的关键对象以及对应的方法,便于更深的理解HDF的实现

一、源码目录

仓库路径仓库内容
drivers/hdf_core/frameworkHDF框架、平台驱动框架、驱动模型等平台无关化的公共框架。
- framework/core目录:驱动框架
  - 提供驱动框架能力,主要完成驱动加载和启动功能。
  - 通过对象管理器方式可实现驱动框架的弹性化部署和扩展。
- framework/model目录:驱动模型
  提供了模型化驱动能力,如网络设备模型。
- framework/ability目录:驱动能力库
  提供基础驱动能力模型,如IO通信能力模型。
- framework/tools目录:驱动工具
  提供HDI接口转换、驱动配置编译等工具。
- framework/support目录:Support
  提供规范化的平台驱动接口和系统接口抽象能力。
drivers/hdf_core/adapter包含所有LiteOS-M和LiteOS-A内核以及用户态接口库等相关适配代码以及编译脚本。
drivers/hdf_core/adapter/khdf/linux包含所有Linux内核相关适配代码以及编译脚本。
drivers/peripheralDisplay、Input、Sensor、WLAN、Audio、Camera等外设模块硬件抽象层。
drivers/interfaceDisplay、Input、Sensor、WLAN、Audio、Camera等外设模块HDI接口定义。

在这里插入图片描述

二、硬件驱动框架(HDF)

1. 驱动开发流程

驱动加载
驱动服务管理
驱动消息机制
配置管理
驱动模型
HDF驱动开发流程
按需加载,加载策略由配置文件中的preload字段来控制
preload为0:则系统启动过程中默认加载
preload为01:当系统支持快速启动的时候,则在系统完成之后再加载这一类驱动
preload为2:则系统启动过程中默认不加载,支持后续动态加载
按序加载(默认)
配置文件中的priority(整数0到200)是用来表示host(驱动容器)和驱动的优先级的
host和驱动都是priority值越小,加载优先级越高
驱动需要以接口的形式对外提供能力时使用
包含驱动服务的发布和获取
驱动对外发布服务的策略,由配置文件中的policy字段来控制
0:驱动不提供服务
1:驱动对内核态发布服务
2:驱动对内核态和用户态都发布服务
3:驱动服务不对外发布服务,但可以被订阅
4:驱动私有服务不对外发布服务,也不能被订阅
5:错误的服务策略
当用户态应用和内核态驱动需要交互时使用:
1.用户态应用发送消息到驱动
2.用户态应用接收驱动主动上报事件
HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码。
它实现了配置代码与驱动代码解耦,便于开发者进行配置管理
HDF框架将一类设备驱动放在同一个Host(设备容器)里面,用于管理一组设备的启动加载等过程
划分Host时,驱动程序是部署在一个Host还是部署在不同的Host,主要考虑驱动程序之间是否存在耦合性

下面以驱动开发流程为主线,一步一步分析每个节点的代码实现,以求完全剖析实现逻辑。本篇为驱动服务管理部分
在看本篇前建议先看下openharmony中HDF驱动框架源码梳理-驱动加载流程这篇。

三、驱动服务管理说明

驱动服务是HDF驱动设备对外提供能力的对象,由HDF框架统一管理。驱动服务管理主要包含驱动服务的发布和获取。HDF框架定义了驱动对外发布服务的策略,由配置文件中的policy字段来控制,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框架开放了以下接口供开发者调用,如下表所示:

表1 服务管理接口

方法描述
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)订阅一个设备服务,在服务有更新时能够接收通知

获取驱动服务

通过服务名获取一个服务对象。

//drivers\hdf_core\interfaces\inner_api\host\shared\hdf_device_desc.h
//drivers\hdf_core\framework\core\host\src\devsvc_manager_clnt.c
const struct HdfObject *DevSvcManagerClntGetService(const char *svcName)|-->struct DevSvcManagerClnt *devSvcMgrClnt = DevSvcManagerClntGetInstance();//获取设备服务管理器客户端单实例|-->static struct DevSvcManagerClnt singletonInstance;|-->DevSvcManagerClntConstruct(&singletonInstance);|-->inst->devSvcMgrIf = (struct IDevSvcManager *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVSVC_MANAGER);//构造单实例对象,会调用DevSvcManagerExtCreate进行创建|-->serviceManager = devSvcMgrClnt->devSvcMgrIf;//将设备服务管理器客户端实例中的服务管理器接口赋值给 serviceManager|-->return serviceManager->GetService(serviceManager, svcName);//传入 serviceManager 和 svcName 作为参数,获取对应的服务对象|-->struct HdfObject *DevSvcManagerGetService(struct IDevSvcManager *inst, const char *svcName)//回调函数|-->uint32_t serviceKey = HdfStringMakeHashKey(svcName, 0);//根据服务名 svcName 和初始值 0 生成一个哈希键 serviceKey,用于快速查找服务记录|-->serviceRecord = DevSvcManagerSearchServiceLocked(inst, serviceKey);//在服务管理器中查找指定哈希键 serviceKey 的服务记录,并将结果赋值给 serviceRecord|-->DLIST_FOR_EACH_ENTRY(record, &devSvcManager->services, struct DevSvcRecord, entry) {//遍历服务管理器中的服务记录链表 devSvcManager->services|-->deviceObject = serviceRecord->value;return deviceObject;//返回值

可参考类图如下:
在这里插入图片描述

由上图可知返回值为xxx,那么从哪里设置此值呢?可参考函数int DevSvcManagerAddService(struct IDevSvcManager *inst,struct HdfDeviceObject *service, const struct HdfServiceInfo *servInfo)驱动加载流程中有描述在这里插入图片描述

订阅一个设备服务,在服务有更新时能够接收通知

此函数允许一个观察者订阅一个特定的服务。如果服务已经存在,则直接将订阅者添加到该服务的订阅者列表中;如果服务不存在,则创建一个新的服务记录,并添加订阅者。如果服务已经发布,且订阅者的回调不为空,则立即调用OnServiceConnected回调。

//drivers\hdf_core\interfaces\inner_api\host\shared\hdf_device_desc.h
//drivers\hdf_core\framework\core\host\src\hdf_device_object.c
int32_t HdfDeviceSubscribeService(struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback)|-->uint32_t serviceKey = HdfStringMakeHashKey(svcName, 0)//|-->serviceRecord = (struct HdfServiceObserverRecord *)HdfSListSearch(&observer->services, serviceKey, HdfServiceObserverRecordCompare);//在服务观察者的服务记录列表中查找指定哈希键 serviceKey 的服务记录|-->serviceRecord = HdfServiceObserverRecordObtain(serviceKey);//未找到服务时,创建新的服务记录 serviceRecord|-->subscriber = HdfServiceSubscriberObtain(callback, deviceId);//创建新的订阅者 subscriber|-->struct HdfServiceSubscriber *serviceSubscriber = (struct HdfServiceSubscriber *)OsalMemCalloc(sizeof(struct HdfServiceSubscriber)) //分配内存|-->serviceSubscriber->callback = callback//设置回调函数|-->subscriber->callback.OnServiceConnected(subscriber->callback.deviceObject, serviceRecord->publisher);//如果满足条件,设置订阅者的状态为 HDF_SUBSCRIBER_STATE_READY,并调用回调函数 OnServiceConnected|-->HdfSListAdd(&serviceRecord->subscribers, &subscriber->entry);//将订阅者添加到服务记录的订阅者列表中

可参考类图如下:
在这里插入图片描述

示例demo

以下是一个简单的示例,展示了如何在 OpenHarmony 的 HDF 框架中实现 Bind 函数、获取服务以及订阅服务:

示例代码

#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "hdf_service_observer.h"#define HDF_LOG_TAG sample_driver// 定义驱动服务接口
struct ISampleDriverService {struct IDeviceIoService ioService;int32_t (*ServiceA)(void);int32_t (*ServiceB)(uint32_t inputCode);
};// 实现驱动服务接口
int32_t SampleDriverServiceA(void) {HDF_LOGD("SampleDriverServiceA called");return HDF_SUCCESS;
}int32_t SampleDriverServiceB(uint32_t inputCode) {HDF_LOGD("SampleDriverServiceB called with inputCode: %u", inputCode);return HDF_SUCCESS;
}// 实现 Bind 函数
int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject) {if (deviceObject == NULL) {HDF_LOGE("deviceObject is null");return HDF_FAILURE;}static struct ISampleDriverService sampleDriverService = {.ServiceA = SampleDriverServiceA,.ServiceB = SampleDriverServiceB,};deviceObject->service = &sampleDriverService.ioService;HDF_LOGD("Sample driver bind success");return HDF_SUCCESS;
}// 实现 Init 函数
int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject) {HDF_LOGD("Sample driver init success");return HDF_SUCCESS;
}// 实现 Release 函数
void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject) {HDF_LOGD("Sample driver release success");
}// 定义驱动入口
struct HdfDriverEntry g_sampleDriverEntry = {.moduleVersion = 1,.moduleName = "sample_driver",.Bind = HdfSampleDriverBind,.Init = HdfSampleDriverInit,.Release = HdfSampleDriverRelease,
};// 注册驱动入口
HDF_INIT(g_sampleDriverEntry);// 获取服务示例
const struct HdfObject *GetSampleDriverService(const char *svcName) {return DevSvcManagerClntGetService(svcName);
}// 订阅服务回调函数
int32_t SampleDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service) {const struct ISampleDriverService *sampleService = (const struct ISampleDriverService *)service;if (sampleService != NULL) {sampleService->ServiceA();sampleService->ServiceB(5);}return HDF_SUCCESS;
}// 订阅服务示例
int32_t SubscribeSampleDriverService(struct HdfDeviceObject *deviceObject, const char *serviceName) {struct SubscriberCallback callback = {.deviceObject = deviceObject,.OnServiceConnected = SampleDriverSubCallBack,};return HdfDeviceSubscribeService(deviceObject, serviceName, callback);
}

说明

  1. Bind 函数实现

    • HdfSampleDriverBind 函数中,将驱动的服务接口 sampleDriverService 绑定到 HDF 框架中。
    • deviceObject->service 设置为服务接口的指针。
  2. 获取服务

    • 使用 DevSvcManagerClntGetService 函数通过服务名获取驱动的服务对象。
  3. 订阅服务

    • 定义回调函数 SampleDriverSubCallBack,在服务连接时调用。
    • 使用 HdfDeviceSubscribeService 函数订阅指定的服务,在服务加载完成后,HDF 框架会调用回调函数。

使用方法

  • 在驱动的配置文件中,指定服务的发布策略(如 SERVICE_POLICY_PUBLIC)。
  • 在驱动的初始化函数中,调用 SubscribeSampleDriverService 函数订阅所需的服务。

这个示例展示了如何在 OpenHarmony 的 HDF 框架中实现驱动服务的绑定、获取和订阅功能,帮助开发者更好地理解和使用这些机制。


http://www.ppmy.cn/server/175445.html

相关文章

PHP:从入门到进阶的旅程

在Web开发的广阔世界里,PHP(Hypertext Preprocessor,超文本预处理器)作为一种开源的服务器端脚本语言,自1995年问世以来,便以其灵活性和易用性赢得了广泛的关注和应用。无论是初学者还是经验丰富的开发者&a…

使用Node的http模块创建web服务,给客户端返回html页面时,css失效的根本原因(有助于理解http)

最近正在尝试使用node写后端,使用node创建http服务的时候,碰到了这样的一个问题: 这是我的源代码: import { createServer } from http import { join, dirname, extname } from path import { fileURLToPath } from url import…

java智慧校园综合管理云平台源码,家校互通、物联控制、走班排课

智慧校园云平台电子班牌系统,智慧电子班牌源代码 系统主要以校园安全、智慧校园综合管理云平台为核心,以智慧班牌为学生智慧之窗,以移动管理平台、家校沟通为辅。教师—家长一学校—学生循环的无纸化管理模式及教学服务,实现多领…

【c语言数组精选代码题】

c语言数组精选代码题 四、数组4.1逆序数组4.2最值交换4.3数组排序4.4统计数字频次4.5输出矩阵4.6矩阵运算4.7找字符串索引4.8找字符串索引4.9统计字母频次4.10最长字符串🚀4.10字符串比较4.12字符串的插入🚀4.13字符串的删除🚀🚀 …

单片机ADC+NTC温度采集电路学习

文章目录 前言一、NTC是什么?二、NTC重要参数三、实际应用举例四、NTC和PTC的区别总结 前言 NTC常用来检测外部环境或者电池温度,及汽车水温传感器。 有时候电池并不内置NTC,所以需要外置NTC来采集电池温度,注意要紧贴电池&#…

深度学习 Deep Learning 第2章 线性代数

深度学习 第2章 线性代数 线性代数是深度学习的语言。 张量操作是神经网络计算的基石,矩阵乘法是前向传播的核心,范数约束模型复杂度,而生成空间理论揭示模型表达能力的本质。 本章介绍线性代数的基本内容,为进一步学习深度学习做…

Flink术语

Flink Application: 一个完整的Flink程序代码叫做一个Flink Application,其始于一个或多个Source,终于一个或多个Sink,中间由一个或者多个Operator(算子)组合对数据进行转换形成Transformation。 编写Flink代码要符合一定的流程,首…

Spring Boot实战:MySQL与Redis数据一致性深度解析与代码实战

Spring Boot实战:MySQL与Redis数据一致性深度解析与代码实战 一、数据一致性问题概述二、常见解决方案三、选择合适的解决方案四、总结 在Spring Boot开发中,MySQL作为关系型数据库,提供了强大的数据存储和查询能力;而Redis作为内…