openharmony5.0中HDF驱动框架源码梳理-服务管理接口
要想大概了解一个公司,我们可能只需要知道它的运行逻辑即可,例如我们只需要知道它有财务有研发有运营等,财务报销、研发负责产品等即可,但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方法)以及各部门都包含哪些关键人员(子对象)以及他们的职责(子对象方法),根据这个逻辑我大概整理了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 框架中实现驱动服务的绑定、获取和订阅功能,帮助开发者更好地理解和使用这些机制。