OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介 精华

OpenHarmony开发者
发布于 2022-6-7 15:53
浏览
2收藏

HDF 驱动框架是 OpenAtom OpenHarmony(简称“OpenHarmony”)系统硬件生态开放的基础,为驱动开发者提供了驱动加载、驱动服务管理和驱动消息机制等驱动框架能力,同时还为开发者提供了规范的HDI硬件设备接口,让开发者能屏蔽南向设备差异,提供更好的硬件。本文将为大家带来 HDI 硬件设备接口的介绍。

 

OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介-鸿蒙开发者社区


图1 HDF驱动框架

一、HDI介绍
HDI(Hardware Device Interface,硬件设备接口)是 HDF 驱动框架为开发者提供的硬件规范化描述性接口。在 OpenHarmony 分层结构中,HDI 位于 “基础系统服务层”和“设备抽象层(DAL)”之间。硬件设备通过 DAL 抽象化,并基于 IDL(Interface Description Language)接口描述语言描述后,为上层应用或服务提供了规范的硬件设备接口。

 

OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介-鸿蒙开发者社区


图2 OpenHarmony 分层结构

 
HDI 支持“IPC 模式”及“直通模式”两种调用方式。其中,IPC 模式即跨进程通信模式,基于 binder 机制实现,调用端通过 Proxy 代理库调用 HDI 接口,具备良好的解耦性和安全性,是标准系统的默认部署方式。直通模式,将 HDI 实现为共享库,调用端使用 dlopen 加载 HDI 实现库并直接调用 HDI 接口,是小型系统的默认部署方式,同时还适用于对性能有特殊需求的标准系统模块。

 

 

OpenHarmony 3.1 Release版本关键特性解析——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++ 代码,从而为调用者提供一致的接口和调用方式。

 

 

OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介-鸿蒙开发者社区


图4 IDL IPC模式通信模型

 
2.2 基于IDL语言实现HDI接口
首先,使用 IDL 语法描述 HDI 接口并保存为.idl文件,然后编写 .idl 文件的编译脚本 BUILD.gn 文件,最后编译 .idl 文件即可。下面我们将为大家演示电源子系统的 HDI 接口的实现过程。
 
(1)使用IDL语法编写 .idl 文件
● 定义电源接口 IPowerInterface.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;

[callback] 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<IPowerInterface> Get();    
    static sptr<IPowerInterface> GetInstance(const std::string& serviceName);    
    virtual int32_t RegisterCallback(const sptr<IPowerHdiCallback>& 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 接口

#include "v1_0/power_interface_stub.h"

/* 继承PowerInterfaceStub并实现IPowerInterface 中的接口*/
class PowerInterfaceImpl : public PowerInterfaceStub {
public:
    virtual ~PowerInterfaceImpl() {}    
    int32_t RegisterCallback(const sptr<IPowerHdiCallback>& 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 库先处理,然后对接口调用的参数进行反序列化,再转换成对服务实现的函数调用,从而实现接口调用过程。

 

 

OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介-鸿蒙开发者社区


图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 = [
"//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 接口,代码如下:

 #include "v1_0/power_interface.h" //包含Power HDI接口头文件 
 using namespace OHOS::HDI::Power::V1_0; //使用HDI接口命名空间 
 namespace OHOS { 
 namespace PowerMgr { 
 sptr<IPowerInterface> powerInterface = nullptr; 
 SystemSuspendController::SystemSuspendController() 
 { 
     sptr<IPowerHdiCallback> 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​

OpenHarmony 3.1 Release版本关键特性解析——HDI硬件设备接口介-鸿蒙开发者社区


 

 

已于2023-4-21 10:49:39修改
3
收藏 2
回复
举报
回复
    相关推荐