要想大概了解一个公司,我们可能只需要知道它的运行逻辑即可,例如我们只需要知道它有财务有研发有运营等,财务报销、研发负责产品等即可,但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方法)以及各部门都包含哪些关键人员(子对象)以及他们的职责(子对象方法),根据这个逻辑我大概整理了openharmony 5.0的HDF框架中包含的关键对象以及对应的方法,便于更深的理解HDF的实现。
一、源码目录
仓库路径 | 仓库内容 |
---|---|
drivers/hdf_core/framework | HDF框架、平台驱动框架、驱动模型等平台无关化的公共框架。 - 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/peripheral | Display、Input、Sensor、WLAN、Audio、Camera等外设模块硬件抽象层。 |
drivers/interface | Display、Input、Sensor、WLAN、Audio、Camera等外设模块HDI接口定义。 |
二、硬件驱动框架(HDF)
1. 驱动开发流程
下面以驱动开发流程为主线,一步一步分析每个节点的代码实现,以求完全剖析实现逻辑。本篇为驱动服务管理部分
在看本篇前建议先看下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);
}
说明
-
Bind 函数实现:
- 在
HdfSampleDriverBind
函数中,将驱动的服务接口sampleDriverService
绑定到 HDF 框架中。 - 将
deviceObject->service
设置为服务接口的指针。
- 在
-
获取服务:
- 使用
DevSvcManagerClntGetService
函数通过服务名获取驱动的服务对象。
- 使用
-
订阅服务:
- 定义回调函数
SampleDriverSubCallBack
,在服务连接时调用。 - 使用
HdfDeviceSubscribeService
函数订阅指定的服务,在服务加载完成后,HDF 框架会调用回调函数。
- 定义回调函数
使用方法
- 在驱动的配置文件中,指定服务的发布策略(如
SERVICE_POLICY_PUBLIC
)。 - 在驱动的初始化函数中,调用
SubscribeSampleDriverService
函数订阅所需的服务。
这个示例展示了如何在 OpenHarmony 的 HDF 框架中实现驱动服务的绑定、获取和订阅功能,帮助开发者更好地理解和使用这些机制。