在上篇文章《 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的代码难度增加。
如果大家想更加深入的学习 OpenHarmony(鸿蒙南向) 开发的全栈内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:
OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy
《OpenHarmony源码解析》:https://qr18.cn/CgxrRy
- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ……
系统架构分析:https://qr18.cn/CgxrRy
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……
OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy
OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy
写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:
https://qr21.cn/FV7h05