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