1# IPC Development (C/C++) 2 3 4## When to Use 5 6Inter-process communication (IPC) allows the proxy and stub running in different processes to communicate with each other using C/C++ APIs. However, the IPC C/C++ APIs cannot implement cross-process communication directly. The setup of an IPC channel between two processes depends on abilities. 7 8 9 10For details about how to set up an IPC channel between processes, see [Ability Development](../application-models/capi_nativechildprocess_development_guideline.md). This topic focuses on how to use the IPC C/C++ APIs. 11 12## Available APIs 13 14**Table 1** IPC C/C++ APIs 15 16| API | Description | 17| ------------------------------------ | ---------------------------------------------------------------- | 18|typedef int (\*OH_OnRemoteRequestCallback)<br>(uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> void \*userData);|Called to process the peer request at the stub.| 19| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | Creates an **OHIPCRemoteStub** object.| 20|int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy \*proxy,<br> uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> const OH_IPC_MessageOption \*option);|Sends an IPC message.| 21|struct OHIPCRemoteProxy;|Defines an **OHIPCRemoteProxy** object, which is used to send requests to the peer end.<br>The **OHIPCRemoteProxy** object is returned by an ability API. | 22|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|Creates an **OHIPCDeathRecipient** object, which alllows a notification to be received when the peer **OHIPCRemoteStub** object dies unexpectedly.| 23|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|Adds a recipient to the **OHIPCRemoteProxy** object to receive notifications of the death of the peer **OHIPCRemoteStub** object.| 24 25For details about the APIs, see [IPC Kit](../reference/apis-ipc-kit/_i_p_c_kit.md). 26 27 28## How to Develop 29 30The following describes how to use the C/C++ APIs provided by IPC Kit to implement communication between the stub (service provider) and the proxy (service requester) and listen for the death of the peer end. 31 32### 1. Adding Dynamic Link Libraries 33 34Add the following libraries to **CMakeLists.txt**. 35 36```txt 37# ipc capi 38libipc_capi.so 39# Ability C/C++ APIs 40libchild_process.so 41``` 42 43### 2. Adding Header Files 44 45```c++ 46// IPC C/C++ APIs 47#include <IPCKit/ipc_kit.h> 48// Ability C/C++ APIs 49#include <AbilityKit/native_child_process.h> 50``` 51 52### 3. Implementing IPC 53#### Common Data and Functions 54 55```c++ 56#include <string> 57#include <thread> 58#include <mutex> 59#include <chrono> 60#include <condition_variable> 61#include <IPCKit/ipc_kit.h> 62#include <AbilityKit/native_child_process.h> 63#include <hilog/log.h> 64#undef LOG_DOMAIN 65#undef LOG_TAG 66#define LOG_DOMAIN 0x0201 67#define LOG_TAG "IPCCApiSample" 68 69enum RequestCode { 70 ASYNC_ADD_CODE = 1, 71 REQUEST_EXIT_CODE = 2, 72 OTHER_CODE 73}; 74static constexpr int MAX_MEMORY_SIZE = 204800; 75static const std::string INTERFACE_DESCRIPTOR = "INTERFACE_DESCRIPTOR"; 76static const std::string NATIVE_REMOTE_STUB_TEST_TOKEN = "native.remote.stub"; 77static const std::string NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN = "native.remote.stub.async.call"; 78 79// Define the memory allocation function. 80static void* LocalMemoryAllocator(int32_t len) { 81 if (len < 0 || len > MAX_MEMORY_SIZE ) { 82 return nullptr; 83 } 84 void *buffer = malloc(len); 85 if (buffer == nullptr) { 86 return nullptr; 87 } 88 memset(buffer, 0, len); 89 return buffer; 90} 91``` 92#### Server Object IpcCApiStubTest 93 94```c++ 95class IpcCApiStubTest { 96public: 97 explicit IpcCApiStubTest(); 98 ~IpcCApiStubTest(); 99 void MainProc(); 100 OHIPCRemoteStub* GetRemoteStub(); 101 static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData); 102private: 103 int AsyncAdd(const OHIPCParcel *data); 104 int RequestExitChildProcess(); 105private: 106 OHIPCRemoteStub *stub_{ nullptr }; 107 std::mutex childMutex_; 108 std::condition_variable childCondVar_; 109}; 110 111IpcCApiStubTest::IpcCApiStubTest() { 112 stub_ = OH_IPCRemoteStub_Create(INTERFACE_DESCRIPTOR.c_str(), &IpcCApiStubTest::OnRemoteRequest, 113 nullptr, this); 114} 115 116IpcCApiStubTest::~IpcCApiStubTest() { 117 if (stub_ != nullptr) { 118 OH_IPCRemoteStub_Destroy(stub_); 119 } 120} 121 122void IpcCApiStubTest::MainProc() { 123 std::unique_lock<std::mutex> autoLock(childMutex_); 124 childCondVar_.wait(autoLock); 125} 126 127OHIPCRemoteStub* IpcCApiStubTest::GetRemoteStub() { 128 return stub_; 129} 130 131int IpcCApiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData) { 132 int readLen = 0; 133 char *token = nullptr; 134 // Interface verification 135 if (OH_IPCParcel_ReadInterfaceToken(data, &token, &readLen, LocalMemoryAllocator) != OH_IPC_SUCCESS 136 || NATIVE_REMOTE_STUB_TEST_TOKEN != token) { 137 if (token != nullptr) { 138 OH_LOG_ERROR(LOG_APP, "check InterfaceToken failed"); 139 free(token); 140 } 141 return OH_IPC_PARCEL_WRITE_ERROR; 142 } 143 free(token); 144 auto *stubTest = reinterpret_cast<IpcCApiStubTest *>(userData); 145 if (stubTest == nullptr) { 146 return OH_IPC_CHECK_PARAM_ERROR; 147 } 148 auto rqCode = RequestCode(code); 149 switch (rqCode) { 150 case ASYNC_ADD_CODE: { 151 return stubTest->AsyncAdd(data); 152 } 153 case REQUEST_EXIT_CODE: { 154 return stubTest->RequestExitChildProcess(); 155 } 156 default: 157 break; 158 } 159 return OH_IPC_SUCCESS; 160} 161 162int IpcCApiStubTest::AsyncAdd(const OHIPCParcel *data) { 163 int a = 0; 164 int b = 0; 165 OH_LOG_INFO(LOG_APP, "start async add a=%d,b=%d", a, b); 166 if ((OH_IPCParcel_ReadInt32(data, &a) != OH_IPC_SUCCESS) 167 || (OH_IPCParcel_ReadInt32(data, &b) != OH_IPC_SUCCESS)) { 168 return OH_IPC_PARCEL_READ_ERROR; 169 } 170 auto proxyCallBack = OH_IPCParcel_ReadRemoteProxy(data); 171 if (proxyCallBack == nullptr) { 172 return OH_IPC_PARCEL_READ_ERROR; 173 } 174 OH_LOG_INFO(LOG_APP, "start create sendCallBack thread!"); 175 // Define asynchronous thread processing and use proxyCallBack to respond to asynchronous results. To implement synchronous calls, use replyData to write the response result. 176 std::thread th([proxyCallBack, a, b] { 177 auto data = OH_IPCParcel_Create(); 178 if (data == nullptr) { 179 OH_IPCRemoteProxy_Destroy(proxyCallBack); 180 return; 181 } 182 auto reply = OH_IPCParcel_Create(); 183 if (reply == nullptr) { 184 OH_IPCParcel_Destroy(data); 185 OH_IPCRemoteProxy_Destroy(proxyCallBack); 186 return; 187 } 188 if (OH_IPCParcel_WriteInt32(data, a + b) != OH_IPC_SUCCESS) { 189 OH_IPCParcel_Destroy(data); 190 OH_IPCParcel_Destroy(reply); 191 OH_IPCRemoteProxy_Destroy(proxyCallBack); 192 return; 193 } 194 // The asynchronous thread processing result is returned to the service requester in IPC synchronous calls. 195 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 }; 196 OH_LOG_INFO(LOG_APP, "thread start sendCallBack!"); 197 int ret = OH_IPCRemoteProxy_SendRequest(proxyCallBack, ASYNC_ADD_CODE, data, reply, &option); 198 OH_LOG_INFO(LOG_APP, "thread sendCallBack ret = %d", ret); 199 if (ret != OH_IPC_SUCCESS) { 200 OH_IPCParcel_Destroy(data); 201 OH_IPCParcel_Destroy(reply); 202 OH_IPCRemoteProxy_Destroy(proxyCallBack); 203 return; 204 } 205 OH_IPCRemoteProxy_Destroy(proxyCallBack); 206 OH_IPCParcel_Destroy(data); 207 OH_IPCParcel_Destroy(reply); 208 }); 209 th.detach(); 210 return OH_IPC_SUCCESS; 211} 212 213int IpcCApiStubTest::RequestExitChildProcess() { 214 std::unique_lock<std::mutex> autoLock(childMutex_); 215 childCondVar_.notify_all(); 216 return OH_IPC_SUCCESS; 217} 218``` 219 220#### Client Proxy Object IpcCApiProxyTest 221 222```cpp 223// Customize error codes. 224static constexpr int OH_IPC_CREATE_OBJECT_ERROR = OH_IPC_USER_ERROR_CODE_MIN + 1; 225 226class IpcCApiProxyTest { 227public: 228 explicit IpcCApiProxyTest(OHIPCRemoteProxy *proxy); 229 ~IpcCApiProxyTest(); 230public: 231 int AsyncAdd(int a, int b, int &result); 232 int RequestExitChildProcess(); 233 void ClearResource(); 234private: 235 void SendAsyncReply(int &replyValue); 236 int WaitForAsyncReply(int timeOut); 237 static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, 238 OHIPCParcel *reply, void *userData); 239 static void OnDeathRecipientCB(void *userData); 240private: 241 int asyncReply_{}; 242 std::mutex mutex_; 243 std::condition_variable cv_; 244 OHIPCRemoteProxy *proxy_{ nullptr }; 245 OHIPCRemoteStub *replyStub_{ nullptr }; 246 OHIPCDeathRecipient *deathRecipient_{ nullptr }; 247}; 248 249IpcCApiProxyTest::IpcCApiProxyTest(OHIPCRemoteProxy *proxy) { 250 if (proxy == nullptr) { 251 OH_LOG_ERROR(LOG_APP, "proxy is nullptr"); 252 return; 253 } 254 proxy_ = proxy; 255 replyStub_ = OH_IPCRemoteStub_Create(NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN.c_str(), OnRemoteRequest, 256 nullptr, this); 257 if (replyStub_ == nullptr) { 258 OH_LOG_ERROR(LOG_APP, "crete reply stub failed!"); 259 return; 260 } 261 deathRecipient_ = OH_IPCDeathRecipient_Create(OnDeathRecipientCB, nullptr, this); 262 if (deathRecipient_ == nullptr) { 263 OH_LOG_ERROR(LOG_APP, "OH_IPCDeathRecipient_Create failed!"); 264 return; 265 } 266 OH_IPCRemoteProxy_AddDeathRecipient(proxy_, deathRecipient_); 267} 268 269IpcCApiProxyTest::~IpcCApiProxyTest() { 270 if (proxy_ != nullptr) { 271 OH_IPCRemoteProxy_Destroy(proxy_); 272 } 273 if (deathRecipient_ != nullptr) { 274 OH_IPCDeathRecipient_Destroy(deathRecipient_); 275 } 276 if (replyStub_ != nullptr) { 277 OH_IPCRemoteStub_Destroy(replyStub_); 278 } 279} 280 281int IpcCApiProxyTest::AsyncAdd(int a, int b, int &result) { 282 OH_LOG_INFO(LOG_APP, "start %d + %d", a, b); 283 auto data = OH_IPCParcel_Create(); 284 if (data == nullptr) { 285 return OH_IPC_CREATE_OBJECT_ERROR; 286 } 287 // Write the interface token for verification. 288 if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) { 289 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!"); 290 OH_IPCParcel_Destroy(data); 291 return OH_IPC_PARCEL_WRITE_ERROR; 292 } 293 if (OH_IPCParcel_WriteInt32(data, a) != OH_IPC_SUCCESS 294 || OH_IPCParcel_WriteInt32(data, b) != OH_IPC_SUCCESS 295 || OH_IPCParcel_WriteRemoteStub(data, replyStub_) != OH_IPC_SUCCESS) { 296 OH_IPCParcel_Destroy(data); 297 return OH_IPC_PARCEL_WRITE_ERROR; 298 } 299 // Use replyStub_ to receive responses in asynchronous transmission. In asynchronous processing, the OHIPCRemoteStub object for receiving the result needs to be written. 300 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_ASYNC, 0 }; 301 int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::ASYNC_ADD_CODE, data, nullptr, &option); 302 if (ret != OH_IPC_SUCCESS) { 303 OH_IPCParcel_Destroy(data); 304 OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!"); 305 return ret; 306 } 307 static constexpr int TIMEOUT = 3; 308 WaitForAsyncReply(TIMEOUT); 309 OH_LOG_INFO(LOG_APP, "asyncReply_:%d", asyncReply_); 310 result = asyncReply_; 311 OH_IPCParcel_Destroy(data); 312 OH_IPCParcel_Destroy(reply); 313 return OH_IPC_SUCCESS; 314} 315 316int IpcCApiProxyTest::RequestExitChildProcess() { 317 auto data = OH_IPCParcel_Create(); 318 if (data == nullptr) { 319 return OH_IPC_CREATE_OBJECT_ERROR; 320 } 321 auto reply = OH_IPCParcel_Create(); 322 if (reply == nullptr) { 323 OH_IPCParcel_Destroy(data); 324 return OH_IPC_CREATE_OBJECT_ERROR; 325 } 326 if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) { 327 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!"); 328 OH_IPCParcel_Destroy(data); 329 OH_IPCParcel_Destroy(reply); 330 return OH_IPC_PARCEL_WRITE_ERROR; 331 } 332 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 }; 333 int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::REQUEST_EXIT_CODE, data, reply, &option); 334 if (ret != OH_IPC_SUCCESS) { 335 OH_IPCParcel_Destroy(data); 336 OH_IPCParcel_Destroy(reply); 337 OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!"); 338 return ret; 339 } 340 OH_IPCParcel_Destroy(data); 341 OH_IPCParcel_Destroy(reply); 342 return OH_IPC_SUCCESS; 343} 344 345void IpcCApiProxyTest::SendAsyncReply(int &replyValue) { 346 std::unique_lock<std::mutex> lck(mutex_); 347 asyncReply_ = replyValue; 348 cv_.notify_all(); 349} 350 351int IpcCApiProxyTest::WaitForAsyncReply(int timeOut) { 352 asyncReply_ = 0; 353 std::unique_lock<std::mutex> lck(mutex_); 354 cv_.wait_for(lck, std::chrono::seconds(timeOut), [&] { 355 return asyncReply_ != 0; 356 }); 357 return asyncReply_; 358} 359 360int IpcCApiProxyTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, 361 OHIPCParcel *reply, void *userData) { 362 OH_LOG_INFO(LOG_APP, "start %u", code); 363 auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData); 364 if (proxyTest == nullptr || code != static_cast<uint32_t>(RequestCode::ASYNC_ADD_CODE)) { 365 OH_LOG_ERROR(LOG_APP, "check param failed!"); 366 return OH_IPC_CHECK_PARAM_ERROR; 367 } 368 int32_t val = -1; 369 if (OH_IPCParcel_ReadInt32(data, &val) != OH_IPC_SUCCESS) { 370 OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_ReadInt32 failed!"); 371 return OH_IPC_PARCEL_READ_ERROR; 372 } 373 proxyTest->SendAsyncReply(val); 374 return OH_IPC_SUCCESS; 375} 376 377void IpcCApiProxyTest::ClearResource() { 378 // clear resource; 379} 380 381void IpcCApiProxyTest::OnDeathRecipientCB(void *userData) { 382 auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData); 383 if (proxyTest != nullptr) { 384 proxyTest->ClearResource(); 385 } 386 OH_LOG_INFO(LOG_APP, "the stub is dead!"); 387} 388``` 389#### Server Invocation Entry in libipcCapiDemo.so 390 391```C++ 392IpcCApiStubTest g_ipcStubObj; 393 394#ifdef __cplusplus 395extern "C" { 396 397// The following functions need to be implemented for the server. For details, see the Ability APIs. 398OHIPCRemoteStub* NativeChildProcess_OnConnect() { 399 OH_LOG_INFO(LOG_APP, "NativeChildProcess_OnConnect"); 400 return g_ipcStubObj.GetRemoteStub(); 401} 402 403void NativeChildProcess_MainProc() { 404 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc"); 405 g_ipcStubObj.MainProc(); 406 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc End"); 407} 408 409} 410#endif 411``` 412 413#### Client Invocation Entry 414 415```c++ 416IpcCApiProxyTest *g_ipcProxy = nullptr; 417 418// Callback to be invoked when the IPC channel is set up via the ability. 419void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) { 420 OH_LOG_INFO(LOG_APP, "OnNativeChildProcessStarted proxy=%{public}p err=%{public}d", remoteProxy, errCode); 421 if (remoteProxy == nullptr) { 422 return; 423 } 424 g_ipcProxy = new (std::nothrow) IpcCApiProxyTest(remoteProxy); 425 if (g_ipcProxy == nullptr) { 426 OH_IPCRemoteProxy_Destroy(remoteProxy); 427 OH_LOG_ERROR(LOG_APP, "Alloc IpcCApiProxyTest object failed"); 428 return; 429 } 430} 431 432int main(int argc, char *argv[]) { 433 int32_t ret = OH_Ability_CreateNativeChildProcess("libipcCapiDemo.so", OnNativeChildProcessStarted); 434 if (ret != 0) { 435 return -1; 436 } 437 if (g_ipcProxy == nullptr) { 438 return -1; 439 } 440 int a = 2; 441 int b = 3; 442 int result = 0; 443 ret = g_ipcProxy->AsyncAdd(a, b, result); 444 OH_LOG_INFO(LOG_APP, "AsyncAdd: %d + %d = %d, ret=%d", a, b, result, ret); 445 446 // kill the stub. 447 ret = g_ipcProxy->RequestExitChildProcess(); 448 // Output on the console: the stub is dead! 449 if (g_ipcProxy != nullptr) { 450 delete g_ipcProxy; 451 g_ipcProxy = nullptr; 452 } 453 return 0; 454} 455``` 456<!--no_check-->