openharmony中HDF驱动框架关键流程说明-观察者模式

在分析openharmony 5.0的HDF驱动框架时我们会发现用了很多面向对象的思想,例如类继承、接口、单例类等,本来应该是好事情,但使用时对象之间的关系交错复杂,不太符合linux内核分层分模块的思路,导致整体理解起来比较困难,再加上"C/S设计模式”和“观察者设计模式"更导致系统理解起来比较麻烦,本文便针对观察者模式这个问题做梳理。C/S设计模式和单例类可参考

观察者模式

本文主要分析openharmony的HDF的观察者模式的实现方式以及使用方法,如果对观察者模式没有了解的码友建议先看下这篇文章(提供了一个c语言版本的观察者模式的示例)。在对观察者模式有一个简单的了解后可以根据下图的类图来理解一下

在这里插入图片描述

从openharmony中变量命名的方式中可以看出开发者更倾向于将观察者模式中的两个对象命名为观察者和订阅者(以前都叫观察者和被观察者)。为了更便于理解我在此处写成了被观察者和订阅者

为了加强对整体的理解,我们从核心代码(hdf_core\framework\core\host\src\hdf_service_observer.c)处中可以看出观察者模式的主要实现逻辑。其中主要涉及了以下四个方法:

方法描述
bool HdfServiceObserverConstruct(struct HdfServiceObserver *observer)初始化服务观察者
void HdfServiceObserverDestruct(struct HdfServiceObserver *observer)清空服务列表
int HdfServiceObserverPublishService(struct HdfServiceObserver *observer, const char *svcName, devid_t deviceId,uint16_t policy, struct HdfObject *service)发布驱动服务
int HdfDeviceSubscribeService( struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback)订阅驱动服务

驱动服务是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框架会通过DeviceManagerStart函数最终调用设备host服务创建DevHostServiceCreate函数,进而调用初始化服务观察者函数,如下所示:

struct HdfObject *DevHostServiceCreate(void) #|-->DevHostServiceConstruct(devHostService)|-->HdfServiceObserverConstruct(&service->observer)

清空服务列表

设备host服务释放时会清空服务列表,调用过程如下:

void DevHostServiceRelease(struct HdfObject *object)|-->struct DevHostService *devHostService = (struct DevHostService *)object|-->DevHostServiceDestruct(devHostService)|-->HdfServiceObserverDestruct(&service->observer)

订阅服务

订阅服务,此函数为驱动可以使用的接口函数(hdf_core\interfaces\inner_api\host\shared\hdf_device_desc.h),当驱动需要知到加载时间时可以使用此函数来订阅驱动服务(驱动服务和订阅者必须在同一主机上),在订阅的驱动服务被HDF(硬件驱动框架)加载后,框架会主动向订阅者发布服务接口

int32_t HdfDeviceSubscribeService(struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback)|-->HdfServiceObserverSubscribeService(&hostService->observer, serviceName, devNode->devId, callback)

通过HDF提供的订阅机制获取

当内核态驱动服务获取者对驱动(同一个host)加载的时机不能感知时,可以通过HDF框架提供的订阅机制来订阅该驱动服务。当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者(驱动服务获取者),实现方式如下所示:

// 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用。
// object为订阅者的私有数据,service为被订阅的服务对象。
int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
{const struct ISampleDriverService *sampleService =(const struct ISampleDriverService *)service;if (sampleService == NULL) {return HDF_FAILURE;}sampleService->ServiceA();sampleService->ServiceB(5);
}// 订阅过程的实现
int32_t TestDriverInit(struct HdfDeviceObject *deviceObject)
{if (deviceObject == NULL) {HDF_LOGE("Test driver init failed, deviceObject is null!");return HDF_FAILURE;}struct SubscriberCallback callBack;callBack.deviceObject = deviceObject;callBack.OnServiceConnected = TestDriverSubCallBack;int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack);if (ret != HDF_SUCCESS) {HDF_LOGE("Test driver subscribe sample driver failed!");}return ret;
}

发布服务

在系统启动时HDF框架会通过DeviceManagerStart函数最终调用下图的红色部分,即为发布服务的调用过程:

在这里插入图片描述

示例说明

HDF驱动服务管理策略的应用

假设我们正在开发一个名为“MyDriver”的设备驱动,该驱动提供了一些特定的功能,我们希望这些功能能够以服务的形式对外暴露,以便其他模块或应用能够使用

1. 配置服务策略

在MyDriver的配置文件中,我们需要指定服务的发布策略。例如,如果我们希望MyDriver的服务既对内核态开放,也对用户态开放,我们可以将policy字段设置为SERVICE_POLICY_CAPACITY

配置文件(假设为mydriver.hcs)可能看起来像这样:

root {device_mydriver {device_type = "platform"device_node = "/dev/mydriver"policy = 2  // 指定服务策略为对内核态和用户态都开放service_list = [{service_name = "MyService"service_func = "MyDriverServiceFunc"  // 指向驱动中提供的服务函数}]}
}

在这个配置中,policy字段被设置为2,意味着MyDriver提供的服务MyService将对内核态和用户态的应用都可见。

2. 清空服务列表

在MyDriver的源代码中,我们需要实现MyDriverServiceFunc这个函数,该函数将包含服务要执行的具体操作。例如:

int32_t MyDriverServiceFunc(struct HdfDeviceIoClient *client, struct HdfSBuf *data, struct HdfSBuf *reply)
{// 在这里执行服务的具体操作// ...// 假设操作成功,返回HDF_SUCCESSreturn HDF_SUCCESS;
}
3. 发布服务

在MyDriver的初始化代码中,我们需要调用HDF框架提供的接口来发布这个服务。但是,在HDF框架中,服务的发布通常是由框架本身根据配置文件自动完成的,开发者不需要显式调用发布服务的接口。不过,开发者需要确保他们的驱动正确实现了服务函数,并且配置文件中的信息准确无误。

4. 订阅和使用服务

其他模块或应用可以通过调用HdfDeviceSubscribeService接口来订阅MyDriver提供的服务。一旦订阅成功,它们就可以调用服务函数来执行特定的操作了。

例如,一个用户态的应用可能想要使用MyDriver提供的服务,它可以这样做:

struct HdfDeviceObject *deviceObject; // 假设这个对象已经被正确初始化并指向了MyDriver
const char *serviceName = "MyService";
struct SubscriberCallback callback = {.OnServiceConnected = MyServiceConnectedCallback,  // 当服务连接成功时调用的回调函数.OnServiceDisconnected = MyServiceDisconnectedCallback  // 当服务断开连接时调用的回调函数
};int ret = HdfDeviceSubscribeService(deviceObject, serviceName, callback);
if (ret != HDF_SUCCESS) {// 处理订阅失败的情况
}

在这个例子中,MyServiceConnectedCallbackMyServiceDisconnectedCallback是用户定义的回调函数,它们将在服务连接成功或断开连接时被调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/70196.shtml

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

相关文章

深度学习框架及其常用模型文件保存格式

在深度学习领域,不同的框架有各自常用的模型文件保存格式。了解这些格式对于模型的训练、保存、部署和分享都非常重要。下面将详细介绍几种常见深度学习框架及其对应的模型文件保存格式。 1. PyTorch 框架 1.1 文件格式 .pt .pth 1.2 说明 这两种文件格式本质上…

Java字符串到底能有多长

文章目录 编译期运行期实际开发建议总结编译期 在编写代码时,直接写在代码里的字符串(硬编码字符串)有一个长度限制。具体来说,字符串的最大长度不能超过65534个字符。如果超过这个限制,编译器会报错。 当你在代码里直接写字符串时: String text = "我是一个很长很…

blender骨骼分层问题:某一层的骨骼怎么移动到第一层

一、原生Blender骨骼分层操作方法 1. 进入姿态模式 按A选中骨骼 →按M →鼠标左键点击相应骨骼层 注意:Blender原生界面中,骨骼层是通过姿态模式下的快捷键M勾选框直接控制的,每个勾选框对应一个层(共32层)。移动骨…

一.AI大模型开发-初识机器学习

机器学习基本概念 前言 本文主要介绍了深度学习基础,包括机器学习、深度学习的概念,机器学习的两种典型任务分类任务和回归任务,机器学习中的基础名词解释以及模型训练的基本流程等。 一.认识机器学习 1.人工智能和机器学习 人工智能&am…

cornerstone3D学习笔记-MPR

最近在研究如何利用cornerstone3D (v1.70.13) 来实现MPR功能,找到它的一个demo -- volumeBasic, 运行效果如下图 看了下主程序的示例代码,非常简单,可以说corestone3D这个库把很多细节都封装起来了,使得调用者可以很简单的快速实…

使用 Go-DeepSeek 轻松调用 DeepSeek 模型:从在线 API 到本地部署

引言 DeepSeek 是一个强大的 AI 模型平台,支持多种自然语言处理任务,如对话生成、代码补全和函数调用。为了方便 Go 开发者快速集成 DeepSeek 的功能,我开发了一个非官方的 Go 客户端库:go-deepseek。本文将详细介绍如何使用该库…

VSCode 实用快捷键

前文 VSCode 作为文本编辑神器, 熟练使用其快捷键更是效率翻倍, 本文介绍 VSCode 常用的实用的快捷键 实用快捷键 涉及到文本操作, 搜索定位, 多光标, 面板打开等快捷键 功能快捷键复制光标当前行 (不需要鼠标选中) Ctrl C 剪切光标当前行 (不需要鼠标选中) Ctrl X 当前行下…

28、深度学习-自学之路-NLP自然语言处理-做一个完形填空,让机器学习更多的内容程序展示

import sys,random,math from collections import Counter import numpy as npnp.random.seed(1) random.seed(1) f open(reviews.txt) raw_reviews f.readlines() f.close()tokens list(map(lambda x:(x.split(" ")),raw_reviews))#wordcnt Counter() 这行代码的…

用deepseek学大模型08-卷积神经网络(CNN)

yuanbao.tencent.com 从入门到精通卷积神经网络(CNN),着重介绍的目标函数,损失函数,梯度下降 标量和矩阵形式的数学推导,pytorch真实能跑的代码案例以及模型,数据,预测结果的可视化展示, 模型应用场景和优缺点&#xf…

【Rust中级教程】1.10. 引用及内部可变性(简单回顾):引用、内部可变性、`Cell`类型及相关操作

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 这篇文章只对所有权进行简单回顾,想要看完整的所有权系统阐述见【Rust自学】专栏…

2012年下半年软件设计师上午题知识点及其详细解释(附真题及答案解析)

以下是2012年下半年软件设计师上午题的所有题目(从第1题到第75题)的总结,按顺序列出每道题目的考察知识点及其详细解释,供考生背诵记忆: 1. 控制器 知识点:CPU的组成与功能解释:控制器负责指令…

openGauss 6.0.0 RC1数据库日常运维

引言 随着数字化时代的快速发展,数据库作为企业信息化的核心,其稳定性和性能对于企业至关重要。openGauss 6.0.0 openGauss是一款开源关系型数据库管理系统,采用木兰宽松许可证v2发行。openGauss内核深度融合华为在数据库领域多年的经验&…

4090单卡挑战DeepSeek r1 671b:尝试量化后的心得的分享

引言: 最近,DeepSeek-R1在完全开源的背景下,与OpenAI的O1推理模型展开了激烈竞争,引发了广泛关注。为了让更多本地用户能够运行DeepSeek,我们成功将R1 671B参数模型从720GB压缩至131GB,减少了80%&#xff…

【Scrapy】Scrapy教程6——提取数据

前一小节我们拿到了页面的数据,那页面中那么多内容,我们想要其中的部分内容,该如何获取呢?这就需要对我们下载到的数据进行解析,提取出来想要的数据,这节就讲讲如何提取数据。 引入 我们编辑保存下来的shouye.html文件看下,发现这是什么鬼,全是如下图的代码。 没错…

Python 的 with 语句可以用来管理资源的自动清理,并替代 try...finally 语句,使代码更简洁易读

Python 的 with 语句可以用来管理资源的自动清理,并替代 try...finally 语句,使代码更简洁易读。 1. with 语句的作用 在 Python 里,with 语句通常用于管理资源,比如文件、数据库连接、网络请求等。 它可以保证无论代码是否执行…

栈回溯基础

指令集区分 thumb指令集 长度:thumb指令通常是 16 位。特点:thumb 指令集是为了压缩指令集长度减少程序占用空间。对齐方式:2字节对齐,存放 thumb 指令的地址一般会被1,设置为奇数,用于表示地址上存放的是…

Pytorch论文实现之GAN-C约束鉴别器训练自己的数据集

简介 简介:这次介绍复现的论文主要是约束判别器的函数空间,作者认为原来的损失函数在优化判别器关于真样本和假样本的相对输出缺乏显式约束,因为在实践中,在优化生成器时,鉴别器对生成样本的输出会增加,但对真实数据保持不变,而优化鉴别器会导致其对真实数据的输出增加…

Pyecharts系列课程06——热力图(Heatmap)

1. 基础使用 热力图是一种用于展示数据分布的密度或热度的图表,通过颜色深浅来表示数值大小。 a. 简单示例 我们先来看一个简单示例: 简单示例 from pyecharts.charts import HeatMapx_data = ["分类1", "分类2", "分类3"] y_data

交换路由——控制VLAN之间通信

项目 最近一段时间,A公司发现划分VLAN之后,网速提高很多,发生拥堵的情况消失了.但是,部门之间不能互联,也给办公室带来不便.公司要求项目实施各VLAN内主机互通。 部门 VLAN 名称 端口范围 网络ID 计算机 市场部 VLAN 10 shichang f0/1-f/010 192.168.10.0/24 pc0,pc…

使用 Redis 实现 RBAC 权限管理

1. 什么是 RBAC? RBAC(Role-Based Access Control,基于角色的访问控制)是一种常见的权限管理模型,它通过用户(User)、角色(Role)、权限(Permission&#xff…