HDF 驅動框架是 OpenAtom OpenHarmony(簡稱“OpenHarmony”)系統硬件生態開放的基礎,為驅動開發者提供了驅動加載、驅動服務管理和驅動消息機制等驅動框架能力,同時還為開發者提供了規范的HDI硬件設備接口,讓開發者能屏蔽南向設備差異,提供更好的硬件。本文將為大家帶來 HDI 硬件設備接口的介紹。
一、HDI介紹
HDI(Hardware Device Interface,硬件設備接口)是 HDF 驅動框架為開發者提供的硬件規范化描述性接口。在 OpenHarmony 分層結構中,HDI 位于 “基礎系統服務層”和“設備抽象層(DAL)”之間。硬件設備通過 DAL 抽象化,并基于 IDL(Interface Description Language)接口描述語言描述后,為上層應用或服務提供了規范的硬件設備接口。
圖2 OpenHarmony 分層結構
HDI 支持“IPC 模式”及“直通模式”兩種調用方式。其中,IPC 模式即跨進程通信模式,基于 binder 機制實現,調用端通過 Proxy 代理庫調用 HDI 接口,具備良好的解耦性和安全性,是標準系統的默認部署方式。直通模式,將 HDI 實現為共享庫,調用端使用 dlopen 加載 HDI 實現庫并直接調用 HDI 接口,是小型系統的默認部署方式,同時還適用于對性能有特殊需求的標準系統模塊。
圖3 兩種調用方式
HDI 硬件設備接口的優點用一句話總結就是:為硬件的接入提供了統一的實現通路。屏蔽了硬件接口的具體實現,實現系統軟件與硬件的架構解耦。讓開發者專注于硬件接口的使用,從而簡化開發過程,提升開發效率。
二、HDI實現
通過上文的介紹,相信很多小伙伴會有疑問,HDI 接口是怎么實現的呢?下面我們將為你介紹 IPC 模式下基于 C/S(Client-Server 客戶端與服務端)結構的 HDI 接口實現。
2.1 IDL接口描述語言
為方便后文的理解,我們先簡單了解一下 IDL 接口描述語言。
IDL(Interface Description Language)是一類用來描述接口的語言,通過一種中立的方式來定義客戶端與服務端均認可的編程接口,可以實現在二者間的跨進程通信(IPC)。跨進程通信意味著可以在一個進程訪問另一個進程的數據,或調用另一個進程的方法。通常把應用接口提供方(供調用)稱為服務端,調用方稱為客戶端。
IDL 先把需要傳遞的對象分解成操作系統能夠理解的基本類型,然后根據接口聲明編譯,生成 IPC/RPC代理(Proxy)和樁(Stub)的 C/C++ 代碼,從而為調用者提供一致的接口和調用方式。
圖4 IDL IPC模式通信模型
2.2 基于IDL語言實現HDI接口
首先,使用 IDL 語法描述 HDI 接口并保存為.idl文件,然后編寫 .idl 文件的編譯腳本 BUILD.gn 文件,最后編譯 .idl 文件即可。下面我們將為大家演示電源子系統的 HDI 接口的實現過程。
(1)使用IDL語法編寫 .idl 文件
package ohos.hdi.power.v1_0;
import ohos.hdi.power.v1_0.IPowerHdiCallback;
import ohos.hdi.power.v1_0.PowerTypes;
interface IPowerInterface {
RegisterCallback([in] IPowerHdiCallback ipowerHdiCallback);
StartSuspend();
StopSuspend();
ForceSuspend();
SuspendBlock([in] String name);
SuspendUnblock([in] String name);
PowerDump([out] String info);
}
● 如果需要從服務端回調,可以定義 callback 接口類 IPowerHdiCallback.idl
package ohos.hdi.power.v1_0;
[interface IPowerHdiCallback { ]
OnSuspend();
OnWakeup();
}
● 如果 interface 中用到了自定義數據類型,將自定義類型定義到 powerTypes.idl
package ohos.hdi.power.v1_0;
enum PowerHdfCmd {
CMD_REGISTER_CALLBCK = 0,
CMD_START_SUSPEND,
CMD_STOP_SUSPEND,
CMD_FORCE_SUSPEND,
CMD_SUSPEND_BLOCK,
CMD_SUSPEND_UNBLOCK,
CMD_DUMP,
};
enum PowerHdfCallbackCmd {
CMD_ON_SUSPEND = 0,
CMD_ON_WAKEUP,
};
enum PowerHdfState {
AWAKE = 0,
INACTIVE,
SLEEP,
};
(2)編寫 .idl 文件的編譯腳本 BUILD.gn
import("//drivers/adapter/uhdf2/hdi.gni")
if (defined(ohos_lite)) {
group("libpower_proxy_1.0") {
deps = []
public_configs = []
}
} else {
hdi("power") {
module_name = "power_interface_service"
sources = [
"IPowerHdiCallback.idl",
"IPowerInterface.idl",
"PowerTypes.idl",
]
language = "cpp" subsystem_name = "hdf" part_name = "power_device_driver" }
}
(3)編譯 .idl文件
使用編譯工具 hdi-gen 編譯 IDL 文件,IDL 文件在編譯過程中轉換為 C/C++ 語言的函數接口聲明、客戶端與服務端 IPC 相關過程代碼,開發者只需要基于生成的 power.h 函數接口實現具體服務功能即可。
編譯后生成代碼在 out/product/gen/drivers/interface/power 中,接口代碼如下:
namespace OHOS {
namespace HDI {
namespace Power {
namespace V1_0 {
using namespace OHOS;
enum {
CMD_POWER_INTERFACE_REGISTER_CALLBACK,
CMD_POWER_INTERFACE_START_SUSPEND,
CMD_POWER_INTERFACE_STOP_SUSPEND,
CMD_POWER_INTERFACE_FORCE_SUSPEND,
CMD_POWER_INTERFACE_SUSPEND_BLOCK,
CMD_POWER_INTERFACE_SUSPEND_UNBLOCK,
CMD_POWER_INTERFACE_POWER_DUMP,
CMD_POWER_INTERFACE_GET_VERSION,
};
class IPowerInterface : public IRemoteBroker {
public:
DECLARE_INTERFACE_DESCRIPTOR(u"ohos.hdi.power.v1_0.IPowerInterface");
virtual ~IPowerInterface() = default;
static sptr
Get() ;static sptr
GetInstance(const std::string& serviceName) ;virtual int32_t RegisterCallback(const sptr
& ipowerHdiCallback ) = 0;virtual int32_t StartSuspend() = 0;
virtual int32_t StopSuspend() = 0;
virtual int32_t ForceSuspend() = 0;
virtual int32_t SuspendBlock(const std::string& name) = 0;
virtual int32_t SuspendUnblock(const std::string& name) = 0;
virtual int32_t PowerDump(std::string& info) = 0;
virtual int32_t GetVersion(uint32_t& majorVer, uint32_t& minorVer) = 0;
};
} // V1_0
} // Power
} // HDI
}//OHOS
(4)實現HDI接口
● 實現 UHDF Driver,用于將 HDI 實現加載為獨立進程,并基于 HDF 驅動框架發布設備服務。
static int32_t PowerInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
struct HdfSBuf *reply)
{
......
return hdfPowerInterfaceHost->service->OnRemoteRequest(cmdId, *dataParcel, *replyParcel, option); // 將接口調用轉發到stub實現
}
static int HdfPowerInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
{
......
hdfPowerInterfaceHost->ioservice.Dispatch = PowerInterfaceDriverDispatch;
hdfPowerInterfaceHost->ioservice.Open = NULL;
hdfPowerInterfaceHost->ioservice.Release = NULL;
hdfPowerInterfaceHost->service = new PowerInterfaceImpl();
deviceObject->service = &hdfPowerInterfaceHost->ioservice;
return HDF_SUCCESS;
}
......
struct HdfDriverEntry g_powerinterfaceDriverEntry = {
.moduleVersion = 1,
.moduleName = "power_interface_service",
.Bind = HdfPowerInterfaceDriverBind,
.Init = HdfPowerInterfaceDriverInit,
.Release = HdfPowerInterfaceDriverRelease,
};
● 實現 HDI 接口
/* 繼承PowerInterfaceStub并實現IPowerInterface 中的接口*/
class PowerInterfaceImpl : public PowerInterfaceStub {
public:
virtual ~PowerInterfaceImpl() {}
int32_t RegisterCallback(const sptr
& ipowerHdiCallback) override; int32_t StartSuspend() override;
int32_t StopSuspend() override;
int32_t ForceSuspend() override;
int32_t SuspendBlock(const std::string& name) override;
int32_t SuspendUnblock(const std::string& name) override;
int32_t PowerDump(std::string& info) override;
};
// 在cpp中對相關接口進行實現,其中調用了內核相關接口,實現了具體功能
int32_t PowerInterfaceImpl::StopSuspend()
{
suspendRetry_ = false;
return HDF_SUCCESS;
}
int32_t PowerInterfaceImpl::ForceSuspend()
{
suspendRetry_ = false;
NotifyCallback(CMD_ON_SUSPEND);
DoSuspend();
NotifyCallback(CMD_ON_WAKEUP);
return HDF_SUCCESS;
}
int32_t PowerInterfaceImpl::SuspendBlock(const std::string& name)
{
std::lock_guard<std::mutex> lock(mutex_);
if (name.empty()) {
return HDF_ERR_INVALID_PARAM;
}
UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
bool ret = SaveStringToFd(fd, name);
if (!ret) {
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
三、HDI使用
通過上文的介紹,相信大家已經對 HDI 有了一定的了解,下面我們將為大家介紹 HDI 的使用,在直通模式下,對 HDI 接口調用為同一進程空間函數調用,過程較為直接,這里我們重點闡述 IPC 模式下的調用原理,然后通過 CPP 語言來展示電源子系統 HDI 的調用。
3.1 調用原理
在 IPC 模式下,當系統服務調用 HDI 接口時,通過 proxy 庫將函數調用轉換為 IPC 請求,將接口調用的參數進行序列化;IPC 請求通過 IPC 框架發送到服務端,請求將被 stub 庫先處理,然后對接口調用的參數進行反序列化,再轉換成對服務實現的函數調用,從而實現接口調用過程。
圖5 HDI調用過程
3.2 基于CPP語言的使用
上文已經編譯生成了電源子系統的 HDI 接口,下面我們來看看如何使用 CPP 語言來調用 HDI 接口吧。
(1)客戶端在BUILD.gn中增加依賴://drivers/interface/foo/v1.0:libfoo_proxy_1.0"
ohos_executable("call_foo_hdi") {
sources = [
"src/call_foo_hdi.cpp",
]
deps = [
"http://drivers/interface/foo/v1.0:libfoo_proxy_1.0",
]
external_deps = [
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"utils_base:utils",
]
part_name = "bar"
subsystem_name = "bar_subsystem"
}
(2)在實現電源子系統的代碼中調用 HDI 接口,代碼如下:
using namespace OHOS::V1_0; //使用HDI接口命名空間
namespace OHOS {
namespace PowerMgr {
sptr
powerInterface = nullptr; SystemSuspendController::SystemSuspendController()
{
sptr
g_callback = new PowerHdiCallbackImpl(); powerInterface = IPowerInterface::Get(); //調用接口實例化接口獲取客戶端實例
if (powerInterface == nullptr) {
POWER_HILOGE(COMP_SVC, "The hdf interface is null");
return;
}
powerInterface->RegisterCallback(g_callback); // 調用HDI接口注冊電源事件回調
}
四、結語
以上就是本文全部內容,我們在這里簡單介紹了HDI接口的實現思路及使用,對于廣大南向開發者,我們還在社區提供了詳細的HDI接口實現指導,歡迎大家在gitee社區參與更多討論。
社區鏈接:
https://gitee.com/openharmony/drivers_interface
審核編輯 :李倩
-
接口
+關注
關注
33文章
8526瀏覽量
150862 -
HDI
+關注
關注
6文章
193瀏覽量
21277
原文標題:OpenHarmony 3.1 Release版本關鍵特性解析——HDI硬件設備接口介紹
文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論