1# IPC通信开发指导(C/C++)
2
3
4## 场景介绍
5
6IPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,而IPC CAPI是提供的C接口。
7IPC CAPI接口不直接提供跨进程通信能力,两个进程之间的IPC通道建立,依赖于[Ability Kit](../application-models/abilitykit-overview.md)。
8
9![图](./figures/_i_p_c_architecture_diagram.png)
10
11进程间IPC通道建立,详情参考[Native子进程开发指导(C/C++)](../application-models/capi_nativechildprocess_development_guideline.md),本文重点阐述IPC CAPI部分使用说明。
12
13## 接口说明
14
15**表1** CAPI侧IPC接口
16
17| 接口名                               | 描述                                                             |
18| ------------------------------------ | ---------------------------------------------------------------- |
19|typedef int (\*OH_OnRemoteRequestCallback)<br>(uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> void \*userData);|Stub端用于处理远端数据请求的回调函数。|
20| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | 创建OHIPCRemoteStub对象。 |
21|int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy \*proxy,<br> uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> const OH_IPC_MessageOption \*option);|IPC消息发送函数。|
22|struct OHIPCRemoteProxy;|OHIPCRemoteProxy对象,用于向远端发送请求。<br>需要依赖**元能力**接口返回。|
23|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|创建远端OHIPCRemoteStub对象死亡通知对象OHIPCDeathRecipient。|
24|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|向OHIPCRemoteProxy对象添加死亡监听,<br>用于接收远端OHIPCRemoteStub对象死亡的回调通知。|
25
26详细的接口说明请参考[IPCKit](../reference/apis-ipc-kit/_i_p_c_kit.md)。
27
28
29## 开发步骤
30
31以下步骤描述了如何使用[IPCKit](../reference/apis-ipc-kit/_i_p_c_kit.md)提供的CAPI接口,创建远端Stub和使用客户端代理Proxy进行通信,同时兼备远端死亡通知接收能力。
32
33### 1. 添加动态链接库
34
35CMakeLists.txt中添加以下lib。
36
37```txt
38# ipc capi
39libipc_capi.so
40# 元能力,ability capi
41libchild_process.so
42```
43
44### 2. 头文件
45
46```c++
47// ipc capi
48#include <IPCKit/ipc_kit.h>
49// 元能力,ability capi
50#include <AbilityKit/native_child_process.h>
51```
52
53### 3. 异步调用场景
54#### 3.1 公共数据及函数定义
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// 定义内存分配函数
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#### 3.2 服务端对象: 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    // 接口校验
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    // 此处开启线程异步完成功能实现并利用proxyCallBack完成结果响应,如果同步调用,则直接通过replyData写入响应结果即可
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        // 异步线程处理结果通过IPC同步调用方式返回给业务请求方
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#### 3.3 客户端代理对象: IpcCApiProxyTest
222
223```cpp
224// 用戶自定义错误码
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    // 写入接口校验token
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    // 异步发送使用replyStub_进行响应结果接收,异步处理需要写入用于接收结果的OHIPCRemoteStub对象
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#### 3.4 服务端调用入口,服务端文件"libipcCapiDemo.so"
391
392```C++
393IpcCApiStubTest g_ipcStubObj;
394
395#ifdef __cplusplus
396extern "C" {
397
398// 服务需要实现如下函数,具体可参考元能力接口说明
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#### 3.5 客户端调用入口
415
416```c++
417IpcCApiProxyTest *g_ipcProxy = nullptr;
418
419// 元能力打通IPC通道回调接口
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 stub端
448    ret = g_ipcProxy->RequestExitChildProcess();
449    //控制台输出: the stub is dead!
450    if (g_ipcProxy != nullptr) {
451        delete g_ipcProxy;
452        g_ipcProxy = nullptr;
453    }
454    return 0;
455}
456```
457
458