文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

OpenHarmony HDF HDI基础能力分析与使用

2024-12-14 00:39

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

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. 实现驱动入口

  1. int SampleDriverBind(struct HdfDeviceObject *deviceObject) 
  2.     HDF_LOGE("SampleDriverBind enter!"); 
  3.     static struct IDeviceIoService testService = { 
  4.         .Dispatch = SampleServiceDispatch, // 服务回调接口 
  5.     }; 
  6.     deviceObject->service = &testService; 
  7.     return HDF_SUCCESS; 
  8.   
  9. int SampleDriverInit(struct HdfDeviceObject *deviceObject) 
  10.     HDF_LOGE("SampleDriverInit enter"); 
  11.   
  12.     return HDF_SUCCESS; 
  13.   
  14. void SampleDriverRelease(struct HdfDeviceObject *deviceObject) 
  15.     HDF_LOGE("SampleDriverRelease enter"); 
  16.     return
  17.   
  18. struct HdfDriverEntry g_sampleDriverEntry = { 
  19.     .moduleVersion = 1, 
  20.     .moduleName = "sample_driver"
  21.     .Bind = SampleDriverBind, 
  22.     .Init = SampleDriverInit, 
  23.     .Release = SampleDriverRelease, 
  24. }; 
  25.  
  26. HDF_INIT(g_sampleDriverEntry); 

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

2. 实现服务响应接口

  1. int32_t SampleServiceOnRemoteRequest(struct HdfDeviceIoClient *client, int cmdId, 
  2.     struct HdfSBuf *data, struct HdfSBuf *reply) 
  3.     switch (cmdId) { 
  4.         case SAMPLE_SERVICE_PING: 
  5.             return SampleServiceStubPing(client, data, reply); 
  6.         … … 
  7.         default
  8.             HDF_LOGE("SampleServiceDispatch: not support cmd %d", cmdId); 
  9.             return HDF_ERR_INVALID_PARAM; 
  10.     } 
  11. static int32_t SampleServiceDispatch(struct HdfDeviceIoClient *client, int cmdId, 
  12.     struct HdfSBuf *data, struct HdfSBuf *reply) 
  13.     return SampleServiceOnRemoteRequest(client, cmdId, data, reply); 

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

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

  1. int32_t SbufToParcel(struct HdfSBuf *sbuf, OHOS::MessageParcel **parcel); 

3. UHDF 驱动配置

  1. platform :: host { 
  2.     hostName = "sample_host"
  3.     priority = 50; 
  4.     sample_device :: device { 
  5.         device0 :: deviceNode { 
  6.             policy = 2; 
  7.             priority = 100; 
  8.             moduleName = "libsample_driver.z.so"
  9.             serviceName = "sample_driver_service"
  10.         } 
  11.     } 

参数说明:

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

HDI基础组件

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

SBuf

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

常用 API 如下:

  1. struct HdfSBuf; 
  2. struct HdfSbufImpl; 
  3. struct HdfRemoteService; 
  4.  
  5.  
  6. enum HdfSbufType { 
  7.     SBUF_RAW = 0,    
  8.     SBUF_IPC,        
  9.     SBUF_IPC_HW,     
  10.     SBUF_TYPE_MAX,   
  11. }; 

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

RemoteService

RemoteService 对象和系统 IPC 框架中的 IRemoteObject 对象(仅支持 C++)对应并可以相互转换,表示一个 IPC 对象。相关 API 说明:

  1. // 消息分发器,用于服务端响应调用或者在客户端发起调用 
  2. struct HdfRemoteDispatcher { 
  3.     int (*Dispatch)(struct HdfRemoteService *, int, struct HdfSBuf *, struct HdfSBuf *); 
  4. }; 
  5.  
  6. // RemoteService 死亡回调对象 
  7. struct HdfDeathRecipient { 
  8.     void (*OnRemoteDied)(struct HdfDeathRecipient *, struct HdfRemoteService *); 
  9. }; 
  10.  
  11. struct HdfRemoteService { 
  12.     struct HdfObject object_; 
  13.     struct HdfObject *target; 
  14.     struct HdfRemoteDispatcher *dispatcher; 
  15.     bool isHw; 
  16. }; 
  17. // 以自定义的消息分发器实例化一个RemoteService 
  18. struct HdfRemoteService *HdfRemoteServiceObtain( 
  19.     struct HdfObject *object, struct HdfRemoteDispatcher *dispatcher); 
  20.  
  21. // 回收RemoteService对象 
  22. void HdfRemoteServiceRecycle(struct HdfRemoteService *service); 
  23.  
  24. // 添加RemoteService的死亡通知,如果对应RemoteService的进程异常退出,HdfDeathRecipient的回调接口将被调用 
  25. void HdfRemoteServiceAddDeathRecipient(struct HdfRemoteService *service, struct HdfDeathRecipient *recipient); 

 基于 RemoteService 实现一个服务端的示例:

  1. int SampleServiceStubDispatch( 
  2.     struct HdfRemoteService* service, int code, struct HdfSBuf *data, struct HdfSBuf *reply) 
  3.     // IPC 调用响应接口 
  4.     int ret = HDF_FAILURE; 
  5.     switch (code) { 
  6.         case SAMPLE_IF_0: { 
  7.             // do something 
  8.             break; 
  9.         } 
  10.         default: { 
  11.             ret = HDF_ERR_INVALID_PARAM; 
  12.         } 
  13.     } 
  14.     return ret; 
  15. bool SampleStubConstruct() 
  16.     // 构造消息分发器,实现消息处理回调 
  17.     static struct HdfRemoteDispatcher dispatcher = { 
  18.         .Dispatch = SampleServiceStubDispatch 
  19. }; 
  20. // 实例化RemoteService 
  21.     inst->remote = HdfRemoteServiceObtain((struct HdfObject *)inst, &dispatcher); 
  22.     if (inst->remote == NULL) { 
  23.         HDF_LOGE("Device service manager failed to obtain remote service"); 
  24.         return false
  25. … … 

直接基于 RemoteService 实现服务端只适用于需要实现匿名 IPC 服务的情况,基于 UHDF 发布 HDI 服务只需要实现 Driver 绑定的 IoService 即可。

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

HDI实现


HDI接口调用

HDI驱动框架HDI接口

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

C++实现:

  1. namespace OHOS { 
  2. namespace HDI { 
  3. namespace ServiceManager { 
  4. namespace V1_0 { 
  5.  
  6. struct IServiceManager : public IRemoteBroker { 
  7. public
  8.     DECLARE_INTERFACE_DESCRIPTOR(u"HDI.IServiceManager.V1_0"); 
  9.     // get()静态方法用于获取IServiceManager对象实例 
  10.     static ::OHOS::sptr Get(); 
  11.     // GetService()接口是真正提供的HDI接口,用于查询并获取其他HDI服务的客户端对象 
  12.     virtual ::OHOS::sptr GetService(const char* serviceName) = 0; 
  13. }; 
  14. } // namespace V1_0 
  15. } // namespace ServiceManager 
  16. } // namespace HDI 
  17. } // namespace OHOS 

C 实现:

  1. #ifdef __cplusplus 
  2. extern "C" { 
  3. #endif  
  4.  
  5. struct HDIServiceManager { 
  6.     struct HdfRemoteService *remote; 
  7.  
  8.     struct HdfRemoteService *(*GetService)(struct HDIServiceManager *self, const char* serviceName); 
  9. }; 
  10.  
  11. struct HDIServiceManager *HDIServiceManagerGet(void); 
  12. void HDIServiceManagerRelease(struct HDIServiceManager *servmgr); 
  13.  
  14. #ifdef __cplusplus 
  15. #endif  

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

HDI客户端实现


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

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

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

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

HDI接口调用

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

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

C++接口调用:

  1. #include  
  2.  
  3. void GetTestService() 
  4.      
  5.     auto servmgr = IServiceManager::Get(); 
  6.     if (servmgr == nullptr) { 
  7.     HDF_LOGE("failed to get IServiceManager"); 
  8.     return
  9.   } 
  10.  
  11.     auto sampleService = servmgr->GetService(TEST_SERVICE_NAME); 
  12.   if (sampleService == nullptr) { 
  13.     HDF_LOGE("failed to get TEST_SERVICE"); 
  14.     return
  15.   } 
  16.     // do something 

C 接口调用:

  1. #include  
  2.  
  3. void GetTestService() 
  4.      
  5.     struct HDIServiceManager *servmgr = HDIServiceManagerGet(); 
  6.     if (servmgr == nullptr) { 
  7.     HDF_LOGE("failed to get IServiceManager"); 
  8.     return
  9.   } 
  10.  
  11.     struct HdfRemoteService *sampleService = servmgr->GetService(servmgr, TEST_SERVICE_NAME); 
  12.   if (sampleService == nullptr) { 
  13.     HDF_LOGE("failed to get TEST_SERVICE"); 
  14.     return
  15.   } 
  16.     // do something 

 总结

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

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯