OpenHarmony驱动框架HDF中设备管理服务构建过程详解(二)

作者: 侯旗

在上篇文章《 OpenHarmony驱动框架HDF中设备管理服务构建过程详解(一)》中,介绍了设备管理服务涉及的对象类型及其相应的接口,也初步展示了设备管理服务中的对象类型关系网。如下图所示

在本篇文章中,我们开始叙述这张网的构建过程,按照上图中标识的数字,将本篇文章分为4个章节:

  • 1. 创建DevHostServiceClnt
  • 2. 创建DevHostService
  • 3. 创建HdfDevice
  • 4. 创建HdfDeviceNode

在介绍上述对象类型实体的过程中,也会介绍这些对象是如何进行关联的。

1 DevmgrService 构建DevHostServiceClnt

有上图可知,DevMgrService 并不是管理所有的设备,而只是管理host设备,而且 DevMgrService 管理的不是host设备,而是host设备服务的客户端(DevHostServiceClnt),所以DevMgrService管理的是DevHostServiceClnt。

1.1 DevMgrService的启动过程

DevMgrService的启动以DeviceManagerInit()为起点,以late_initcall()为入口点,被静态编译进内核,在内核启动后期启动,其启动过程如下:

late_initcall(DeviceManagerInit);
|-> DeviceManagerInit()
    |-> DeviceManagerStart()
        | // (1)创建DevMgr对象
        |-> instance = DevmgrServiceGetInstance();
        | // (2)发布DevMgr,"/dev/hdf/"+"dev_mgr"
        |-> ioService = HdfIoServicePublish(DEV_MGR_NODE, DEV_MGR_NODE_PERM);
        | // (3)启动DevMgr服务
        |-> instance->StartService(instance);

如上,在函数 DeviceManagerStart() 内,调用HdfIoServicePublish() 将DevMgrService发布为一个设备服务节点“/dev/hdf/dev_mgr”,是为了能像控制器一般设备服务一样控制DevMgrService服务。

在最后,调用 DevMgrService的接口 StartService,即 DevmgrServiceStartService() 启动设备管理服务主体,其实就是为一个个host设备创建 DevHostServiceClnt ,并启动对应的 Host 设备在Host域内的DevHostService。

1.2 DevmgrService 构建host服务客户端

所有Host设备源于hcs设备配置树,DevMgrService 的 StartService 接口实现 DevmgrServiceStartService()调用HcsGetRootNode()依据hcs设备配置树构建其在内存内的树形结构链表g_hcsTreeRoot,然后GetHdfManagerNode()从该链表内获取根节点"hdf_manager"。然后依次创建Host设备服务在Manager域的Client节点——DevHostServiceClnt,并将该client节点添加到DevMgrService的hosts链表上。
具体过程如下:

DeviceManagerInit()
|-> DeviceManagerStart()
    | // IDevmgrService :: StartService();
    |-> DevmgrServiceStartService()
        |   // 获得DriverInstaller单例类对象指针
        |-> installer = DriverInstallerGetInstance();
        |
        |   // (1.1)初始化host设备链表hostList
        |-> HdfAttributeManagerGetHostList(&hostList)
        |   |   // 由hcs设备配置树构建内存内hcs树,并获得根节点"hdf_manager"
        |   |-> hdfManagerNode = GetHdfManagerNode(HcsGetRootNode());
        |   |-> hostNode = hdfManagerNode->child;
        |   |-> while (hostNode != NULL) {
        |   |->     struct HdfHostInfo *hostInfo = HdfHostInfoNewInstance();
        |   |->     GetHostInfo(hostNode, hostInfo);
        |   |->     hostInfo->hostId = hostId;
        |   |->     HdfSListAddOrder(hostList, &hostInfo->node, HdfHostListCompare)
        |   |->     hostId++;
        |   |->     hostNode = hostNode->sibling;
        |   |-> }
        |
        |    (1.2)初始化递归链表it
        |-> HdfSListIteratorInit(&it, &hostList);
        |
        |-> while (HdfSListIteratorHasNext(&it)) {
        |->     hostAttr = (struct HdfHostInfo *)HdfSListIteratorNext(&it);
        |       // (2.1)创建host服务客户端(DevHostServiceClnt)
        |->     hostClnt = DevHostServiceClntNewInstance(hostAttr->hostId, hostAttr->hostName);
        |                  |-> struct DevHostServiceClnt *hostClnt =
        |                           struct DevHostServiceClnt *)OsalMemCalloc(sizeof(struct DevHostServiceClnt));
        |       // (2.2)添加DevHostServiceClnt对象到DevMgrService的hosts链表
        |->     DListInsertTail(&hostClnt->node, &inst->hosts);
        |       // (3)启动Host设备服务(进一步启动host设备下的所有设备:装载各设备驱动、发布设备服务等)
        |->     hostClnt->hostPid = installer->StartDeviceHost(hostAttr->hostId, hostAttr->hostName)
        |-> }

经过如上的DevMgrService的启动流程,则创建DevMgrService的Hosts链表内的Host服务,如下图所示:

2 DriverInstaller 构建Host设备服务DevHostService

在本节中,利用DriverInstaller的StartDeviceHost接口,在启动Host设备服务的过程中创建 DevHostService。为了将Host域中的DevHostService与Manager域中的DevHostServiceClnt 相关联,调用了DevmgrService在Host域client端DevmgrServiceClnt。DevmgrServiceClnt实际上就是DevHostServiceClnt“本尊”。 调用IDevmgrService的AttachDeviceHost接口实现DevmgrServiceAttachDeviceHost(), 将Host域内的DevHostService对象Attach到Manager域的DevHostServiceClnt。

创建DevHostService,并将DevHostService与DevHostServiceClnt关联的过程如下:

// IDriverInstaller:: StartDeviceHost
DriverInstallerStartDeviceHost(uint32_t devHostId, const char *devHostName)
|   // IDevHostService:: StartService
|-> DevHostServiceStartService()
    | 
    |-> DevmgrServiceClntAttachDeviceHost()
        |  // 虽名称为client,实际却是“本尊”
        |-> struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
        |   // IDevmgrService:: AttachDeviceHost
        |-> DevmgrServiceAttachDeviceHost()
        |
        |-> hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
        |-> hostClnt->hostService = hostService;
        |-> hostClnt->deviceInfos = HdfAttributeManagerGetDeviceList(hostClnt->hostId, hostClnt->hostName);
        |-> hostClnt->devCount = HdfSListCount(hostClnt->deviceInfos);
        |  // 名为“InstallDriver”,实际上却是依次启动Host节点下的所有设备服务
        |-> DevHostServiceClntInstallDriver()

DevHostService与DevHostServiceClnt关联关系如下图:

3 DevHostService 构建HdfDevice

3.1 DevMgrService依次启动Host节点下的所有设备

接上文,DriverInstaller在Host域反向调用Manager域中的DevMgrService的AttachDeviceHost接口将HostService与其在Manager域中的Client相关联后,便开始装载host设备的驱动,实际上是装载Host节点下所有设备的设备驱动,并初始化驱动,最后发布设备服务。

// IDriverInstaller:: StartDeviceHost
DevmgrServiceAttachDeviceHost()
|-> DevHostServiceClntInstallDriver()
    |-> devHostSvcIf = (struct IDevHostService *)hostClnt->hostService;
    |
    |-> HdfSListIteratorInit(&it, hostClnt->deviceInfos);
    |-> while (HdfSListIteratorHasNext(&it)) {
    |->     deviceInfo = (struct HdfDeviceInfo *)HdfSListIteratorNext(&it);
    |->     devHostSvcIf->AddDevice(devHostSvcIf, deviceInfo);
    |->  }

3.2 创建HdfDevice对象并将其挂载到DevHostService的devices链表

DevHostService的AddDevice接口负责为Host节下的每个设备创建一个HdfDevice类型对象,并且把新创建的对象挂载到DevHostService的Devices链表中,过程如下:

// IDevHostService:: AddDevice
DevHostServiceAddDevice()
 |-> device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
			  | // 创建HdfDevice对象
			  |-> struct HdfDevice *device = HdfDeviceNewInstance();
			  |-> device->hostId = inst->hostId;
			  |-> device->deviceId = deviceId;
			  | // 将HdfDevice对象挂载到DevHostService的devices链表
			  |-> DListInsertHead(&device->node, &inst->devices);

将HdfDevice挂载到DevHostService的Devices链表,构成如下的DevHostService与HdfDevice的关系图:

为按照文章开始的对象类型关系图叙述对象类型实体的创建过程,上面只描述了HdfDevice的创建过程。实际上,除此之外,DevHostServiceAddDevice()还负责设备驱动的匹配、加载、初始化,以及发布设备服务等,这些在下一章节叙述。

4 DriverLoader 构建设备节点HdfDeviceNode

接上节,继续叙述DevHostServiceAddDevice()其余功能,包含创建HdfDeviceNode、匹配并装载设备驱动、发布服务等。

4.1 DriverLoader 创建设备节点HdfDeviceNode

HdfDeviceNode与设备驱动一一对应,但是一个HdfDeviceNode可能对应着多个设备,对应关系与Hcs设备配置树中的配置有关。在DriverLoader的LoadNode接口的实现函数HdfDriverLoaderLoadNode(),按照设备信息中的moduleName依次匹配系统设备驱动列表中的驱动项,若匹配成功,则将设备驱动的入口地址关联到HdfDeviceNode的driverEntr指针,而且会将设备驱动提供的IoService服务与设备服务相关联(driverEntry->Bind())。

// IDevHostService:: AddDevice();
DevHostServiceAddDevice()
|-> device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
|
| // DriverLoader:: LoadNode
|-> devNode = HdfDriverLoaderLoadNode(struct IDriverLoader *loader, const struct HdfDeviceInfo *deviceInfo)
|			    | // (1)从设备驱动列表内获取与设备moduleName相匹配设备驱动
|			    | // driverEntry = IDriverLoader:: GetDriverEntry();
|			    |-> driverEntry = HdfDriverLoaderGetDriverEntry()
|			    | // (2)创建 HdfDeviceNode 对象
|			    |-> devNode = HdfDeviceNodeNewInstance();
|			    | // (3)关联设备节点与设备驱动等
|			    |-> devNode->driverEntry = driverEntry;
|			    |-> devNode->deviceInfo = deviceInfo;
|			    |-> devNode->deviceObject.property = HcsGetNodeByMatchAttr(HdfGetRootNode(), 
|				|										deviceInfo->deviceMatchAttr);
|			    |-> devNode->deviceObject.priv = (void *)(deviceInfo->private);
|			    | // (4)绑定设备驱动IoService与设备服务
|			    |-> driverEntry->Bind(&devNode->deviceObject);
|
|-> devNode->hostService = hostService;

4.2 DevHostService将HdfDeviceNode挂载到HdfDevice的devNode链表

如下,在完成设备驱动的装载后,便调用DevHostService的Attach接口,将HdfDeviceNode挂载到HdfDevice的devNode链表:

// IDevHostService:: AddDevice();
DevHostServiceAddDevice()
|-> device = DevHostServiceGetDevice(hostService, deviceInfo->deviceId);
|-> devNode = driverLoader->LoadNode(driverLoader, deviceInfo);
|-> devNode->hostService = hostService;
|
| // IHdfDevice:: Attach
|-> HdfDeviceAttach()
	|-> DListInsertTail(&devNode->entry, &device->devNodes);
	|-> nodeIf->LaunchNode(devNode, devInst);

经过上面的过程,HdfDeviceNode和HdfDevice的对象关系图(并考虑到一对多的情况)可表示如下:

4.3 挂载HdfDeviceNode到Host的设备链表

在完成驱动匹配与装载后,其后便是初始化驱动,将设备服务发布到DevSvcManager,然后将HdfDeviceNode节点以Token的形式挂载到DevHostService在Manager域内的Client对象DevHostServiceClnt的devices链表,完成设备在DevMgrService上的注册,具体过程如下:

// IDeviceNode:: LaunchNode
HdfDeviceLaunchNode(struct HdfDeviceNode *devNode, struct IHdfDevice *devInst)
| // (1)初始化设备驱动
|-> driverEntry = HdfDriverLoaderGetDriverEntry()
|-> driverEntry->Init(&devNode->deviceObject);
| // (2)发布设备服务
|-> HdfDeviceNodePublishService()
| // (3)挂载deviceNode到DevHostServiceClnt对象的devices列表上,以token的形式
|-> deviceToken = devNode->token;
|-> DevmgrServiceClntAttachDevice()
    |-> struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
    |-> devMgrSvcIf = inst->devMgrSvcIf;
    | // IDevmgrService:: AttachDevice
    |-> DevmgrServiceAttachDevice()
        |-> hostClnt = DevmgrServiceFindDeviceHost(inst, deviceInfo->hostId);
        |-> HdfSListAdd(&hostClnt->devices, &tokenClnt->node);

至此,完成了整个拼图的最后一块,将HdfDeviceNode以Token的形式挂载到DevHostServiceClnt的Device链表中,如下:

总结

在DevMgrService的构建过程中涉及了众多的对象类型,这些对象类型间的关系有大量借鉴了一些面向对象编程的类、接口、类继承、单例类等的编程思想,本来使用C语言实现面向对象编程的思维就已经使得C编程错综复杂,经常跨层,不太符合Linux内核分层分模块的习惯,增加了代码阅读的难度。而融入的“C/S设计模式”和“观察者设计模式”,无疑又使得阅读HDF的代码难度增加。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值