文章目錄

  • 前言
  • HDF 大體的認識
  • HDF 核心模塊 和 關鍵結構體
  • 總結
一、前言

作為鴻蒙驅動開發來説,HDF框架和分佈式軟總線是非常重要的內容,可以這麼説,正是這兩部分內容,讓鴻蒙系統跟android 和 ios 有了很大的不同。

原本的驅動開發,需要為每個設備寫不同驅動,換個硬件還要重寫代碼,很容易出問題。而鴻蒙有了HDF框架,就變的不一樣了。

用一句化來簡單的概括,就是對驅動開發,進行抽象。更高層次的抽象,使得驅動開發,變得更簡單。一次開發,在鴻蒙各種設備上都能使用。

正是因為更高層的抽象,使驅動開發簡單,HDF框架就需要進行系統層抽象,提供標準驅動模型,還有統一平台的操作接口。最終實現一次開發,多端部署。

接下來,我們就一步步分析HDF框架,再到源碼中的關鍵流程。

二、HDF 大體的認識
1、怎麼使用HDF框架
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 驅動為例,這樣能更清楚的看到整個大概流程。

1、配置hcs文件:要定義LED設備,指定驅動源碼的路徑、設置GPIO引腳,設置發佈策略等
2、驅動的實現: 在驅動代碼中實現 Bind、Init、Release 函數,還有LED開關的邏輯
3、應用調用驅動: 應用通過 DevSvcManagerClntGetService("sample_driver") 來獲取驅動服務,
   拿到代表驅動的 HdfDeviceObject 後,通過 service->Dispatch 方法,
   來發送控制命令,來點亮或熄滅 LED。
==================================下面是更深入一點認識==================================
三、核心模塊 和 關鍵結構體
1、HDF 框架的核心模塊
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 設備管理服務

1、核心職責: 驅動生命週期管理
2、管理層次:管理Host 及 它下面的設備和驅動
3、主要工作內容:啓動、停止Host,加載、卸載驅動,電源事件分發
4、管理對象:Host 、Device、DeviceNode
5、數據存儲結構:Hosts 雙向鏈表
6、暴露的接口:StartService, StartDeviceHost 等

DevSvcManager 服務管理器

1、核心職責:驅動服務註冊與發現
2、管理層次:管理已發佈的服務接口
3、主要工作內容: 維護服務註冊表、提供服務的查詢和獲取
4、管理對象:由HdfDeviceObject 代表的驅動服務
5、數據存儲結構:服務名到 HdfDeviceObject    的映射表(服務註冊表)
6、暴露的接口:DevSvcManagerClntGetService

上面兩個是極其容易混淆的,他們之間的關係概括如下:
1、驅動加載與服務註冊:

1、當系統啓動或動態加載驅動時,DevmgrService 負責啓動對應的 Host 進程(也就是 DevHostService),
   並觸發驅動的加載流程
2、驅動在初始化過程中,會通過 DeviceDriverBind 函數將自身的服務接口(具體的實現 IDeviceIoService) 
  綁定到對應的 HdfDeviceObject(驅動實例)的servce 字段上,這樣只要拿到HdfDeviceObject,就能拿到驅動提供的方法了。
3、DeviceDriverBind 執行完之後,也就是驅動初始化之後,會通過 HdfDeviceNodePublishService 
  最終調用 DevSvcManagerAddService 向DevSvcManager註冊驅動的服務。
  此時DevSvcManager 會將驅動服務的名稱和對應的 HdfDeviceObject 
  存入DevSvcManager的服務的註冊表 services 中(也就是 DListHead)。

OpenHarmony 4.0 源碼中實際調用過程如下(從上往下調用,縮進部分是函數內部的操作)

從 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框架如下)
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框架的整體運行流程