HDI接口概述
回顧之前的文章,HDF 驅(qū)動(dòng)框架的一個(gè)重要功能是為系統(tǒng)提供穩(wěn)定的統(tǒng)一的硬件接口,這樣才能保證系統(tǒng)服務(wù)可以運(yùn)行在不同硬件上而不需要額外的適配工作,HDI(Hardware Device Interfaces)正是為了實(shí)現(xiàn)該目的而設(shè)計(jì)。
HDI 是對硬件功能的較高層次抽象接口,各類外設(shè)完成 HDI 接口定義后便只會在 HDI 的兼容性規(guī)則下進(jìn)行變更,從而保證接口的穩(wěn)定性。具體的驅(qū)動(dòng)實(shí)現(xiàn)不需要再重復(fù)定義 HDI 接口,只需要按需實(shí)現(xiàn)即可接入系統(tǒng)功能。
在不同量級的 OpenHarmony 系統(tǒng)上,HDI 存在兩種部署形態(tài),IPC 模式和直通模式。
在輕量級 OpenHarmony 系統(tǒng)上,出于減小系統(tǒng)性能負(fù)載考慮,HDI 實(shí)現(xiàn)為用戶態(tài)共享庫,由系統(tǒng)服務(wù)直接加載 HDI 實(shí)現(xiàn)到自己進(jìn)程中函數(shù)調(diào)用使用。HDI 實(shí)現(xiàn)封裝具體的用戶態(tài)-內(nèi)核態(tài)交互過程,當(dāng)需要訪問驅(qū)動(dòng)程序時(shí)使用 IO Service 請求將消息通過 system call 方式調(diào)用到內(nèi)核驅(qū)動(dòng)實(shí)現(xiàn)。
在標(biāo)準(zhǔn) OpenHarmony 系統(tǒng)上,HDI 以獨(dú)立服務(wù)進(jìn)程方式部署,系統(tǒng)服務(wù)只加載 HDI 客戶端實(shí)現(xiàn)到自己進(jìn)程中,實(shí)際業(yè)務(wù)運(yùn)行在獨(dú)立進(jìn)程中,客戶端通過 IPC 與服務(wù)端交互,便于架構(gòu)解耦、權(quán)限管理。
HDI接口實(shí)現(xiàn)
直通模式為函數(shù)實(shí)現(xiàn)方式,無論調(diào)用還是實(shí)現(xiàn)都不需要其他組件支持即可實(shí)現(xiàn),這里將重點(diǎn)分析 IPC 模式的實(shí)現(xiàn)。
HDI發(fā)布
HDI IPC 模式基于 OpenHarmony 系統(tǒng)通信框架的通用模型,但是因?yàn)轵?qū)動(dòng)很多時(shí)候涉及到底層操作和多系統(tǒng)遷移的場景而使用C語言編寫,所以驅(qū)動(dòng)框架還提供了 HDI 服務(wù)的 C 語言實(shí)現(xiàn)的基礎(chǔ)組件,C++實(shí)現(xiàn)則主要使用系統(tǒng)通信框架組件。
HDI 服務(wù)發(fā)布基于 UHDF(用戶態(tài) HDF 驅(qū)動(dòng)框架)實(shí)現(xiàn),通用的服務(wù)發(fā)布實(shí)現(xiàn)如下。
1. 實(shí)現(xiàn)驅(qū)動(dòng)入口
int SampleDriverBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGE("SampleDriverBind enter!");
static struct IDeviceIoService testService = {
.Dispatch = SampleServiceDispatch, // 服務(wù)回調(diào)接口
};
deviceObject->service = &testService;
return HDF_SUCCESS;
}
int SampleDriverInit(struct HdfDeviceObject *deviceObject)
{
HDF_LOGE("SampleDriverInit enter");
return HDF_SUCCESS;
}
void SampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGE("SampleDriverRelease enter");
return;
}
struct HdfDriverEntry g_sampleDriverEntry = {
.moduleVersion = 1,
.moduleName = "sample_driver",
.Bind = SampleDriverBind,
.Init = SampleDriverInit,
.Release = SampleDriverRelease,
};
HDF_INIT(g_sampleDriverEntry);
首先要添加一個(gè) UHDF 驅(qū)動(dòng)用于發(fā)布 IoService 服務(wù),IoService 設(shè)備服務(wù)即為 HDI 服務(wù)實(shí)體。實(shí)現(xiàn)方式與 KHDF 驅(qū)動(dòng)一致。
2. 實(shí)現(xiàn)服務(wù)響應(yīng)接口
int32_t SampleServiceOnRemoteRequest(struct HdfDeviceIoClient *client, int cmdId,
struct HdfSBuf *data, struct HdfSBuf *reply)
{
switch (cmdId) {
case SAMPLE_SERVICE_PING:
return SampleServiceStubPing(client, data, reply);
… …
default:
HDF_LOGE("SampleServiceDispatch: not support cmd %d", cmdId);
return HDF_ERR_INVALID_PARAM;
}
}
static int32_t SampleServiceDispatch(struct HdfDeviceIoClient *client, int cmdId,
struct HdfSBuf *data, struct HdfSBuf *reply)
{
return SampleServiceOnRemoteRequest(client, cmdId, data, reply);
}
當(dāng)收到 HDI 調(diào)用時(shí),服務(wù)響應(yīng)接口"SampleServiceDispatch"將會被調(diào)用。
- client 調(diào)用者對象,在用戶態(tài)驅(qū)動(dòng)中暫時(shí)未支持
- cmdId 調(diào)用命令字,用于區(qū)分調(diào)用的 API
- data 調(diào)用入?yún)⑿蛄谢瘜ο螅?IPC 調(diào)用場景為 parcel 對象的 C 語言封裝,入?yún)⑿枰褂眯蛄谢涌趶?data 對象中獲取后再使用
- reply 調(diào)用出參對象,需要返回給調(diào)用的信息寫入該序列化對象
如果 C++實(shí)現(xiàn)客戶端可以使用下面接口將 sbuf 對象轉(zhuǎn)換為 parcel 對象后操作:
int32_t SbufToParcel(struct HdfSBuf *sbuf, OHOS::MessageParcel **parcel);
3. UHDF 驅(qū)動(dòng)配置platform :: host {
hostName = "sample_host";
priority = 50;
sample_device :: device {
device0 :: deviceNode {
policy = 2;
priority = 100;
moduleName = "libsample_driver.z.so";
serviceName = "sample_driver_service";
}
}
}
參數(shù)說明:
- host 一個(gè) host 節(jié)點(diǎn)即為一個(gè)獨(dú)立進(jìn)程,如果需要獨(dú)立進(jìn)程,新增屬于自己的 host 節(jié)點(diǎn)
- policy 服務(wù)發(fā)布策略,HDI 服務(wù)設(shè)置為 2
- moduleName 驅(qū)動(dòng)實(shí)現(xiàn)庫名
- serviceName 服務(wù)名稱,請保持全局唯一性
因?yàn)?HDI 服務(wù) C 和 C++實(shí)現(xiàn)使用的 IPC 組件不一樣,面向?qū)ο髮?shí)現(xiàn)也不一致,所以在具體實(shí)現(xiàn)上存在一些差異。
HDI基礎(chǔ)組件UHDF 框架為了支持 HDI 實(shí)現(xiàn),提供了以下基礎(chǔ)組件(僅用于 C 語言 HDI 實(shí)現(xiàn)):-
SBuf
SBuf 是同時(shí)支持 KHDF 和 UHDF 驅(qū)動(dòng) IoService 消息序列化的工具對象。在 UHDF IPC 通信場景中,SBuf 可以與系統(tǒng) IPC 框架序列化對象 MessageParcel 對象(僅支持 C++)相互轉(zhuǎn)換,從而實(shí)現(xiàn) C 和 C++實(shí)現(xiàn)的 IPC 互通。
常用 API 如下:
struct HdfSBuf;
struct HdfSbufImpl;
struct HdfRemoteService;
/**
* @brief HdfSBuf類型定義。
*
* @since 1.0
*/
enum HdfSbufType {
SBUF_RAW = 0, /* 用于用戶態(tài)內(nèi)核態(tài)通信的sbuf類型 */
SBUF_IPC, /* 用于跨進(jìn)程通信的sbuf類型 */
SBUF_IPC_HW, /* 用于擴(kuò)展的預(yù)留類型 */
SBUF_TYPE_MAX, /* sbuf類型最大值 */
};
上述接口均有對應(yīng)的寫入接口,不再一一列舉,可查閱官網(wǎng)API參考文檔。
-
RemoteService
基于 RemoteService 實(shí)現(xiàn)一個(gè)服務(wù)端的示例:// 消息分發(fā)器,用于服務(wù)端響應(yīng)調(diào)用或者在客戶端發(fā)起調(diào)用
struct HdfRemoteDispatcher {
int (*Dispatch)(struct HdfRemoteService *, int, struct HdfSBuf *, struct HdfSBuf *);
};
// RemoteService 死亡回調(diào)對象
struct HdfDeathRecipient {
void (*OnRemoteDied)(struct HdfDeathRecipient *, struct HdfRemoteService *);
};
struct HdfRemoteService {
struct HdfObject object_;
struct HdfObject *target;
struct HdfRemoteDispatcher *dispatcher;
bool isHw;
};
// 以自定義的消息分發(fā)器實(shí)例化一個(gè)RemoteService
struct HdfRemoteService *HdfRemoteServiceObtain(
struct HdfObject *object, struct HdfRemoteDispatcher *dispatcher);
// 回收RemoteService對象
void HdfRemoteServiceRecycle(struct HdfRemoteService *service);
// 添加RemoteService的死亡通知,如果對應(yīng)RemoteService的進(jìn)程異常退出,HdfDeathRecipient的回調(diào)接口將被調(diào)用
voidHdfRemoteServiceAddDeathRecipient(structHdfRemoteService*service,structHdfDeathRecipient*recipient);
int SampleServiceStubDispatch(
struct HdfRemoteService* service, int code, struct HdfSBuf *data, struct HdfSBuf *reply)
{
// IPC 調(diào)用響應(yīng)接口
int ret = HDF_FAILURE;
switch (code) {
case SAMPLE_IF_0: {
// do something
break;
}
default: {
ret = HDF_ERR_INVALID_PARAM;
}
}
return ret;
}
bool SampleStubConstruct()
{
// 構(gòu)造消息分發(fā)器,實(shí)現(xiàn)消息處理回調(diào)
static struct HdfRemoteDispatcher dispatcher = {
.Dispatch = SampleServiceStubDispatch
};
// 實(shí)例化RemoteService
inst->remote = HdfRemoteServiceObtain((struct HdfObject *)inst, &dispatcher);
if (inst->remote == NULL) {
HDF_LOGE("Device service manager failed to obtain remote service");
return false;
}
……
直接基于 RemoteService 實(shí)現(xiàn)服務(wù)端只適用于需要實(shí)現(xiàn)匿名 IPC 服務(wù)的情況,基于 UHDF 發(fā)布 HDI 服務(wù)只需要實(shí)現(xiàn) Driver 綁定的 IoService 即可。
RemoteService 客戶端對象只能從 SBuf HdfSBufReadRemoteService 接口獲取。
HDI實(shí)現(xiàn)
- Driver 為 HDI 服務(wù)的驅(qū)動(dòng)入口實(shí)現(xiàn)
- IoService 為 HDI 服務(wù)的服務(wù)入口實(shí)現(xiàn),IoService 的 Dispatch 方法中調(diào)用 ServiceStub 中的真正服務(wù)響應(yīng)接口(OnRemoteRequest)
- ServiceStub 為服務(wù)端實(shí)現(xiàn)對象,主要處理與 IPC 相關(guān)的業(yè)務(wù)邏輯,在這里完成參數(shù)反序列化后調(diào)用真正的 Service 實(shí)現(xiàn)接口,即 ServiceImpl 接口
- ServiceImpl 為 HDI 接口的真正實(shí)現(xiàn),這里不關(guān)注 IPC 過程,只實(shí)現(xiàn)函數(shù)接口。
- 驅(qū)動(dòng)框架提供了實(shí)現(xiàn)的樣例代碼,可參考 gitee driver 代碼倉。
HDI接口調(diào)用
HDI驅(qū)動(dòng)框架HDI接口HDI 服務(wù)管理功能由驅(qū)動(dòng)框架 DeviceManager 實(shí)現(xiàn),所以驅(qū)動(dòng)框架提供了 HDI 服務(wù)管理相關(guān) HDI 接口。
C++實(shí)現(xiàn):
namespace OHOS {
namespace HDI {
namespace ServiceManager {
namespace V1_0 {
struct IServiceManager : public IRemoteBroker {
public:
DECLARE_INTERFACE_DESCRIPTOR(u"HDI.IServiceManager.V1_0");
// get()靜態(tài)方法用于獲取IServiceManager對象實(shí)例
static ::sptr
Get(); // GetService()接口是真正提供的HDI接口,用于查詢并獲取其他HDI服務(wù)的客戶端對象
virtual ::sptr
GetService(const char* serviceName) = 0; };
} // namespace V1_0
} // namespace ServiceManager
} // namespace HDI
}//namespaceOHOS
C 實(shí)現(xiàn):
extern "C" {
struct HDIServiceManager {
struct HdfRemoteService *remote;
struct HdfRemoteService *(*GetService)(struct HDIServiceManager *self, const char* serviceName);
};
struct HDIServiceManager *HDIServiceManagerGet(void);
void HDIServiceManagerRelease(struct HDIServiceManager *servmgr);
}
C 語言因?yàn)槿鄙僭拿嫦驅(qū)ο笾С郑@里我們采用 OOC 的實(shí)現(xiàn),函數(shù)方法 HDIServiceManagerGet/Release 用于 HDIServiceManager 對象的實(shí)例化和釋放,HDI 接口關(guān)聯(lián)在接口對象內(nèi)部成員中,與 C++實(shí)現(xiàn)類似。
HDI客戶端實(shí)現(xiàn)
HDI 客戶端同時(shí)支持 C 和 C++實(shí)現(xiàn),實(shí)現(xiàn)方法較為簡單,只需 realize HDI 接口類即可。提供 C++實(shí)現(xiàn)基于系統(tǒng) IPC 子系統(tǒng)的統(tǒng)一模型,C 語言基于 RemoteService 和 SBuf 組件實(shí)現(xiàn),但是有一些公共的約定:
1. 客戶端提供接口對象,接口與對象綁定且必須與 HDI 一致
2. 提供服務(wù)接口對象的實(shí)例化和釋放接口。
3. 客戶端實(shí)現(xiàn) IPC 過程,只為調(diào)用者暴露函數(shù)化接口。
HDI接口調(diào)用
HDI 客戶端接口已經(jīng)提供了服務(wù)獲取接口,調(diào)用者調(diào)用服務(wù)獲取接口后再調(diào)用服務(wù)對象方法即可完成 HDI 調(diào)用。
這里以服務(wù)管理 HDI 接口為例:
C++接口調(diào)用:
void GetTestService()
{
auto servmgr = IServiceManager::Get();
if (servmgr == nullptr) {
HDF_LOGE("failed to get IServiceManager");
return;
}
auto sampleService = servmgr->GetService(TEST_SERVICE_NAME);
if (sampleService == nullptr) {
HDF_LOGE("failed to get TEST_SERVICE");
return;
}
// do something
}
C 接口調(diào)用:
void GetTestService()
{
struct HDIServiceManager *servmgr = HDIServiceManagerGet();
if (servmgr == nullptr) {
HDF_LOGE("failed to get IServiceManager");
return;
}
struct HdfRemoteService *sampleService = servmgr->GetService(servmgr, TEST_SERVICE_NAME);
if (sampleService == nullptr) {
HDF_LOGE("failed to get TEST_SERVICE");
return;
}
// do something
}
總結(jié)
本文介紹了 HDI 的總體方案,重點(diǎn)介紹了 HDI 的 IPC 模式具體實(shí)現(xiàn)方法和驅(qū)動(dòng)框架能力,相信對讀者理解和使用 HDI 有所幫助。
-
HDI
+關(guān)注
關(guān)注
7文章
212瀏覽量
21888 -
C++
+關(guān)注
關(guān)注
22文章
2119瀏覽量
75274 -
代碼
+關(guān)注
關(guān)注
30文章
4900瀏覽量
70705 -
OpenHarmony
+關(guān)注
關(guān)注
29文章
3852瀏覽量
18592
原文標(biāo)題:OpenHarmony HDF HDI基礎(chǔ)能力分析與使用
文章出處:【微信號:HarmonyOS_Community,微信公眾號:電子發(fā)燒友開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
迅為RK3568開發(fā)板實(shí)操-HDF驅(qū)動(dòng)配置UART-修改HCS配置
【北京迅為】iTOP-RK3568開發(fā)板鴻蒙OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)實(shí)操-HDF驅(qū)動(dòng)配置UART

迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-UART應(yīng)用開發(fā)-UART驅(qū)動(dòng)API接口介紹
北京迅為iTOP-RK3568開發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)實(shí)操-HDF驅(qū)動(dòng)配置LED

北京迅為RK3568開發(fā)板OpenHarmony系統(tǒng)南向驅(qū)動(dòng)開發(fā)內(nèi)核HDF驅(qū)動(dòng)框架架構(gòu)

迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-UART應(yīng)用開發(fā)-UART驅(qū)動(dòng)API接口介紹
迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-實(shí)操-HDF驅(qū)動(dòng)配置UART-修改HCS配置
迅為RK3568開發(fā)板篇Openharmony配置HDF控制UART-UART 接口運(yùn)作機(jī)制
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-編寫應(yīng)用APP
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-添加內(nèi)核編譯
迅為RK3568開發(fā)板篇OpenHarmony實(shí)操HDF驅(qū)動(dòng)控制LED-編寫內(nèi)核 LED HDF 驅(qū)動(dòng)程序
迅為RK3568開發(fā)板篇OpenHarmony配置HDF驅(qū)動(dòng)控制LED-新增 topeet子系統(tǒng)
迅為RK3568開發(fā)板篇OpenHarmony配置HDF驅(qū)動(dòng)控制LED-配置創(chuàng)建私有配置文件
HDI盲埋孔工藝及制程能力你了解多少?

評論