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![](./figures/_i_p_c_architecture_diagram.png)
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