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