1# IPC and RPC Development (C/C++) 2<!--Kit: IPC Kit--> 3<!--Subsystem: Communication--> 4<!--Owner: @xdx19211@luodonghui0157--> 5<!--SE: @zhaopeng_gitee--> 6<!--TSE: @maxiaorong2--> 7 8 9## When to Use 10 11 12Inter-process communication (IPC) allows the proxy and stub running in different processes to communicate with each other using C/C++ APIs. 13The IPC C APIs do not provide the capability of obtaining the communication proxy object. This feature depends on [Ability Kit](../application-models/abilitykit-overview.md). 14 15 16 17For details about how to establish IPC channels between processes, see [Native Child Process Development (C/C++)](../application-models/capi_nativechildprocess_development_guideline.md). This document describes how to use the IPC C APIs. 18 19## Available APIs 20 21**Table 1** Key APIs 22 23| API | Description | 24| ------------------------------------ | ---------------------------------------------------------------- | 25|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.| 26| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | Creates an **OHIPCRemoteStub** object.| 27|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.| 28|struct OHIPCRemoteProxy;|Defines an **OHIPCRemoteProxy** object, which is used to send requests to the peer end. The **OHIPCRemoteProxy** object is returned by an ability API.| 29|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|Creates an **OHIPCRemoteStub** object, which triggers a notification when the **OHIPCDeathRecipient** object dies unexpectedly.| 30|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|Subscribes to the death of an **OHIPCRemoteStub** object for an **OHIPCRemoteProxy** object.| 31 32For details about the APIs, see [IPC Kit](../reference/apis-ipc-kit/capi-ipckit.md). 33 34 35## How to Develop 36 37Create a stub object on the server, obtain the proxy object of the client through ability APIs, and use the proxy object to communicate with the stub object on the server through IPC. Then, register the death notification callback of the remote object to detect the death status of the process hosting the remote stub object. 38 39### Adding Dynamic Link Libraries 40 41Add the following libraries to **CMakeLists.txt**. 42 43```txt 44# ipc capi 45libipc_capi.so 46# Ability C/C++ APIs 47libchild_process.so 48``` 49 50### Adding Header Files 51 52```c++ 53// IPC C/C++ APIs 54#include <IPCKit/ipc_kit.h> 55// Ability C/C++ APIs 56#include <AbilityKit/native_child_process.h> 57``` 58 59### Implementing IPC 60#### Common Data and Functions 61 62```c++ 63#include <string> 64#include <thread> 65#include <mutex> 66#include <chrono> 67#include <condition_variable> 68#include <IPCKit/ipc_kit.h> 69#include <AbilityKit/native_child_process.h> 70#include <hilog/log.h> 71#undef LOG_DOMAIN 72#undef LOG_TAG 73#define LOG_DOMAIN 0x0201 74#define LOG_TAG "IPCCApiSample" 75 76enum RequestCode { 77 ASYNC_ADD_CODE = 1, 78 REQUEST_EXIT_CODE = 2, 79 OTHER_CODE 80}; 81static constexpr int MAX_MEMORY_SIZE = 204800; 82static const std::string INTERFACE_DESCRIPTOR = "INTERFACE_DESCRIPTOR"; 83static const std::string NATIVE_REMOTE_STUB_TEST_TOKEN = "native.remote.stub"; 84static const std::string NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN = "native.remote.stub.async.call"; 85 86// Define the memory allocation function. 87static void* LocalMemoryAllocator(int32_t len) { 88 if (len < 0 || len > MAX_MEMORY_SIZE ) { 89 return nullptr; 90 } 91 void *buffer = malloc(len); 92 if (buffer == nullptr) { 93 return nullptr; 94 } 95 memset(buffer, 0, len); 96 return buffer; 97} 98``` 99#### Server Object 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 // Create a stub object. 120 stub_ = OH_IPCRemoteStub_Create(INTERFACE_DESCRIPTOR.c_str(), &IpcCApiStubTest::OnRemoteRequest, 121 nullptr, this); 122} 123 124IpcCApiStubTest::~IpcCApiStubTest() { 125 if (stub_ != nullptr) { 126 // Destroy the stub object when it is no longer used. 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// Request processing function of the server. Requests sent by the client are processed in this function. 141int IpcCApiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData) { 142 int readLen = 0; 143 char *token = nullptr; 144 // Verify the current communication based on interfaceToken sent by the client. 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 // Obtain the proxy object for 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 // Define asynchronous thread processing and use proxyCallBack to respond to asynchronous results. To implement synchronous calls, use replyData to write the response result. 187 std::thread th([proxyCallBack, a, b] { 188 auto data = OH_IPCParcel_Create(); 189 if (data == nullptr) { 190 // If the parcel fails to be created, destroy the obtained proxyCallBack object. 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 // The asynchronous thread processing result is returned to the service requester in IPC synchronous calls. 207 OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 }; 208 OH_LOG_INFO(LOG_APP, "thread start sendCallBack!"); 209 // Send an IPC request. 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#### Client Proxy Object IpcCApiProxyTest 234 235```cpp 236// Customize error codes. 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 // Note: OnRemoteRequest is the callback function used by the stub object to process IPC requests. This function does not need to be implemented on the proxy side. 251 // OnRemoteRequest is the callback function used by the asynchronous callback object (replyStub_) to process IPC requests. 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, "crete reply stub failed!"); 274 return; 275 } 276 // Create a death callback object. 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 // Register the death callback object with the proxy to detect the death status of the stub object on the server. 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 // Write the interface token for verification. 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 // Use replyStub_ to receive responses in asynchronous transmission. In asynchronous processing, the OHIPCRemoteStub object for receiving the result needs to be written. 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#### libipcCapiDemo.so for Server Calls 406 407```C++ 408IpcCApiStubTest g_ipcStubObj; 409 410#ifdef __cplusplus 411extern "C" { 412 413// The following functions need to be implemented for the server. For details, see the Ability APIs. 414OHIPCRemoteStub* NativeChildProcess_OnConnect() { 415 OH_LOG_INFO(LOG_APP, "NativeChildProcess_OnConnect"); 416 return g_ipcStubObj.GetRemoteStub(); 417} 418 419void NativeChildProcess_MainProc() { 420 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc"); 421 g_ipcStubObj.MainProc(); 422 OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc End"); 423} 424 425} 426#endif 427``` 428 429#### Client Invocation Entry 430 431```c++ 432IpcCApiProxyTest *g_ipcProxy = nullptr; 433 434// Callback to be invoked when the IPC channel is set up via the ability. 435void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) { 436 OH_LOG_INFO(LOG_APP, "OnNativeChildProcessStarted proxy=%{public}p err=%{public}d", remoteProxy, errCode); 437 if (remoteProxy == nullptr) { 438 return; 439 } 440 g_ipcProxy = new (std::nothrow) IpcCApiProxyTest(remoteProxy); 441 if (g_ipcProxy == nullptr) { 442 OH_IPCRemoteProxy_Destroy(remoteProxy); 443 OH_LOG_ERROR(LOG_APP, "Alloc IpcCApiProxyTest object failed"); 444 return; 445 } 446} 447 448int main(int argc, char *argv[]) { 449 // Call the ability API to create a child process and load the libipcCapiDemo.so file specified in the parameter. The process startup result is asynchronously notified through the callback parameter OnNativeChildProcessStarted. The proxy object is obtained from the callback function. 450 int32_t ret = OH_Ability_CreateNativeChildProcess("libipcCapiDemo.so", OnNativeChildProcessStarted); 451 if (ret != 0) { 452 return -1; 453 } 454 if (g_ipcProxy == nullptr) { 455 return -1; 456 } 457 int a = 2; 458 int b = 3; 459 int result = 0; 460 ret = g_ipcProxy->AsyncAdd(a, b, result); 461 OH_LOG_INFO(LOG_APP, "AsyncAdd: %d + %d = %d, ret=%d", a, b, result, ret); 462 463 // Trigger the stub process to exit. 464 ret = g_ipcProxy->RequestExitChildProcess(); 465 // The death notification callback function (IpcCApiProxyTest::OnDeathRecipientCB) is automatically executed. 466 if (g_ipcProxy != nullptr) { 467 delete g_ipcProxy; 468 g_ipcProxy = nullptr; 469 } 470 return 0; 471} 472``` 473