1# IPC与RPC通信开发指导(C/C++) 2<!--Kit: IPC Kit--> 3<!--Subsystem: Communication--> 4<!--Owner: @xdx19211@luodonghui0157--> 5<!--Designer: @zhaopeng_gitee--> 6<!--Tester: @maxiaorong--> 7<!--Adviser: @zhang_yixin13--> 8 9## 场景介绍 10 11IPC让运行在不同进程间的Proxy和Stub实现互相通信。IPC CAPI是IPC Kit提供的C语言接口。 12IPC CAPI接口不直接提供获取通信代理对象的能力,该功能由[Ability Kit](../application-models/abilitykit-overview.md)提供。 13 14 15 16进程间IPC通道的建立,请参考[Native子进程开发指导(C/C++)](../application-models/capi_nativechildprocess_development_guideline.md)。本文重点介绍IPC CAPI的使用。 17 18## 接口说明 19 20**表1** IPC CAPI侧关键接口 21 22| 接口名 | 描述 | 23| ------------------------------------ | ---------------------------------------------------------------- | 24|typedef int (\*OH_OnRemoteRequestCallback)<br>(uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> void \*userData);|Stub端用于处理远端数据请求的回调函数。| 25| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | 创建OHIPCRemoteStub对象。 | 26|int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy \*proxy,<br> uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> const OH_IPC_MessageOption \*option);|IPC消息发送函数。| 27|struct OHIPCRemoteProxy;|用于向远端发送请求的OHIPCRemoteProxy对象,需要依赖元能力接口返回。| 28|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|创建用于监听远端OHIPCRemoteStub对象死亡的通知对象(OHIPCDeathRecipient对象)。| 29|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|向OHIPCRemoteProxy对象注册死亡监听,用于接收远端OHIPCRemoteStub对象死亡时的回调通知。| 30 31详细的接口说明请参考[IPCKit](../reference/apis-ipc-kit/capi-ipckit.md)。 32 33## 开发步骤 34 35先创建服务端Stub对象,通过元能力获取其客户端代理Proxy对象,然后用Proxy对象与服务端Stub对象进行IPC通信,同时再注册远端对象的死亡通知回调,用于Proxy侧感知服务端Stub对象所在进程的死亡状态。 36 37### 添加动态链接库 38 39CMakeLists.txt中添加以下lib。 40 41```txt 42# ipc capi 43libipc_capi.so 44# 元能力,ability capi 45libchild_process.so 46``` 47 48### 头文件 49 50```c++ 51// ipc capi 52#include <IPCKit/ipc_kit.h> 53// 元能力,ability capi。 54#include <AbilityKit/native_child_process.h> 55``` 56 57### 异步调用场景 58 59**公共数据及函数定义** 60 61```c++ 62#include <string> 63#include <thread> 64#include <mutex> 65#include <chrono> 66#include <condition_variable> 67#include <IPCKit/ipc_kit.h> 68#include <AbilityKit/native_child_process.h> 69#include <hilog/log.h> 70#undef LOG_DOMAIN 71#undef LOG_TAG 72#define LOG_DOMAIN 0x0201 73#define LOG_TAG "IPCCApiSample" 74 75enum RequestCode { 76 ASYNC_ADD_CODE = 1, 77 REQUEST_EXIT_CODE = 2, 78 OTHER_CODE 79}; 80static constexpr int MAX_MEMORY_SIZE = 204800; 81static const std::string INTERFACE_DESCRIPTOR = "INTERFACE_DESCRIPTOR"; 82static const std::string NATIVE_REMOTE_STUB_TEST_TOKEN = "native.remote.stub"; 83static const std::string NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN = "native.remote.stub.async.call"; 84 85// 定义内存分配函数。 86static void* LocalMemoryAllocator(int32_t len) { 87 if (len < 0 || len > MAX_MEMORY_SIZE ) { 88 return nullptr; 89 } 90 void *buffer = malloc(len); 91 if (buffer == nullptr) { 92 return nullptr; 93 } 94 memset(buffer, 0, len); 95 return buffer; 96} 97``` 98 99**服务端对象: IpcCApiStubTest** 100 101```c++ 102class IpcCApiStubTest { 103public: 104 explicit IpcCApiStubTest(); 105 ~IpcCApiStubTest(); 106 void MainProc(); 107 OHIPCRemoteStub* GetRemoteStub(); 108 static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData); 109private: 110 int AsyncAdd(const OHIPCParcel *data); 111 int RequestExitChildProcess(); 112private: 113 OHIPCRemoteStub *stub_{ nullptr }; 114 std::mutex childMutex_; 115 std::condition_variable childCondVar_; 116}; 117 118IpcCApiStubTest::IpcCApiStubTest() { 119 // 创建stub对象。 120 stub_ = OH_IPCRemoteStub_Create(INTERFACE_DESCRIPTOR.c_str(), &IpcCApiStubTest::OnRemoteRequest, 121 nullptr, this); 122} 123 124IpcCApiStubTest::~IpcCApiStubTest() { 125 if (stub_ != nullptr) { 126 // 当stub对象不再使用时,销毁该对象。 127 OH_IPCRemoteStub_Destroy(stub_); 128 } 129} 130 131void IpcCApiStubTest::MainProc() { 132 std::unique_lock<std::mutex> autoLock(childMutex_); 133 childCondVar_.wait(autoLock); 134} 135 136OHIPCRemoteStub* IpcCApiStubTest::GetRemoteStub() { 137 return stub_; 138} 139 140// 服务端的请求处理函数,客户端发送的请求在该函数中处理。 141int IpcCApiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData) { 142 int readLen = 0; 143 char *token = nullptr; 144 // 根据客户端传过来的interfaceToken校验当前通信是否合法。 145 if (OH_IPCParcel_ReadInterfaceToken(data, &token, &readLen, LocalMemoryAllocator) != OH_IPC_SUCCESS 146 || NATIVE_REMOTE_STUB_TEST_TOKEN != token) { 147 if (token != nullptr) { 148 OH_LOG_ERROR(LOG_APP, "check InterfaceToken failed"); 149 free(token); 150 } 151 return OH_IPC_PARCEL_WRITE_ERROR; 152 } 153 free(token); 154 auto *stubTest = reinterpret_cast<IpcCApiStubTest *>(userData); 155 if (stubTest == nullptr) { 156 return OH_IPC_CHECK_PARAM_ERROR; 157 } 158 auto rqCode = RequestCode(code); 159 switch (rqCode) { 160 case ASYNC_ADD_CODE: { 161 return stubTest->AsyncAdd(data); 162 } 163 case REQUEST_EXIT_CODE: { 164 return stubTest->RequestExitChildProcess(); 165 } 166 default: 167 break; 168 } 169 return OH_IPC_SUCCESS; 170} 171 172int IpcCApiStubTest::AsyncAdd(const OHIPCParcel *data) { 173 int a = 0; 174 int b = 0; 175 OH_LOG_INFO(LOG_APP, "start async add a=%d,b=%d", a, b); 176 if ((OH_IPCParcel_ReadInt32(data, &a) != OH_IPC_SUCCESS) 177 || (OH_IPCParcel_ReadInt32(data, &b) != OH_IPC_SUCCESS)) { 178 return OH_IPC_PARCEL_READ_ERROR; 179 } 180 // 此处获取proxy对象,用于后续的IPC通信调用。 181 auto proxyCallBack = OH_IPCParcel_ReadRemoteProxy(data); 182 if (proxyCallBack == nullptr) { 183 return OH_IPC_PARCEL_READ_ERROR; 184 } 185 OH_LOG_INFO(LOG_APP, "start create sendCallBack thread!"); 186 // 此处开启线程异步完成功能实现并利用proxyCallBack完成结果响应,如果同步调用,则直接通过replyData写入响应结果即可。 187 std::thread th([proxyCallBack, a, b] { 188 auto data = OH_IPCParcel_Create(); 189 if (data == nullptr) { 190 // 当创建parcel失败,则销毁获取到的proxyCallBack对象。 191 OH_IPCRemoteProxy_Destroy(proxyCallBack); 192 return; 193 } 194 auto reply = OH_IPCParcel_Create(); 195 if (reply == nullptr) { 196 OH_IPCParcel_Destroy(data); 197 OH_IPCRemoteProxy_Destroy(proxyCallBack); 198 return; 199 } 200 if (OH_IPCParcel_WriteInt32(data, a + b) != OH_IPC_SUCCESS) { 201 OH_IPCParcel_Destroy(data); 202 OH_IPCParcel_Destroy(reply); 203 OH_IPCRemoteProxy_Destroy(proxyCallBack); 204 return; 205 } 206 // 异步线程处理结果通过IPC同步调用方式返回给业务请求方。 207 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 }; 208 OH_LOG_INFO(LOG_APP, "thread start sendCallBack!"); 209 // 发送IPC通信请求。 210 int ret = OH_IPCRemoteProxy_SendRequest(proxyCallBack, ASYNC_ADD_CODE, data, reply, &option); 211 OH_LOG_INFO(LOG_APP, "thread sendCallBack ret = %d", ret); 212 if (ret != OH_IPC_SUCCESS) { 213 OH_IPCParcel_Destroy(data); 214 OH_IPCParcel_Destroy(reply); 215 OH_IPCRemoteProxy_Destroy(proxyCallBack); 216 return; 217 } 218 OH_IPCRemoteProxy_Destroy(proxyCallBack); 219 OH_IPCParcel_Destroy(data); 220 OH_IPCParcel_Destroy(reply); 221 }); 222 th.detach(); 223 return OH_IPC_SUCCESS; 224} 225 226int IpcCApiStubTest::RequestExitChildProcess() { 227 std::unique_lock<std::mutex> autoLock(childMutex_); 228 childCondVar_.notify_all(); 229 return OH_IPC_SUCCESS; 230} 231``` 232 233**客户端代理对象: IpcCApiProxyTest** 234 235```cpp 236// 用户自定义错误码。 237static constexpr int OH_IPC_CREATE_OBJECT_ERROR = OH_IPC_USER_ERROR_CODE_MIN + 1; 238 239class IpcCApiProxyTest { 240public: 241 explicit IpcCApiProxyTest(OHIPCRemoteProxy *proxy); 242 ~IpcCApiProxyTest(); 243public: 244 int AsyncAdd(int a, int b, int &result); 245 int RequestExitChildProcess(); 246 void ClearResource(); 247private: 248 void SendAsyncReply(int &replyValue); 249 int WaitForAsyncReply(int timeOut); 250 // 注意:OnRemoteRequest方法是Stub对象需要实现的处理IPC请求消息的回调函数,Proxy侧不需要实现该函数。 251 // 此处的OnRemoteRequest是用来给异步回调对象(下文中的replyStub_)配套使用的处理IPC请求消息的回调函数。 252 static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, 253 OHIPCParcel *reply, void *userData); 254 static void OnDeathRecipientCB(void *userData); 255private: 256 int asyncReply_{}; 257 std::mutex mutex_; 258 std::condition_variable cv_; 259 OHIPCRemoteProxy *proxy_{ nullptr }; 260 OHIPCRemoteStub *replyStub_{ nullptr }; 261 OHIPCDeathRecipient *deathRecipient_{ nullptr }; 262}; 263 264IpcCApiProxyTest::IpcCApiProxyTest(OHIPCRemoteProxy *proxy) { 265 if (proxy == nullptr) { 266 OH_LOG_ERROR(LOG_APP, "proxy is nullptr"); 267 return; 268 } 269 proxy_ = proxy; 270 replyStub_ = OH_IPCRemoteStub_Create(NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN.c_str(), OnRemoteRequest, 271 nullptr, this); 272 if (replyStub_ == nullptr) { 273 OH_LOG_ERROR(LOG_APP, "create reply stub failed!"); 274 return; 275 } 276 // 创建死亡回调对象。 277 deathRecipient_ = OH_IPCDeathRecipient_Create(OnDeathRecipientCB, nullptr, this); 278 if (deathRecipient_ == nullptr) { 279 OH_LOG_ERROR(LOG_APP, "OH_IPCDeathRecipient_Create failed!"); 280 return; 281 } 282 // 向Proxy注册死亡回调对象,用于感知服务端Stub对象的死亡状态。 283 OH_IPCRemoteProxy_AddDeathRecipient(proxy_, deathRecipient_); 284} 285 286IpcCApiProxyTest::~IpcCApiProxyTest() { 287 if (proxy_ != nullptr) { 288 OH_IPCRemoteProxy_Destroy(proxy_); 289 } 290 if (deathRecipient_ != nullptr) { 291 OH_IPCDeathRecipient_Destroy(deathRecipient_); 292 } 293 if (replyStub_ != nullptr) { 294 OH_IPCRemoteStub_Destroy(replyStub_); 295 } 296} 297 298int IpcCApiProxyTest::AsyncAdd(int a, int b, int &result) { 299 OH_LOG_INFO(LOG_APP, "start %d + %d", a, b); 300 auto data = OH_IPCParcel_Create(); 301 if (data == nullptr) { 302 return OH_IPC_CREATE_OBJECT_ERROR; 303 } 304 // 写入接口校验token。 305 if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) { 306 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!"); 307 OH_IPCParcel_Destroy(data); 308 return OH_IPC_PARCEL_WRITE_ERROR; 309 } 310 if (OH_IPCParcel_WriteInt32(data, a) != OH_IPC_SUCCESS 311 || OH_IPCParcel_WriteInt32(data, b) != OH_IPC_SUCCESS 312 || OH_IPCParcel_WriteRemoteStub(data, replyStub_) != OH_IPC_SUCCESS) { 313 OH_IPCParcel_Destroy(data); 314 return OH_IPC_PARCEL_WRITE_ERROR; 315 } 316 // 异步发送使用replyStub_进行响应结果接收,异步处理需要写入用于接收结果的OHIPCRemoteStub对象。 317 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_ASYNC, 0 }; 318 int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::ASYNC_ADD_CODE, data, nullptr, &option); 319 if (ret != OH_IPC_SUCCESS) { 320 OH_IPCParcel_Destroy(data); 321 OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!"); 322 return ret; 323 } 324 static constexpr int TIMEOUT = 3; 325 WaitForAsyncReply(TIMEOUT); 326 OH_LOG_INFO(LOG_APP, "asyncReply_:%d", asyncReply_); 327 result = asyncReply_; 328 OH_IPCParcel_Destroy(data); 329 return OH_IPC_SUCCESS; 330} 331 332int IpcCApiProxyTest::RequestExitChildProcess() { 333 auto data = OH_IPCParcel_Create(); 334 if (data == nullptr) { 335 return OH_IPC_CREATE_OBJECT_ERROR; 336 } 337 auto reply = OH_IPCParcel_Create(); 338 if (reply == nullptr) { 339 OH_IPCParcel_Destroy(data); 340 return OH_IPC_CREATE_OBJECT_ERROR; 341 } 342 if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) { 343 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!"); 344 OH_IPCParcel_Destroy(data); 345 OH_IPCParcel_Destroy(reply); 346 return OH_IPC_PARCEL_WRITE_ERROR; 347 } 348 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 }; 349 int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::REQUEST_EXIT_CODE, data, reply, &option); 350 if (ret != OH_IPC_SUCCESS) { 351 OH_IPCParcel_Destroy(data); 352 OH_IPCParcel_Destroy(reply); 353 OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!"); 354 return ret; 355 } 356 OH_IPCParcel_Destroy(data); 357 OH_IPCParcel_Destroy(reply); 358 return OH_IPC_SUCCESS; 359} 360 361void IpcCApiProxyTest::SendAsyncReply(int &replyValue) { 362 std::unique_lock<std::mutex> lck(mutex_); 363 asyncReply_ = replyValue; 364 cv_.notify_all(); 365} 366 367int IpcCApiProxyTest::WaitForAsyncReply(int timeOut) { 368 asyncReply_ = 0; 369 std::unique_lock<std::mutex> lck(mutex_); 370 cv_.wait_for(lck, std::chrono::seconds(timeOut), [&] { 371 return asyncReply_ != 0; 372 }); 373 return asyncReply_; 374} 375 376int IpcCApiProxyTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, 377 OHIPCParcel *reply, void *userData) { 378 OH_LOG_INFO(LOG_APP, "start %u", code); 379 auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData); 380 if (proxyTest == nullptr || code != static_cast<uint32_t>(RequestCode::ASYNC_ADD_CODE)) { 381 OH_LOG_ERROR(LOG_APP, "check param failed!"); 382 return OH_IPC_CHECK_PARAM_ERROR; 383 } 384 int32_t val = -1; 385 if (OH_IPCParcel_ReadInt32(data, &val) != OH_IPC_SUCCESS) { 386 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_ReadInt32 failed!"); 387 return OH_IPC_PARCEL_READ_ERROR; 388 } 389 proxyTest->SendAsyncReply(val); 390 return OH_IPC_SUCCESS; 391} 392 393void IpcCApiProxyTest::ClearResource() { 394 // clear resource; 395} 396 397void IpcCApiProxyTest::OnDeathRecipientCB(void *userData) { 398 auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData); 399 if (proxyTest != nullptr) { 400 proxyTest->ClearResource(); 401 } 402 OH_LOG_INFO(LOG_APP, "the stub is dead!"); 403} 404``` 405 406**服务端调用入口,服务端文件"libipcCapiDemo.so"** 407 408```C++ 409IpcCApiStubTest g_ipcStubObj; 410 411#ifdef __cplusplus 412extern "C" { 413 414// 服务需要实现如下函数,具体可参考元能力接口说明。 415OHIPCRemoteStub* NativeChildProcess_OnConnect() { 416 OH_LOG_INFO(LOG_APP, "NativeChildProcess_OnConnect"); 417 return g_ipcStubObj.GetRemoteStub(); 418} 419 420void NativeChildProcess_MainProc() { 421 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc"); 422 g_ipcStubObj.MainProc(); 423 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc End"); 424} 425 426} 427#endif 428``` 429 430**客户端调用入口** 431 432```c++ 433IpcCApiProxyTest *g_ipcProxy = nullptr; 434 435// 元能力打通IPC通道回调接口。 436void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) { 437 OH_LOG_INFO(LOG_APP, "OnNativeChildProcessStarted proxy=%{public}p err=%{public}d", remoteProxy, errCode); 438 if (remoteProxy == nullptr) { 439 return; 440 } 441 g_ipcProxy = new (std::nothrow) IpcCApiProxyTest(remoteProxy); 442 if (g_ipcProxy == nullptr) { 443 OH_IPCRemoteProxy_Destroy(remoteProxy); 444 OH_LOG_ERROR(LOG_APP, "Alloc IpcCApiProxyTest object failed"); 445 return; 446 } 447} 448 449int main(int argc, char *argv[]) { 450 // 调用元能力接口,创建子进程,并加载参数中指定的libipcCapiDemo.so文件,进程启动结果通过回调参数OnNativeChildProcessStarted异步通知,在该回调函数中获取Proxy对象。 451 int32_t ret = OH_Ability_CreateNativeChildProcess("libipcCapiDemo.so", OnNativeChildProcessStarted); 452 if (ret != 0) { 453 return -1; 454 } 455 if (g_ipcProxy == nullptr) { 456 return -1; 457 } 458 int a = 2; 459 int b = 3; 460 int result = 0; 461 ret = g_ipcProxy->AsyncAdd(a, b, result); 462 OH_LOG_INFO(LOG_APP, "AsyncAdd: %d + %d = %d, ret=%d", a, b, result, ret); 463 464 // 触发Stub侧进程退出。 465 ret = g_ipcProxy->RequestExitChildProcess(); 466 // 此时,死亡通知回调函数(IpcCApiProxyTest::OnDeathRecipientCB)会被自动执行。 467 if (g_ipcProxy != nullptr) { 468 delete g_ipcProxy; 469 g_ipcProxy = nullptr; 470 } 471 return 0; 472} 473``` 474