0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OpenHarmony HDF HDI的IPC模式具体实现方法和驱动框架能力

电子发烧友开源社区 来源:OpenAtom OpenHarmony 作者:OAOH 2021-09-22 14:55 次阅读

HDI接口概述

回顾之前的文章,HDF 驱动框架的一个重要功能是为系统提供稳定的统一的硬件接口,这样才能保证系统服务可以运行在不同硬件上而不需要额外的适配工作,HDI(Hardware Device Interfaces)正是为了实现该目的而设计。

HDI 是对硬件功能的较高层次抽象接口,各类外设完成 HDI 接口定义后便只会在 HDI 的兼容性规则下进行变更,从而保证接口的稳定性。具体的驱动实现不需要再重复定义 HDI 接口,只需要按需实现即可接入系统功能。

在不同量级的 OpenHarmony 系统上,HDI 存在两种部署形态,IPC 模式和直通模式。

在轻量级 OpenHarmony 系统上,出于减小系统性能负载考虑,HDI 实现为用户态共享库,由系统服务直接加载 HDI 实现到自己进程中函数调用使用。HDI 实现封装具体的用户态-内核态交互过程,当需要访问驱动程序时使用 IO Service 请求将消息通过 system call 方式调用到内核驱动实现。

在标准 OpenHarmony 系统上,HDI 以独立服务进程方式部署,系统服务只加载 HDI 客户端实现到自己进程中,实际业务运行在独立进程中,客户端通过 IPC 与服务端交互,便于架构解耦、权限管理。

HDI接口实现

直通模式为函数实现方式,无论调用还是实现都不需要其他组件支持即可实现,这里将重点分析 IPC 模式的实现。

HDI发布

HDI IPC 模式基于 OpenHarmony 系统通信框架的通用模型,但是因为驱动很多时候涉及到底层操作和多系统迁移的场景而使用C语言编写,所以驱动框架还提供了 HDI 服务的 C 语言实现的基础组件,C++实现则主要使用系统通信框架组件。

HDI 服务发布基于 UHDF(用户态 HDF 驱动框架)实现,通用的服务发布实现如下。

1. 实现驱动入口

int SampleDriverBind(struct HdfDeviceObject *deviceObject){    HDF_LOGE("SampleDriverBind enter!");    static struct IDeviceIoService testService = {        .Dispatch = SampleServiceDispatch, // 服务回调接口    };    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);

首先要添加一个 UHDF 驱动用于发布 IoService 服务,IoService 设备服务即为 HDI 服务实体。实现方式与 KHDF 驱动一致。

2. 实现服务响应接口

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);}

当收到 HDI 调用时,服务响应接口"SampleServiceDispatch"将会被调用。

  • client 调用者对象,在用户态驱动中暂时未支持
  • cmdId 调用命令字,用于区分调用的 API
  • data 调用入参序列化对象,在 IPC 调用场景为 parcel 对象的 C 语言封装,入参需要使用序列化接口从 data 对象中获取后再使用
  • reply 调用出参对象,需要返回给调用的信息写入该序列化对象

如果 C++实现客户端可以使用下面接口将 sbuf 对象转换为 parcel 对象后操作:

int32_t SbufToParcel(struct HdfSBuf *sbuf, OHOS::MessageParcel **parcel);
3. UHDF 驱动配置
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";        }    }}

参数说明:

  • host 一个 host 节点即为一个独立进程,如果需要独立进程,新增属于自己的 host 节点
  • policy 服务发布策略,HDI 服务设置为 2
  • moduleName 驱动实现库名
  • serviceName 服务名称,请保持全局唯一性

因为 HDI 服务 C 和 C++实现使用的 IPC 组件不一样,面向对象实现也不一致,所以在具体实现上存在一些差异。

HDI基础组件UHDF 框架为了支持 HDI 实现,提供了以下基础组件(仅用于 C 语言 HDI 实现):
  • SBuf

SBuf 是同时支持 KHDF 和 UHDF 驱动 IoService 消息序列化的工具对象。在 UHDF IPC 通信场景中,SBuf 可以与系统 IPC 框架序列化对象 MessageParcel 对象(仅支持 C++)相互转换,从而实现 C 和 C++实现的 IPC 互通。

常用 API 如下:

struct HdfSBuf;struct HdfSbufImpl;struct HdfRemoteService;
/** * @brief HdfSBuf类型定义。 * * @since 1.0 */enum HdfSbufType {    SBUF_RAW = 0,   /* 用于用户态内核态通信的sbuf类型 */    SBUF_IPC,       /* 用于跨进程通信的sbuf类型 */    SBUF_IPC_HW,    /* 用于扩展的预留类型 */    SBUF_TYPE_MAX,  /* sbuf类型最大值 */};

bede5c9e-0b50-11ec-8fb8-12bb97331649.png

上述接口均有对应的写入接口,不再一一列举,可查阅官网API参考文档。

  • RemoteService

RemoteService 对象和系统 IPC 框架中的 IRemoteObject 对象(仅支持 C++)对应并可以相互转换,表示一个 IPC 对象。相关 API 说明:
// 消息分发器,用于服务端响应调用或者在客户端发起调用struct HdfRemoteDispatcher {    int (*Dispatch)(struct HdfRemoteService *, int, struct HdfSBuf *, struct HdfSBuf *);};
// RemoteService 死亡回调对象struct HdfDeathRecipient {    void (*OnRemoteDied)(struct HdfDeathRecipient *, struct HdfRemoteService *);};
struct HdfRemoteService {    struct HdfObject object_;    struct HdfObject *target;    struct HdfRemoteDispatcher *dispatcher;    bool isHw;};// 以自定义的消息分发器实例化一个RemoteServicestruct HdfRemoteService *HdfRemoteServiceObtain(    struct HdfObject *object, struct HdfRemoteDispatcher *dispatcher);
// 回收RemoteService对象void HdfRemoteServiceRecycle(struct HdfRemoteService *service);
// 添加RemoteService的死亡通知,如果对应RemoteService的进程异常退出,HdfDeathRecipient的回调接口将被调用voidHdfRemoteServiceAddDeathRecipient(structHdfRemoteService*service,structHdfDeathRecipient*recipient);
基于 RemoteService 实现一个服务端的示例:
int SampleServiceStubDispatch(    struct HdfRemoteService* service, int code, struct HdfSBuf *data, struct HdfSBuf *reply){    // IPC 调用响应接口    int ret = HDF_FAILURE;    switch (code) {        case SAMPLE_IF_0: {            // do something            break;        }        default: {            ret = HDF_ERR_INVALID_PARAM;        }    }    return ret;}bool SampleStubConstruct(){    // 构造消息分发器,实现消息处理回调    static struct HdfRemoteDispatcher dispatcher = {        .Dispatch = SampleServiceStubDispatch};// 实例化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 实现服务端只适用于需要实现匿名 IPC 服务的情况,基于 UHDF 发布 HDI 服务只需要实现 Driver 绑定的 IoService 即可。

RemoteService 客户端对象只能从 SBuf HdfSBufReadRemoteService 接口获取。

HDI实现

  • Driver 为 HDI 服务的驱动入口实现
  • IoService 为 HDI 服务的服务入口实现,IoService 的 Dispatch 方法中调用 ServiceStub 中的真正服务响应接口(OnRemoteRequest)
  • ServiceStub 为服务端实现对象,主要处理与 IPC 相关的业务逻辑,在这里完成参数反序列化后调用真正的 Service 实现接口,即 ServiceImpl 接口
  • ServiceImpl 为 HDI 接口的真正实现,这里不关注 IPC 过程,只实现函数接口。
  • 驱动框架提供了实现的样例代码,可参考 gitee driver 代码仓。

HDI接口调用

HDI驱动框架HDI接口

HDI 服务管理功能由驱动框架 DeviceManager 实现,所以驱动框架提供了 HDI 服务管理相关 HDI 接口。

C++实现:

namespace OHOS {namespace HDI {namespace ServiceManager {namespace V1_0 {
struct IServiceManager : public IRemoteBroker {public:    DECLARE_INTERFACE_DESCRIPTOR(u"HDI.IServiceManager.V1_0");    // get()静态方法用于获取IServiceManager对象实例    static ::sptr Get();    // GetService()接口是真正提供的HDI接口,用于查询并获取其他HDI服务的客户端对象    virtual ::sptr GetService(const char* serviceName) = 0;};} // namespace V1_0} // namespace ServiceManager} // namespace HDI}//namespaceOHOS

C 实现:

#ifdef __cplusplusextern "C" {#endif /* __cplusplus */
struct HDIServiceManager {    struct HdfRemoteService *remote;
    struct HdfRemoteService *(*GetService)(struct HDIServiceManager *self, const char* serviceName);};
struct HDIServiceManager *HDIServiceManagerGet(void);void HDIServiceManagerRelease(struct HDIServiceManager *servmgr);
#ifdef __cplusplus}#endif/*__cplusplus*/

C 语言因为缺少原生的面向对象支持,这里我们采用 OOC 的实现,函数方法 HDIServiceManagerGet/Release 用于 HDIServiceManager 对象的实例化和释放,HDI 接口关联在接口对象内部成员中,与 C++实现类似。

HDI客户端实现

HDI 客户端同时支持 C 和 C++实现,实现方法较为简单,只需 realize HDI 接口类即可。提供 C++实现基于系统 IPC 子系统的统一模型,C 语言基于 RemoteService 和 SBuf 组件实现,但是有一些公共的约定:

1. 客户端提供接口对象,接口与对象绑定且必须与 HDI 一致

2. 提供服务接口对象的实例化和释放接口。

3. 客户端实现 IPC 过程,只为调用者暴露函数化接口。

HDI接口调用

HDI 客户端接口已经提供了服务获取接口,调用者调用服务获取接口后再调用服务对象方法即可完成 HDI 调用。

这里以服务管理 HDI 接口为例:

C++接口调用:

#include 
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 接口调用:

#include 
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}

总结

本文介绍了 HDI 的总体方案,重点介绍了 HDI 的 IPC 模式具体实现方法和驱动框架能力,相信对读者理解和使用 HDI 有所帮助。

编辑:jq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • HDI
    HDI
    +关注

    关注

    6

    文章

    179

    浏览量

    21086
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72899
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66736
  • OpenHarmony
    +关注

    关注

    23

    文章

    3262

    浏览量

    15159

原文标题:OpenHarmony HDF HDI基础能力分析与使用

文章出处:【微信号:HarmonyOS_Community,微信公众号:电子发烧友开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    OpenHarmony开源GPU库Mesa3D适配说明

    ,对下使用Gallium框架,屏蔽驱动差异。在RK3568中,panfrost对ARM GPU提供了非常好的开源驱动支持。 二、适配方法 在RK3568 GPU 开源库mesa3D适配
    发表于 12-25 11:38

    OpenHarmony之NAPI框架介绍

    。 可以看到,NAPI 接口本身是 C++语言实现的,这些接口可以帮助 C++代码创建 JS 变量,或访问 JavaScript 运行环境中的 JS 变量与方法OpenHarmony
    发表于 11-23 15:36

    OpenHarmony 4.0 Release版本发布,邀您体验

    Release版本,新增4000+个API,应用开发能力更加丰富;HDF新增200+个HDI接口,硬件适配更加便捷;持续优化图形框架、方舟编译器(ArkCompiler)、ArkUI
    的头像 发表于 11-10 20:15 285次阅读

    OpenHarmony:全流程讲解如何编写Watchdog平台驱动以及应用程序

    watchdog的hdf驱动具体如下所示: CONFIG_DRIVERS_HDF_PLATFORM_WATCHDOG=y 3.3、OpenHar
    发表于 09-19 11:43

    OpenHarmony:全流程讲解如何编写RTC平台驱动以及应用程序

    ;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。2.2、RTC驱动开发在HDF框架中,RTC的接口适配模式采用独立服务模式
    发表于 09-18 15:45

    OpenHarmony:如何使用HDF平台驱动控制PWM

    方法的目的。独立服务模式可以直接借助HDF设备管理器的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。独立服务模式下,核心层不
    发表于 09-13 11:53

    OpenHarmony:如何使用HDF平台驱动控制I2C

    功能说明: I2cLockMethod结构体成员函数功能说明: 2.2.2、I2C驱动开发步骤 I2C模块适配HDF框架包含以下四个步骤: 实例化驱动入口。 配置属性文件。 实例
    发表于 09-12 15:18

    OpenHarmony:如何使用HDF驱动控制LED灯

    跑通。详细资料请参考官网:https://gitee.com/Lockzhiner-Ele ... les/b02_hdf_rgb_led详细资料请参考OpenHarmony官网: GPIO平台驱动
    发表于 09-05 14:10

    OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序

    设备的能力。 核心层:主要负责服务绑定、初始化以及释放管理器,并提供添加、删除以及获取控制器的能力。 适配层:由驱动适配者实现与硬件相关的具体
    发表于 09-04 16:34

    开源图形驱动OpenHarmony上的使用和落地

    。 03►开源图形驱动OpenHarmony上的移植 OpenHarmony驱动框架支持多种接入模式
    发表于 08-31 18:07

    OpenHarmony平台驱动案例--UART

    函数,驱动适配者需要在适配层实现这些函数的具体功能,并与钩子函数挂接,从而完成适配层与核心层的交互。UartHostMethod定义:struct UartHostMethod { int32_t
    发表于 08-17 16:57

    OpenHarmony:全流程讲解如何编写简易HDF驱动以及应用程序

    OpenHarmony HDF开发简介HDF(Hardware Driver Foundation)驱动框架,为
    发表于 08-17 10:29

    OpenHarmony 3.2 Release新特性解读之驱动HCS

    HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置
    发表于 05-31 10:30

    OpenHarmony支持HDMI接口声卡适配说明

    /hdf_core/framework/model/audio/hdmi。平台适配支持HDMI声卡可以不用关注驱动具体实现。 支持HDMI声卡是O
    发表于 05-23 14:04

    Linux的PWM驱动框架实现方法

    本文主要讲述了Linux的PWM驱动框架实现方法驱动添加方法和调试
    的头像 发表于 05-14 15:24 1009次阅读
    Linux的PWM<b class='flag-5'>驱动</b><b class='flag-5'>框架</b>及<b class='flag-5'>实现</b><b class='flag-5'>方法</b>