鸿蒙HDF框架源码分析

文章目录

  • 前言
  • HDF 大体的认识
  • HDF 核心模块 和 关键结构体
  • 总结

一、前言

作为鸿蒙驱动开发来说,HDF框架和分布式软总线是非常重要的内容,可以这么说,正是这两部分内容,让鸿蒙系统跟android 和 ios 有了很大的不同。

原本的驱动开发,需要为每个设备写不同驱动,换个硬件还要重写代码,很容易出问题。而鸿蒙有了HDF框架,就变的不一样了。

用一句化来简单的概括,就是对驱动开发,进行抽象。更高层次的抽象,使得驱动开发,变得更简单。一次开发,在鸿蒙各种设备上都能使用。

正是因为更高层的抽象,使驱动开发简单,HDF框架就需要进行系统层抽象,提供标准驱动模型,还有统一平台的操作接口。最终实现一次开发,多端部署。

接下来,我们就一步步分析HDF框架,再到源码中的关键流程。

二、HDF 大体的认识

1、怎么使用HDF框架
cpp 复制代码
1、通过配置hcs文件,适配不同的硬件。
2、HDF框架解析 hcs 配置,获取驱动信息。
3、驱动实现的Bind 函数被调用,进行服务接口的实例化和绑定
4、Init函数执行硬件初始化,最终通过 HdfDeviceNodePublishPublicService 等接口,
   按照配置policy 将服务发布到全局管理器,供其他组件发现和获取。
5、应用 可以通过 DevSvcManagerClntGetService 接口, 传入服务名称,
   获取对应的驱动服务对象,进而操作硬件。
2、HDF 核心设计思想

通过 OSAL 和 Platform 抽象层,屏蔽不同内核和芯片平台的差异。(不同内核,比如: LiteOs 和 Linux 内核。 不同的芯片,比如:海思、高通)

也就是 HDF 充当了翻译的工作, 不同内核层面:比如 驱动需要分配内存内存空间 OsalMemAlloc,HDF框架会进行翻译,在Linux 上运行,就会翻译成 malloc。 在 LiteOs 上就会翻译成LOS_MemAlloc。

不同平台层面: 比如驱动说,我要点灯,HDF会根据hcs 配置文件,知道在芯片A上,点灯的这个动作对应的操作地址 0x1000。而在芯片B上,对应的地址是 0x1010。

hcs配置文件的作用:实现了硬件配置 和 驱动代码的解耦。

3、一个 LED 驱动实现流程

以一个简单的LED 驱动为例,这样能更清楚的看到整个大概流程。

cpp 复制代码
1、配置hcs文件:要定义LED设备,指定驱动源码的路径、设置GPIO引脚,设置发布策略等
2、驱动的实现: 在驱动代码中实现 Bind、Init、Release 函数,还有LED开关的逻辑
3、应用调用驱动: 应用通过 DevSvcManagerClntGetService("sample_driver") 来获取驱动服务,
   拿到代表驱动的 HdfDeviceObject 后,通过 service->Dispatch 方法,
   来发送控制命令,来点亮或熄灭 LED。
cpp 复制代码
================================下面是更深入一点认识================================

三、核心模块 和 关键结构体

1、HDF 框架的核心模块
cpp 复制代码
1、核心管理层:DevmgrService, DevSvcManager 
            (主要目的: 驱动生命周期管理、服务注册与发现)
2、驱动宿主层:DevHostService,HdfDevice, HdfDeviceNode   
            (主要目的:驱动实例的承载,驱动加载 HdfDriverLoader)
3、平台抽象和模型:GPIO/I2C/SPI 等平台接口   
               (主要目的:提供标准驱动模型 和 统一平台操作接口)
4、配置解析:HCS Parser (主要目的:解析hcs文件,生成配置树供驱动读取)

大白话,简化下上面内容:DevmgrService 启动 Host进程,触发驱动加载流程,然后进行绑定,接着调用驱动Init函数,初始化之后通过 HdfDeviceNodePublishPublicService 进行服务的注册。

2、关键结构体 (HDF中涉及的主要结构体 DevmgrService 、DevSvcManager)

DevmgrService 设备管理服务

cpp 复制代码
1、核心职责: 驱动生命周期管理
2、管理层次:管理Host 及 它下面的设备和驱动
3、主要工作内容:启动、停止Host,加载、卸载驱动,电源事件分发
4、管理对象:Host 、Device、DeviceNode
5、数据存储结构:Hosts 双向链表
6、暴露的接口:StartService, StartDeviceHost 等

DevSvcManager 服务管理器

cpp 复制代码
1、核心职责:驱动服务注册与发现
2、管理层次:管理已发布的服务接口
3、主要工作内容: 维护服务注册表、提供服务的查询和获取
4、管理对象:由HdfDeviceObject 代表的驱动服务
5、数据存储结构:服务名到 HdfDeviceObject    的映射表(服务注册表)
6、暴露的接口:DevSvcManagerClntGetService

上面两个是极其容易混淆的,他们之间的关系概括如下:

1、驱动加载与服务注册:

cpp 复制代码
1、当系统启动或动态加载驱动时,DevmgrService 负责启动对应的 Host 进程(也就是 DevHostService),并触发驱动的加载流程
2、驱动在初始化过程中,会通过 DeviceDriverBind 函数将自身的服务接口(具体的实现 IDeviceIoService)
   绑定到对应的 HdfDeviceObject(驱动实例)的servce 字段上,这样只要拿到HdfDeviceObject,就能拿到驱动提供的方法了。
3、DeviceDriverBind 执行完之后,也就是驱动初始化之后,会通过HdfDeviceNodePublishService 
   最终调用 DevSvcManagerAddService 向DevSvcManager注册驱动的服务。
   此时DevSvcManager 会将驱动服务的名称和对应的 HdfDeviceObject 
   存入DevSvcManager的服务的注册表 services 中(也就是 DListHead)。

OpenHarmony 4.0 源码中实际调用过程如下(从上往下调用,缩进部分是函数内部的操作)

cpp 复制代码
从 device_manager.c 的入口 main 开始
main
    DevmgrServiceGetInstance  实际是 DevmgrServiceCreate
    DevmgrServiceConstruct 
    instance->StartService  (StartService 实际是 DevmgrServiceStartService)
DevmgrServiceStartService
DevmgrServiceStartDeviceHosts 启动设备所有主机
DevmgrServiceStartDeviceHost  启动单个设备主机
DevmgrServiceStartHostProcess 
    DriverInstallerGetInstance  实际是 DriverInstallerCreate
    installer->StartDeviceHost  StartDeviceHost 实际是 DriverInstallerStartDeviceHost
DriverInstallerStartDeviceHost  创建并启动主机
    DevHostServiceNewInstance   实际是 DevHostServiceCreate -> DevHostServiceConstruct
    hostServiceIf->StartService 实际是 DevHostServiceStartService
DevHostServiceStartService
DevmgrServiceClntAttachDeviceHost(hostService->hostId, service)  service 实际是 DevHostService
    DevmgrServiceClntGetInstance  调用 DevmgrServiceCreate 调用 DevmgrServiceConstruct 获得 inst
    devMgrSvcIf = inst->devMgrSvcIf;
    devMgrSvcIf->AttachDeviceHost
AttachDeviceHost 实际是 DevmgrServiceAttachDeviceHost
DevHostServiceClntInstallDriver
devHostSvcIf->AddDevice    (DevHostService 继承 IDevHostService 调用 AddDevice, AddDevice 实际是 DevHostServiceAddDevice)
DevHostServiceAddDevice
device->super.Attach(&device->super, devNode)    (Attach 实际是 HdfDeviceAttach)
HdfDeviceAttach
    nodeIf->LaunchNode(devNode)  (LaunchNode 实际是 HdfDeviceLaunchNode)
HdfDeviceLaunchNode
HdfDeviceNodePublishPublicService 发布服务
DevSvcManagerClntAddService
DevSvcManagerAddService
到这里服务已经发布完成

2、服务发现与使用

当应用需要 调用驱动提供的服务时,它会通过 DevSvcManagerClntGetService,向DevSvcManager 查询指定名称的驱动服务。 DevSvcManager 在其服务注册表中,找到 HdfDeviceObject ,这样调用者就能使用驱动提供的服务接口。

大白话:DevmgrSevice 负责把驱动加载和初始化,HdfDeviceObject 主要提供具体的硬件服务,然后DevSvcManager负责给这个驱动宣传,告诉外界这个驱动能提供什么服务,以及如何联系(注册和发现)。

四、总体流程(关键结构体,再加上Hcs文件的解析,于是总的HDF框架如下)

cpp 复制代码
1、HCS Parser 解析配置,生成配置树
2、DevmgrService 会根据配置树,读取驱动列表。通过下发加载指令,调用 DevHostService
3、DevHostService 会通过 HdfDriverLoader 解析、调用 Bind/Init  最终创建生成 HdfDevice(驱动实例)
4、HdfDevice 会初始化硬件/服务接口,通过 HdfDeviceNodePublishPublicService 发布服务,
   最终把服务注册到 DevSvcManager 的注册表中
5、有了驱动的服务,这样应用就能通过 DevSvcManager  的注册表查询,获取驱动,并进行驱动的调用

HDF框架还是有很多内容的,当涉及用户态和内核态,还会牵扯到IPC,但一旦有了上面的蓝图,相信你看源码就有了方向, 也对HDF框架有了大体的认识。

总结

1、介绍HDF框架的好处

2、HDF 框架大体的认识

3、最后通过源码中的关键结构体,还有关键模块,理解HDF框架的整体运行流程

如果对你有一点点帮助,那是值得高兴的事情。:)

我的csdn:blog.csdn.net/shenshizhon...

我的掘金:juejin.cn/user/428855...

相关推荐
凌晨起床2 小时前
Vue3 对比 Vue2
前端·javascript
clausliang3 小时前
实现一个可插入变量的文本框
前端·vue.js
yyongsheng3 小时前
SpringBoot项目集成easy-es框架
java·服务器·前端
fruge3 小时前
前端工程化流程搭建与配置优化指南
前端
东芃93943 小时前
uniapp上传blob对象到后台
前端·javascript·uni-app
coding随想4 小时前
救命!网页还在偷偷耗电?浏览器Battery API事件教你精准控电,这5个场景用了都说香
前端
IT_陈寒4 小时前
Redis性能翻倍的5个冷门优化技巧,90%的开发者都不知道第3个!
前端·人工智能·后端
华仔啊4 小时前
无需UI库!50行CSS打造丝滑弹性动效导航栏,拿来即用
前端·css
光影34155 小时前
专利撰写与申请核心要点简报
前端·数据库·php