文章目錄
- 前言
- 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框架的整體運行流程