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

要想大概了解一个公司,我们可能只需要知道它的运行逻辑即可,例如我们只需要知道它有财务有研发有运营等,财务报销、研发负责产品等即可,但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方法)以及各部门都包含哪些关键人员(子对象)以及他们的职责(子对象方法),根据这个逻辑我大概整理了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.rhkb.cn/news/33874.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言环境搭建并执行第一个Go程序

目录 一、Windows环境搭建 二、vscode安装插件 三、运行第一个go程序 一、Windows环境搭建 下载Go:All releases - The Go Programming Language 这里是Windows搭建,选择的是windows-amd64.msi,也可以选择zip直接解压缩到指定目录 选择msi…

Netty基础—4.NIO的使用简介一

大纲 1.Buffer缓冲区 2.Channel通道 3.BIO编程 4.伪异步IO编程 5.改造程序以支持长连接 6.NIO三大核心组件 7.NIO服务端的创建流程 8.NIO客户端的创建流程 9.NIO优点总结 10.NIO问题总结 1.Buffer缓冲区 (1)Buffer缓冲区的作用 (2)Buffer缓冲区的4个核心概念 (3)使…

linux 命令 tail

tail 是 Linux 中用于查看文件末尾内容的命令&#xff0c;常用于日志监控和大文件快速浏览。以下是其核心用法及常见选项&#xff1a; 基本语法 tail [选项] 文件名 常用选项 显示末尾行数 -n <行数> 或 --lines<行数> 指定显示文件的最后若干行&#xff08;…

网络华为HCIA+HCIP数据链路层协议-以太网协议

以太网协议 以太网是当今现有局域网(Local Area Network,LAN)采用的最通用的通信协议标准&#xff0c;该标准定义了在局域网中采用的电缆类型和信号处理方法。以太网是建立在CSMA/CD(Carrier Sense Multiple Access/Collision Detection,载波监听多路访问/冲突检测)机制上的广…

缓存id路由页面返回,历史路由栈

功能需求 网页端需要做页面数据缓存&#xff08;vue动态路由数据缓存&#xff09;&#xff0c;可根据id值打开多个编辑详情页&#xff0c;需要在页面操作返回时关闭面包屑页签 隐藏问题 1.页面缓存会有初始化和组件激活访问生命周期调用数据接口过多&#xff0c;有性能损耗 2.使…

mingw工具源码编译

ming-w64 mingw编译生成的库&#xff0c;需要mingw的lib文件支持。 https://github.com/mingw-w64/mingw-w64 使用msys2的bash git checkout v8.0.3 ./configure --disable-dependency-tracking --targetx86_64-w64-mingw32 mingw32-make.exe -j4 修改makefile中的make 改成mi…

使用OpenCV和MediaPipe库——抽烟检测(姿态监控)

目录 抽烟检测的运用 1. 安全监控 (1) 公共场所禁烟监管 (2) 工业安全 2. 智能城市与执法 (1) 城市违章吸烟检测 (2) 无人值守管理 3. 健康管理与医疗 (1) 吸烟习惯分析 (2) 远程监护 4. AI 监控与商业分析 (1) 保险行业 (2) 商场营销 5. 技术实现 (1) 计算机视…

大数据学习(66)- CDH管理平台

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

Python字符串高效优化策略:特定编码 -> Unicode码点 -> UTF-8(可自定义)

Python利用唯一uni-pot中介打理&#xff0c;任意制式输出&#xff08;首选uyf-8&#xff09;。 笔记模板由python脚本于2025-03-14 23:37:04创建&#xff0c;本篇笔记适合喜欢探究字符串编码细节的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思…

Linux自动化构建工具—make/makeflie

目录 1、为什么我们需要make和makefile 2、makefile文件的基本语法 makefile文件的语法和make指令的用法 定义变量 3、PHONY关键字 .PHONY 的语法 为什么需要.PHONY&#xff1f; 1、为什么我们需要make和makefile make 和 Makefile 是软件开发中用于自动化构建和管理代…

使用DeepSeek完成一个简单嵌入式开发

开启DeepSeek对话 请帮我使用Altium Designer设计原理图、PCB&#xff0c;使用keil完成代码编写&#xff1b;要求&#xff1a;使用stm32F103RCT6为主控芯片&#xff0c;控制3个流水灯的原理图 这里需要注意&#xff0c;每次DeepSeek的回答都不太一样。 DeepSeek回答 以下是使…

OSPF-2 邻接建立关系

上一期我们说了OSPF的邻居建立关系以及OSPF邻居关系建立中建立失败的因素以及相关实验案例 这一期我们来说说OSPF的邻接关系建立时需要交互哪些报文以及失败因素及原因和相关实验案例 一、概述 在运行了OSPF的网络当中为了交互链路状态信息和路由信息,互相之间需要建立邻接关…

app.config.globalProperties

目录 一:基础使用 1、简介 2、使用 3、打印结果: 二:封装 1、创建一个.ts文件(utils/msg.ts) 2、在main.ts中全局注册 3、在页面中使用 4、打印结果 一:基础使用 1、简介 app.config.globalProperties 是 Vue 3 应用实例&#xff08;app&#xff09;的一个配置属性&…

初探大模型开发:使用 LangChain 和 DeepSeek 构建简单 Demo

最近&#xff0c;我开始接触大模型开发&#xff0c;并尝试使用 LangChain 和 DeepSeek 构建了一个简单的 Demo。通过这个 Demo&#xff0c;我不仅加深了对大模型的理解&#xff0c;还体验到了 LangChain 和 DeepSeek 的强大功能。下面&#xff0c;我将分享我的开发过程以及一些…

基于RWA 与 AI-Agent 协同的企业数字化生态构建

在当前数字经济高速发展的背景下&#xff0c;企业数字化转型已成为提升竞争力和创新能力的必由之路。以实体零售与文旅行业为代表的传统产业&#xff0c;正通过现实世界资产&#xff08;RWA&#xff09;数字化与人工智能代理&#xff08;AI-Agent&#xff09;的协同应用&#x…

专题地图的立体表达-基于QGIS和PPT的“千层饼”视图制作实践

目录 前言 一、QGIS准备基础数据 1、QGIS 相关插件 2、图层标绘操作 二、PPT中制作 1、调整图片的规格 2、设置旋转 3、添加文字 三、总结 前言 在信息爆炸的时代&#xff0c;数据的可视化呈现变得愈发关键&#xff0c;而专题地图作为传递地理空间信息的有力工具&#…

3D文物线上展览如何实现?

3D文物线上展览的实现主要依赖于一系列先进的数字技术和创新手段&#xff0c;以下是实现3D文物线上展览的关键步骤和技术要点&#xff1a; 一、文物数字化采集与建模 高精度扫描&#xff1a; 使用专业的3D扫描仪对文物进行高精度扫描&#xff0c;获取文物的三维数据。积木易…

SpringCloud 学习笔记1(Spring概述、工程搭建、注册中心、负载均衡、 SpringCloud LoadBalancer)

文章目录 SpringCloudSpringCloud 概述集群和分布式集群和分布式的区别和联系 微服务什么是微服务&#xff1f;分布式架构和微服务架构的区别微服务的优缺点&#xff1f;拆分微服务原则 什么是 SpringCloud &#xff1f;核心功能与组件 工程搭建父项目的 pom 文件 注册中心Rest…

1140:验证子串--next.data()、KMP和find

1140&#xff1a;验证子串--KMP 题目 解析next.data()KMP代码Find代码 题目 解析 对于字符串的匹配常见的KMP算法【面试常考】 KMP中需要注意的是&#xff1a;应该从下标1开始遍历&#xff0c;因为下标0前面无值&#xff0c;不能匹配next 固在循环外应初始next[0]0;//易忘点 …

Python 实现大文件的高并发下载

项目背景 基于一个 scrapy-redis 搭建的分布式系统&#xff0c;所有item都通过重写 pipeline 存储到 redis 的 list 中。这里我通过代码演示如何基于线程池 协程实现对 item 的中文件下载。 Item 结构 目的是为了下载 item 中 attachments 保存的附件内容。 {"crawl_tim…