Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
ast/ | 12-May-2024 | - | 2,396 | 1,402 | ||
codegen/ | 12-May-2024 | - | 3,468 | 2,941 | ||
figures/ | 12-May-2024 | - | ||||
metadata/ | 12-May-2024 | - | 1,653 | 1,152 | ||
parser/ | 12-May-2024 | - | 1,327 | 1,085 | ||
test/ | 12-May-2024 | - | 14,597 | 9,948 | ||
util/ | 12-May-2024 | - | 2,160 | 1,555 | ||
BUILD.gn | D | 12-May-2024 | 2.1 KiB | 88 | 76 | |
LICENSE | D | 12-May-2024 | 10.1 KiB | 177 | 150 | |
OAT.xml | D | 12-May-2024 | 4 KiB | 70 | 16 | |
README.md | D | 12-May-2024 | 13.3 KiB | 390 | 302 | |
bundle.json | D | 12-May-2024 | 1.2 KiB | 44 | 43 | |
idl.gni | D | 12-May-2024 | 762 | 17 | 15 | |
idl_tool.gni | D | 12-May-2024 | 814 | 18 | 16 | |
main.cpp | D | 12-May-2024 | 3 KiB | 107 | 75 |
README.md
1# IDL工具 2 3## 简介 4 5在OpenHarmony中,当应用/系统服务的客户端和服务端进行IPC(Inter-Process Communication)跨线程通信时,需要定义双方都认可的接口,以保障双方可以成功通信,OpenHarmony IDL(Interface Definition Language)则是一种定义此类接口的工具。OpenHarmony IDL先把需要传递的对象分解成操作系统能够理解的基本类型,并根据开发者的需要封装跨边界的对象。 6 7 **图1** IDL接口描述 8  9 10OpenHarmony IDL接口描述语言主要用于: 11 12- 声明系统服务对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。 13 14- 声明Ability对外提供的服务接口,根据接口声明在编译时生成跨进程调用(IPC)或跨设备调用(RPC)的代理(Proxy)和桩(Stub)的C/C++代码或JS/TS代码。 15 16**图2** IPC/RPC通信模型 17 18 19 20使用OpenHarmony IDL接口描述语言声明接口具有以下优点: 21 22- OpenHarmony IDL中是以接口的形式定义服务,可以专注于定义而隐藏实现细节。 23 24- OpenHarmony IDL中定义的接口可以支持跨进程调用或跨设备调用。根据OpenHarmony IDL中的定义生成的信息或代码可以简化跨进程或跨设备调用接口的实现。 25 26**部件内子模块职责** 27 28| 子模块名称 | 职责 | 29| ---------------- | ------------------------------------------------------------| 30| 接口文件解析模块 | 解析校验接口定义文件。 | 31| stub/proxy自动生成模块 | 根据IPC/RPC规格自动生成Stub服务端和Proxy客户端代码。 | 32 33## 目录 34 35``` 36foundation/ability/idl_tool 37├── ast # idl语法解析定义代码 38├── codegen # 跨进程通信模板生成模块代码 39├── metadata # matedata自定义数据解析模块代码 40├── parser # idl解析模块代码 41├── test # 测试目录 42└── util # 公共方法代码 43``` 44 45## 开发步骤 46idl工具的获取和TS开发步骤可参考[开发指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/IDL/idl-guidelines.md#31-c%E5%BC%80%E5%8F%91%E6%AD%A5%E9%AA%A4)。 47 48### C++开发步骤 49 50#### 创建.idl文件 51 52开发者可以使用C++编程语言构建.idl文件。 53 54例如,此处构建一个名为IIdlTestService.idl的文件,文件内具体内容如下: 55 56```cpp 57 interface OHOS.IIdlTestService { 58 int TestIntTransaction([in] int data); 59 void TestStringTransaction([in] String data); 60 } 61``` 62 63在idl的可执行文件所在文件夹下执行命令 `idl -gen-cpp -d dir -c dir/IIdlTestService.idl`。 64 65-d后的dir为目标输出目录,以输出文件夹名为IIdlTestServiceCpp为例,在idl可执行文件所在目录下执行`idl -gen-cpp -d IIdlTestServiceCpp -c IIdlTestServiceCpp/IIdlTestService.idl`,将会在执行环境的dir目录(即IIdlTestServiceCpp目录)中生成接口文件、Stub文件、Proxy文件。 66 67 > **注意**:生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。 68 69以名为`IIdlTestService.idl`的.idl文件、目标输出文件夹为IIdlTestServiceCpp为例,其目录结构应类似于: 70 71``` 72├── IIdlTestServiceCpp # idl代码输出文件夹 73│ ├── iidl_test_service.h # 生成文件 74│ ├── idl_test_service_proxy.h # 生成文件 75│ ├── idl_test_service_stub.h # 生成文件 76│ ├── idl_test_service_proxy.cpp # 生成文件 77│ ├── idl_test_service_stub.cpp # 生成文件 78│ └── IIdlTestService.idl # 构造的.idl文件 79└── idl.exe # idl的可执行文件 80``` 81 82#### 服务端公开接口 83 84OpenHarmony IDL工具生成的Stub类是接口类的抽象实现,并且会声明.idl文件中的所有方法。 85 86```cpp 87#ifndef OHOS_IDLTESTSERVICESTUB_H 88#define OHOS_IDLTESTSERVICESTUB_H 89#include <iremote_stub.h> 90#include "iidl_test_service.h" 91 92namespace OHOS { 93class IdlTestServiceStub : public IRemoteStub<IIdlTestService> { 94public: 95 int OnRemoteRequest( 96 /* [in] */ uint32_t code, 97 /* [in] */ MessageParcel& data, 98 /* [out] */ MessageParcel& reply, 99 /* [in] */ MessageOption& option) override; 100 101private: 102 static constexpr int COMMAND_TEST_INT_TRANSACTION = MIN_TRANSACTION_ID + 0; 103 static constexpr int COMMAND_TEST_STRING_TRANSACTION = MIN_TRANSACTION_ID + 1; 104}; 105} // namespace OHOS 106#endif // OHOS_IDLTESTSERVICESTUB_H 107``` 108 109开发者需要继承.idl文件中定义的接口类并实现其中的方法,同时在服务侧初始化时需要将定义的服务注册至SAMGR中,在本示例中,TestService类继承了IdlTestServiceStub接口类并实现了其中的TestIntTransaction和TestStringTransaction方法。具体的示例代码如下: 110 111```cpp 112#ifndef OHOS_IPC_TEST_SERVICE_H 113#define OHOS_IPC_TEST_SERVICE_H 114 115#include "hilog/log.h" 116#include "log_tags.h" 117#include "idl_test_service_stub.h" 118 119namespace OHOS { 120class TestService : public IdlTestServiceStub { 121public: 122 TestService(); 123 ~TestService(); 124 static int Instantiate(); 125 ErrCode TestIntTransaction(int data, int &rep) override; 126 ErrCode TestStringTransaction(const std::string& data) override; 127private: 128 static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestService" }; 129}; 130} // namespace OHOS 131#endif // OHOS_IPC_TEST_SERVICE_H 132``` 133 134注册服务的示例代码如下: 135 136```cpp 137#include "test_service.h" 138 139#include <string_ex.h> 140 141#include "if_system_ability_manager.h" 142#include "ipc_debug.h" 143#include "ipc_skeleton.h" 144#include "iservice_registry.h" 145#include "system_ability_definition.h" 146 147namespace OHOS { 148using namespace OHOS::HiviewDFX; 149 150int TestService::Instantiate() 151{ 152 ZLOGI(LABEL, "%{public}s call in", __func__); 153 auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 154 if (saMgr == nullptr) { 155 ZLOGE(LABEL, "%{public}s:fail to get Registry", __func__); 156 return -ENODEV; 157 } 158 159 sptr<IRemoteObject> newInstance = new TestService(); 160 int result = saMgr->AddSystemAbility(IPC_TEST_SERVICE, newInstance); 161 ZLOGI(LABEL, "%{public}s: IPC_TEST_SERVICE result = %{public}d", __func__, result); 162 return result; 163} 164 165TestService::TestService() 166{ 167} 168 169TestService::~TestService() 170{ 171} 172 173ErrCode TestService::TestIntTransaction(int data, int &rep) 174{ 175 ZLOGE(LABEL, " TestService:read from client data = %{public}d", data); 176 rep = data + data; 177 return ERR_NONE; 178} 179 180ErrCode TestService::TestStringTransaction(const std::string &data) 181{ 182 ZLOGE(LABEL, "TestService:read string from client data = %{public}s", data.c_str()); 183 return data.size(); 184} 185} // namespace OHOS 186``` 187 188#### 客户端调用IPC方法 189 190C++客户端通常通过SAMGR获取系统中定义的服务代理,随后即可正常调用proxy提供的接口。示例代码如下: 191 192```cpp 193#include "test_client.h" 194 195#include "if_system_ability_manager.h" 196#include "ipc_debug.h" 197#include "ipc_skeleton.h" 198#include "iservice_registry.h" 199#include "system_ability_definition.h" 200 201namespace OHOS { 202int TestClient::ConnectService() 203{ 204 auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 205 if (saMgr == nullptr) { 206 ZLOGE(LABEL, "get registry fail"); 207 return -1; 208 } 209 210 sptr<IRemoteObject> object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); 211 if (object != nullptr) { 212 ZLOGE(LABEL, "Got test Service object"); 213 testService_ = (new (std::nothrow) IdlTestServiceProxy(object)); 214 } 215 216 if (testService_ == nullptr) { 217 ZLOGE(LABEL, "Could not find Test Service!"); 218 return -1; 219 } 220 221 return 0; 222} 223 224void TestClient::StartIntTransaction() 225{ 226 if (testService_ != nullptr) { 227 ZLOGE(LABEL, "StartIntTransaction"); 228 [[maybe_unused]] int result = 0; 229 testService_->TestIntTransaction(1234, result); // 1234 : test number 230 ZLOGE(LABEL, "Rec result from server %{public}d.", result); 231 } 232} 233 234void TestClient::StartStringTransaction() 235{ 236 if (testService_ != nullptr) { 237 ZLOGI(LABEL, "StartIntTransaction"); 238 testService_->TestStringTransaction("IDL Test"); 239 } 240} 241} // namespace OHOS 242``` 243 244## C++与TS互通开发步骤 245 246### TS Proxy与C++ Stub开发步骤 247 248#### C++端提供服务对象 249 2501. 如上所述C++开发步骤,开发者使用C++编程语言构建.idl文件,通过命令生成接口、Stub文件、Proxy文件。 251 2522. 开发者创建服务对象,并继承C++ Stub文件中定义的接口类并实现其中的方法,例如: 253 254 ```cpp 255 class IdlTestServiceImpl : public IdlTestServiceStub { 256 public: 257 IdlTestServiceImpl() = default; 258 virtual ~IdlTestServiceImpl() = default; 259 260 ErrCode TestIntTransaction(int _data, int& result) override 261 { 262 result = 256; 263 return ERR_OK; 264 } 265 266 ErrCode TestStringTransaction(const std::string& _data) override 267 { 268 return ERR_OK; 269 } 270 }; 271 ``` 272 273#### C++端提供napi接口 274 275C++需要通过napi的方式,把C++服务对象提供给TS端,例如:C++端提供一个GetNativeObject方法,方法里创建IdlTestServiceImpl实例,通过NAPI_ohos_rpc_CreateJsRemoteObject方法,创建出一个JS远程对象供TS应用使用,如下: 276 277```cpp 278NativeValue* GetNativeObject(NativeEngine& engine, NativeCallbackInfo& info) 279{ 280 sptr<IdlTestServiceImpl> impl = new IdlTestServiceImpl(); 281 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(reinterpret_cast<napi_env>(&engine), impl); 282 NativeValue* nativeRemoteObject = reinterpret_cast<NativeValue*>(napiRemoteObject); 283 return nativeRemoteObject; 284} 285``` 286 287#### TS端提供Proxy对象 288 289如上所述TS开发步骤,开发者使用TS编程语言构建.idl文件,通过命令生成接口、Stub文件、Proxy文件。Proxy文件例如: 290 291```ts 292import {testIntTransactionCallback} from "./i_idl_test_service"; 293import {testStringTransactionCallback} from "./i_idl_test_service"; 294import IIdlTestService from "./i_idl_test_service"; 295import rpc from "@ohos.rpc"; 296 297export default class IdlTestServiceProxy implements IIdlTestService { 298 constructor(proxy) { 299 this.proxy = proxy; 300 } 301 302 testIntTransaction(data: number, callback: testIntTransactionCallback): void 303 { 304 let _option = new rpc.MessageOption(); 305 let _data = new rpc.MessageParcel(); 306 let _reply = new rpc.MessageParcel(); 307 _data.writeInt(data); 308 this.proxy.sendMessageRequest(IdlTestServiceProxy.COMMAND_TEST_INT_TRANSACTION, _data, _reply, _option).then(function(result) { 309 if (result.errCode == 0) { 310 let _errCode = result.reply.readInt(); 311 if (_errCode != 0) { 312 let _returnValue = undefined; 313 callback(_errCode, _returnValue); 314 return; 315 } 316 let _returnValue = result.reply.readInt(); 317 callback(_errCode, _returnValue); 318 } else { 319 console.log('sendMessageRequest failed, errCode: ' + result.errCode); 320 } 321 }) 322 } 323 324 testStringTransaction(data: string, callback: testStringTransactionCallback): void 325 { 326 let _option = new rpc.MessageOption(); 327 let _data = new rpc.MessageParcel(); 328 let _reply = new rpc.MessageParcel(); 329 _data.writeString(data); 330 this.proxy.sendMessageRequest(IdlTestServiceProxy.COMMAND_TEST_STRING_TRANSACTION, _data, _reply, _option).then(function(result) { 331 if (result.errCode == 0) { 332 let _errCode = result.reply.readInt(); 333 callback(_errCode); 334 } else { 335 console.log('sendMessageRequest failed, errCode: ' + result.errCode); 336 } 337 }) 338 } 339 340 static readonly COMMAND_TEST_INT_TRANSACTION = 1; 341 static readonly COMMAND_TEST_STRING_TRANSACTION = 2; 342 private proxy 343} 344``` 345 346#### TS与C++实现互通 347 3481. TS应用调用napi接口获取C++服务的远程对象 3492. 构建TS Proxy对象,并把C++服务的远程对象传递给它 3503. 此时开发者通过TS Proxy对象调用.idl声明的方法,实现TS Proxy与C++ Stub的互通,示例如下: 351 352```ts 353import IdlTestServiceProxy from './idl_test_service_proxy' 354import nativeMgr from 'nativeManager'; 355 356function testIntTransactionCallback(errCode: number, returnValue: number) 357{ 358 console.log('errCode: ' + errCode + ' returnValue: ' + returnValue); 359} 360 361function testStringTransactionCallback(errCode: number) 362{ 363 console.log('errCode: ' + errCode); 364} 365 366function jsProxyTriggerCppStub() 367{ 368 let nativeObj = nativeMgr.GetNativeObject(); 369 let tsProxy = new IdlTestServiceProxy(nativeObj); 370 // invoke testIntTransaction 371 tsProxy.testIntTransaction(10, testIntTransactionCallback); 372 373 // invoke testStringTransaction 374 tsProxy.testStringTransaction('test', testIntTransactionCallback); 375} 376``` 377 378## 相关仓 379元能力子系统 380 381[ability_base](https://gitee.com/openharmony/ability_ability_base) 382 383[ability_runtime](https://gitee.com/openharmony/ability_ability_runtime) 384 385[dmsfwk](https://gitee.com/openharmony/ability_dmsfwk) 386 387[form_fwk](https://gitee.com/openharmony/ability_form_fwk) 388 389[**idl_tool**](https://gitee.com/openharmony/ability_idl_tool) 390