圆咕噜咕噜 发表于 2025-1-4 16:35:07

鸿蒙进阶——HDI及IDL硬件接口IPC框架小结

一、HDI 和IDL 概述

HDI(Hardware Device Interface):OpenHarmony硬件装备接口,定义体系中跨进程通讯的接口,实现服务间的跨进程通讯,常见的HDI Service 有USB Service 他是由HDF间接启动的。而IDL(Interface Description Language)接口描述语言,是HDI接口的语言格式,接口定义利用IDL语言描述并以·idl文件情势生存。
https://i-blog.csdnimg.cn/blog_migrate/e88bdf2a4875f083e5acbb9ba2650ec9.png
二、IPC框架

HDI文件利用IDL语法描述HDI接口并生存为.idl文件,在编译过程中自动转换为C/C++语言的函数接口声明、客户端与服务端IPC相关过程代码,开辟者只需要基于生成的ifoo.h函数接口实现具体服务功能即可。代码生成与编译功能已经集成在//drivers/hdf_core/adapter/uhdf2/hdi.gni编译模板,基于该编译模板编写idl文件的BUILD.gn就可以简单的生成客户端、服务端代码并编译为共享库。简而言之,就是开辟者只需要根据IDL 语法描述接口,编译后就会自动生成一个C/S 结构的IPC通讯功能块。
https://i-blog.csdnimg.cn/direct/122e1eaf30dd4a5caf77ea3748f07cd8.png
简而言之,HDI 是一套与硬件装备通讯的PC 框架,而IDL 就是HDI文件利用的语法格式,HDI 框架颠末编译后就自动生成一套C/S 架构的IPC 通讯模块,而NNRT 就是通过HDI 接口与硬件装备芯片IPC通讯。
https://i-blog.csdnimg.cn/direct/76885c56a9e34c7581302a5b898dcad5.png
三、HDI 在不同类型体系上的架构

在轻量级 OpenHarmony 体系上,出于减小体系性能负载考虑,HDI 实现为用户态共享库,由体系服务直接加载 HDI 实现到本身进程中函数调用利用。HDI 实现封装具体的用户态内核态交互过程,当需要访问驱动步伐时利用 IO Service 请求将消息通过 system call 方式调用到内核驱动实现。而在尺度 OpenHarmony 体系上,HDI 以独立服务进程方式部署,体系服务只加载 HDI 客户端实现到本身进程中,实际业务运行在独立进程中,客户端通过 IPC 与服务端交互,便于架构解耦、权限管理。
https://i-blog.csdnimg.cn/direct/c1c86aa21af64f67987ffe6db2f31958.png
四、HDI接口基于C/S的IPC 实现

直通模式为函数实现方式,无论调用还是实现都不需要其他组件支持即可实现。
https://i-blog.csdnimg.cn/direct/09efdacb70aa4129abe5856d087ab10b.png
1、HDI 接口声明

HDI 的接口阐明是通过IDL语法描述的.idl 文件,
package ohos.hdi.foo.v1_0;

import ohos.hdi.foo.v1_0.IFooCallback;
import ohos.hdi.foo.v1_0.MyTypes;

interface IFoo {
    Ping( String sendMsg, String recvMsg);

    GetData( struct FooInfo info);

    SendCallbackObj( IFooCallback cbObj);
}
如果interface中用到了自定义数据类型,将自定义类型定义到另一个MyTypes.idl文件中:
package ohos.hdi.foo.v1_0;

enum FooType {
    FOO_TYPE_ONE = 1,
    FOO_TYPE_TWO,
};

struct FooInfo {
    unsigned int id;
    String name;
    enum FooType type;
};
如果需要从服务端回调,可以定义callback接口类IFooCallback.idl
package ohos.hdi.foo.v1_0;

interface IFooCallback {
    PushData( String message);
}
2、编写 idl文件的构建编译脚本BUILD.gn

.idl 最终颠末编译后就会自动生成对应IPC 模式的C/S端的通用的IPC代码框架。而且打包成共享库的情势,已经内置了相关的BUILD.gn 模版
import("//drivers/hdf_core/adapter/uhdf2/hdi.gni")   # 编译idl必须要导入的模板
hdi("foo") {                              # 目标名称,会生成两个so,分别对应 libfoo_client_v1.0.z.so 和 libfoo_stub_v1.0.z.so
    package = "ohos.hdi.foo.v1_0"         # 包名,必须与idl路径匹配
    module_name = "foo"                     # module_name控制dirver文件中驱动描 述符(struct HdfDriverEntry)的moduleName
    sources = [                           # 参与编译的idl文件
      "IFoo.idl",                         # 接口idl
      "IFooCallback.idl",               # 用于回调的idl
      "MyTypes.idl",                      # 自定义类型idl
    ]
    language = "cpp"                        # 控制idl生成c或c++代码 可选择`c`或`cpp`
}
3、继承编译后的idl 接口实现HDI服务的真正业务功能

颠末idl编译后将在out目次out//gen/drivers/interfaces/foo/v1_0生成通用的模子代码框架,好比说已经帮你完成了IPC的调用和监听逻辑,作为HDI服务开辟者无需去考虑了,但是你这个服务真正的定制化的业务功能是需要本身去实现的,简而言之,实现这个HDI服务只是借助体系IPC帮你打通了通讯链路,至于你要干什么需要你本身去实现。基于工具自动生成的foo_interface_service.h,实现其中的服务接口,并将相关源码编译为FooService.z.so则
但是由于驱动很多时候涉及到底层操纵和多体系迁移的场景而利用C语言编写,所以驱动框架还提供了 HDI 服务的 C 语言实现的基础组件,C++ 实现则重要利用体系通讯框架组件。
namespace OHOS {
namespace HDI {
namespace Foo {
    namespace V1_0 {
   
      class FooService : public IFoo {//继承接口类,并重写接口
      public:
            virtual ~FooService() {}
      
            int32_t Ping(const std::string& sendMsg, std::string& recvMsg) override;
            int32_t FooService::GetData(FooInfo& info) override;
            int32_t FooService::SendCallbackObj(const sptr<IFooCallback>& cbObj) override;
      };
    } // namespace V1_0
} // namespace Foo
} // namespace Hdi
} // namespace OHOS
4、实现HDI服务驱动入口

HDI服务发布是基于用户态HDF驱动框架,所以需要实现一个驱动入口。驱动实现代码参考已经在out目次中生成,如out/gen/xxx/foo_interface_driver.cpp,可以根据业务需要直接利用该文件或参考该文件按业务需要重新实现。 然后将驱动入口源码编译为libfoo_driver.z.so(该名称无逼迫规定,与hcs配置中配套即可)。
由HDF 驱动框架实现。
5、发布HDI服务

在产品hcs配置中声明HDI服务,以尺度体系Hi3516DV300单板为例,HDF装备配置路径为vendor/hisilicon/Hi3516DV300/hdf_config/uhdf/device_info.hcs,在其中新增以下配置:
fooHost :: host {
      hostName = "fooHost";
      priority = 50;
      fooDevice :: device {
            device0 :: deviceNode {
                policy = 2;
                priority = 100;
                preload = 2;
                moduleName = "libfoo_driver.z.so";
                serviceName = "foo_service";
            }
      }
    }
6、调用HDI服务



[*]客户端在BUILD.gn中增加依赖: //drivers/interface/foo/v1.0:libfoo_proxy_1.0"
[*]在代码中调用HDI接口(以CPP为例)
#include <v1_0/ifoo_interface.h>

int WorkFunc(void) {
    sptr<IFoo> foo = OHOS::HDI::Foo::V1_0::Foo::Get(); // 使用Foo对象的内置静态方法获取该服务客户端实例
    if (foo == nullptr) {
      // hdi service not exist, handle error
    }
    foo->Ping(); // do interface call
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙进阶——HDI及IDL硬件接口IPC框架小结