• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![](./figures/_i_p_c_architecture_diagram.png)
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-->