• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# IPC与RPC通信开发指导(C/C++)
2
3
4## 场景介绍
5
6
7IPC让运行在不同进程间的Proxy和Stub实现互相通信。IPC CAPI是IPC Kit提供的C语言接口。
8IPC CAPI接口不直接提供获取通信代理对象的能力,该功能由[Ability Kit](../application-models/abilitykit-overview.md)提供。
9
10![图](./figures/_i_p_c_architecture_diagram.png)
11
12进程间IPC通道的建立,请参考[Native子进程开发指导(C/C++)](../application-models/capi_nativechildprocess_development_guideline.md)。本文重点介绍IPC CAPI的使用。
13
14## 接口说明
15
16**表1** IPC CAPI侧关键接口
17
18| 接口名                               | 描述                                                             |
19| ------------------------------------ | ---------------------------------------------------------------- |
20|typedef int (\*OH_OnRemoteRequestCallback)<br>(uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> void \*userData);|Stub端用于处理远端数据请求的回调函数。|
21| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | 创建OHIPCRemoteStub对象。 |
22|int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy \*proxy,<br> uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> const OH_IPC_MessageOption \*option);|IPC消息发送函数。|
23|struct OHIPCRemoteProxy;|用于向远端发送请求的OHIPCRemoteProxy对象,需要依赖元能力接口返回。|
24|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|创建用于监听远端OHIPCRemoteStub对象死亡的通知对象(OHIPCDeathRecipient对象)。|
25|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|向OHIPCRemoteProxy对象注册死亡监听,用于接收远端OHIPCRemoteStub对象死亡时的回调通知。|
26
27详细的接口说明请参考[IPCKit](../reference/apis-ipc-kit/_i_p_c_kit.md)。
28
29
30## 开发步骤
31
32先创建服务端Stub对象,通过元能力获取其客户端代理Proxy对象,然后用Proxy对象与服务端Stub对象进行IPC通信,同时再注册远端对象的死亡通知回调,用于Proxy侧感知服务端Stub对象所在进程的死亡状态。
33
34### 添加动态链接库
35
36CMakeLists.txt中添加以下lib。
37
38```txt
39# ipc capi
40libipc_capi.so
41# 元能力,ability capi
42libchild_process.so
43```
44
45### 头文件
46
47```c++
48// ipc capi
49#include <IPCKit/ipc_kit.h>
50// 元能力,ability capi
51#include <AbilityKit/native_child_process.h>
52```
53
54### 异步调用场景
55#### 公共数据及函数定义
56
57```c++
58#include <string>
59#include <thread>
60#include <mutex>
61#include <chrono>
62#include <condition_variable>
63#include <IPCKit/ipc_kit.h>
64#include <AbilityKit/native_child_process.h>
65#include <hilog/log.h>
66#undef LOG_DOMAIN
67#undef LOG_TAG
68#define LOG_DOMAIN 0x0201
69#define LOG_TAG "IPCCApiSample"
70
71enum RequestCode {
72    ASYNC_ADD_CODE = 1,
73    REQUEST_EXIT_CODE = 2,
74    OTHER_CODE
75};
76static constexpr int MAX_MEMORY_SIZE = 204800;
77static const std::string INTERFACE_DESCRIPTOR = "INTERFACE_DESCRIPTOR";
78static const std::string NATIVE_REMOTE_STUB_TEST_TOKEN = "native.remote.stub";
79static const std::string NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN = "native.remote.stub.async.call";
80
81// 定义内存分配函数
82static void* LocalMemoryAllocator(int32_t len) {
83    if (len < 0 || len > MAX_MEMORY_SIZE ) {
84        return nullptr;
85    }
86    void *buffer = malloc(len);
87    if (buffer == nullptr) {
88        return nullptr;
89    }
90    memset(buffer, 0, len);
91    return buffer;
92}
93```
94#### 服务端对象: IpcCApiStubTest
95
96```c++
97class IpcCApiStubTest {
98public:
99    explicit IpcCApiStubTest();
100    ~IpcCApiStubTest();
101    void MainProc();
102    OHIPCRemoteStub* GetRemoteStub();
103    static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData);
104private:
105    int AsyncAdd(const OHIPCParcel *data);
106    int RequestExitChildProcess();
107private:
108    OHIPCRemoteStub *stub_{ nullptr };
109    std::mutex childMutex_;
110    std::condition_variable childCondVar_;
111};
112
113IpcCApiStubTest::IpcCApiStubTest() {
114    // 创建stub对象
115    stub_ = OH_IPCRemoteStub_Create(INTERFACE_DESCRIPTOR.c_str(), &IpcCApiStubTest::OnRemoteRequest,
116        nullptr, this);
117}
118
119IpcCApiStubTest::~IpcCApiStubTest() {
120    if (stub_ != nullptr) {
121        // 当stub对象不再使用时,销毁该对象
122        OH_IPCRemoteStub_Destroy(stub_);
123    }
124}
125
126void IpcCApiStubTest::MainProc() {
127    std::unique_lock<std::mutex> autoLock(childMutex_);
128    childCondVar_.wait(autoLock);
129}
130
131OHIPCRemoteStub* IpcCApiStubTest::GetRemoteStub() {
132    return stub_;
133}
134
135// 服务端的请求处理函数,客户端发送的请求在该函数中处理
136int IpcCApiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData) {
137    int readLen = 0;
138    char *token = nullptr;
139    // 根据客户端传过来的interfaceToken校验当前通信是否合法
140    if (OH_IPCParcel_ReadInterfaceToken(data, &token, &readLen, LocalMemoryAllocator) != OH_IPC_SUCCESS
141        || NATIVE_REMOTE_STUB_TEST_TOKEN != token) {
142        if (token != nullptr) {
143            OH_LOG_ERROR(LOG_APP, "check InterfaceToken failed");
144            free(token);
145        }
146        return OH_IPC_PARCEL_WRITE_ERROR;
147    }
148    free(token);
149    auto *stubTest = reinterpret_cast<IpcCApiStubTest *>(userData);
150    if (stubTest == nullptr) {
151        return OH_IPC_CHECK_PARAM_ERROR;
152    }
153    auto rqCode = RequestCode(code);
154    switch (rqCode) {
155        case ASYNC_ADD_CODE: {
156            return stubTest->AsyncAdd(data);
157        }
158        case REQUEST_EXIT_CODE: {
159            return stubTest->RequestExitChildProcess();
160        }
161        default:
162            break;
163    }
164    return OH_IPC_SUCCESS;
165}
166
167int IpcCApiStubTest::AsyncAdd(const OHIPCParcel *data) {
168    int a = 0;
169    int b = 0;
170    OH_LOG_INFO(LOG_APP, "start async add a=%d,b=%d", a, b);
171    if ((OH_IPCParcel_ReadInt32(data, &a) != OH_IPC_SUCCESS)
172        || (OH_IPCParcel_ReadInt32(data, &b) != OH_IPC_SUCCESS)) {
173        return OH_IPC_PARCEL_READ_ERROR;
174    }
175    // 此处获取proxy对象,用于后续的IPC通信调用
176    auto proxyCallBack = OH_IPCParcel_ReadRemoteProxy(data);
177    if (proxyCallBack == nullptr) {
178        return OH_IPC_PARCEL_READ_ERROR;
179    }
180    OH_LOG_INFO(LOG_APP, "start create sendCallBack thread!");
181    // 此处开启线程异步完成功能实现并利用proxyCallBack完成结果响应,如果同步调用,则直接通过replyData写入响应结果即可
182    std::thread th([proxyCallBack, a, b] {
183        auto data = OH_IPCParcel_Create();
184        if (data == nullptr) {
185            // 当创建parcel失败,则销毁获取到的proxyCallBack对象
186            OH_IPCRemoteProxy_Destroy(proxyCallBack);
187            return;
188        }
189        auto reply = OH_IPCParcel_Create();
190        if (reply == nullptr) {
191            OH_IPCParcel_Destroy(data);
192            OH_IPCRemoteProxy_Destroy(proxyCallBack);
193            return;
194        }
195        if (OH_IPCParcel_WriteInt32(data, a + b) != OH_IPC_SUCCESS) {
196            OH_IPCParcel_Destroy(data);
197            OH_IPCParcel_Destroy(reply);
198            OH_IPCRemoteProxy_Destroy(proxyCallBack);
199            return;
200        }
201        // 异步线程处理结果通过IPC同步调用方式返回给业务请求方
202        OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 };
203        OH_LOG_INFO(LOG_APP, "thread start sendCallBack!");
204        // 发送IPC通信请求
205        int ret = OH_IPCRemoteProxy_SendRequest(proxyCallBack, ASYNC_ADD_CODE, data, reply, &option);
206        OH_LOG_INFO(LOG_APP, "thread sendCallBack ret = %d", ret);
207        if (ret != OH_IPC_SUCCESS) {
208            OH_IPCParcel_Destroy(data);
209            OH_IPCParcel_Destroy(reply);
210            OH_IPCRemoteProxy_Destroy(proxyCallBack);
211            return;
212        }
213        OH_IPCRemoteProxy_Destroy(proxyCallBack);
214        OH_IPCParcel_Destroy(data);
215        OH_IPCParcel_Destroy(reply);
216    });
217    th.detach();
218    return OH_IPC_SUCCESS;
219}
220
221int IpcCApiStubTest::RequestExitChildProcess() {
222    std::unique_lock<std::mutex> autoLock(childMutex_);
223    childCondVar_.notify_all();
224    return OH_IPC_SUCCESS;
225}
226```
227
228#### 客户端代理对象: IpcCApiProxyTest
229
230```cpp
231// 用戶自定义错误码
232static constexpr int OH_IPC_CREATE_OBJECT_ERROR = OH_IPC_USER_ERROR_CODE_MIN + 1;
233
234class IpcCApiProxyTest {
235public:
236    explicit IpcCApiProxyTest(OHIPCRemoteProxy *proxy);
237    ~IpcCApiProxyTest();
238public:
239    int AsyncAdd(int a, int b, int &result);
240    int RequestExitChildProcess();
241    void ClearResource();
242private:
243    void SendAsyncReply(int &replyValue);
244    int WaitForAsyncReply(int timeOut);
245    // 注意:OnRemoteRequest方法是Stub对象需要实现的处理IPC请求消息的回调函数,Proxy侧不需要实现该函数
246    // 此处的OnRemoteRequest是用来给异步回调对象(下文中的replyStub_)配套使用的处理IPC请求消息的回调函数
247    static int OnRemoteRequest(uint32_t code, const OHIPCParcel *data,
248        OHIPCParcel *reply, void *userData);
249    static void OnDeathRecipientCB(void *userData);
250private:
251    int asyncReply_{};
252    std::mutex mutex_;
253    std::condition_variable cv_;
254    OHIPCRemoteProxy *proxy_{ nullptr };
255    OHIPCRemoteStub *replyStub_{ nullptr };
256    OHIPCDeathRecipient *deathRecipient_{ nullptr };
257};
258
259IpcCApiProxyTest::IpcCApiProxyTest(OHIPCRemoteProxy *proxy) {
260    if (proxy == nullptr) {
261        OH_LOG_ERROR(LOG_APP, "proxy is nullptr");
262        return;
263    }
264    proxy_ = proxy;
265    replyStub_ = OH_IPCRemoteStub_Create(NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN.c_str(), OnRemoteRequest,
266        nullptr, this);
267    if (replyStub_ == nullptr) {
268        OH_LOG_ERROR(LOG_APP, "crete reply stub failed!");
269        return;
270    }
271    // 创建死亡回调对象
272    deathRecipient_ = OH_IPCDeathRecipient_Create(OnDeathRecipientCB, nullptr, this);
273    if (deathRecipient_ == nullptr) {
274        OH_LOG_ERROR(LOG_APP, "OH_IPCDeathRecipient_Create failed!");
275        return;
276    }
277    // 向Proxy注册死亡回调对象,用于感知服务端Stub对象的死亡状态
278    OH_IPCRemoteProxy_AddDeathRecipient(proxy_, deathRecipient_);
279}
280
281IpcCApiProxyTest::~IpcCApiProxyTest() {
282    if (proxy_ != nullptr) {
283        OH_IPCRemoteProxy_Destroy(proxy_);
284    }
285    if (deathRecipient_ != nullptr) {
286        OH_IPCDeathRecipient_Destroy(deathRecipient_);
287    }
288    if (replyStub_ != nullptr) {
289        OH_IPCRemoteStub_Destroy(replyStub_);
290    }
291}
292
293int IpcCApiProxyTest::AsyncAdd(int a, int b, int &result) {
294    OH_LOG_INFO(LOG_APP, "start %d + %d", a, b);
295    auto data = OH_IPCParcel_Create();
296    if (data == nullptr) {
297        return OH_IPC_CREATE_OBJECT_ERROR;
298    }
299    // 写入接口校验token
300    if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) {
301        OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!");
302        OH_IPCParcel_Destroy(data);
303        return OH_IPC_PARCEL_WRITE_ERROR;
304    }
305    if (OH_IPCParcel_WriteInt32(data, a) != OH_IPC_SUCCESS
306        || OH_IPCParcel_WriteInt32(data, b) != OH_IPC_SUCCESS
307        || OH_IPCParcel_WriteRemoteStub(data, replyStub_) != OH_IPC_SUCCESS) {
308        OH_IPCParcel_Destroy(data);
309        return OH_IPC_PARCEL_WRITE_ERROR;
310    }
311    // 异步发送使用replyStub_进行响应结果接收,异步处理需要写入用于接收结果的OHIPCRemoteStub对象
312    OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_ASYNC, 0 };
313    int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::ASYNC_ADD_CODE, data, nullptr, &option);
314    if (ret != OH_IPC_SUCCESS) {
315        OH_IPCParcel_Destroy(data);
316        OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!");
317        return ret;
318    }
319    static constexpr int TIMEOUT = 3;
320    WaitForAsyncReply(TIMEOUT);
321    OH_LOG_INFO(LOG_APP, "asyncReply_:%d", asyncReply_);
322    result = asyncReply_;
323    OH_IPCParcel_Destroy(data);
324    return OH_IPC_SUCCESS;
325}
326
327int IpcCApiProxyTest::RequestExitChildProcess() {
328    auto data = OH_IPCParcel_Create();
329    if (data == nullptr) {
330        return OH_IPC_CREATE_OBJECT_ERROR;
331    }
332    auto reply = OH_IPCParcel_Create();
333    if (reply == nullptr) {
334        OH_IPCParcel_Destroy(data);
335        return OH_IPC_CREATE_OBJECT_ERROR;
336    }
337    if (OH_IPCParcel_WriteInterfaceToken(data, NATIVE_REMOTE_STUB_TEST_TOKEN.c_str()) != OH_IPC_SUCCESS) {
338        OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_WriteInterfaceToken failed!");
339        OH_IPCParcel_Destroy(data);
340        OH_IPCParcel_Destroy(reply);
341        return OH_IPC_PARCEL_WRITE_ERROR;
342    }
343    OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 };
344    int ret = OH_IPCRemoteProxy_SendRequest(proxy_, RequestCode::REQUEST_EXIT_CODE, data, reply, &option);
345    if (ret != OH_IPC_SUCCESS) {
346        OH_IPCParcel_Destroy(data);
347        OH_IPCParcel_Destroy(reply);
348        OH_LOG_ERROR(LOG_APP, "OH_IPCRemoteProxy_SendRequest failed!");
349        return ret;
350    }
351    OH_IPCParcel_Destroy(data);
352    OH_IPCParcel_Destroy(reply);
353    return OH_IPC_SUCCESS;
354}
355
356void IpcCApiProxyTest::SendAsyncReply(int &replyValue) {
357    std::unique_lock<std::mutex> lck(mutex_);
358    asyncReply_ = replyValue;
359    cv_.notify_all();
360}
361
362int IpcCApiProxyTest::WaitForAsyncReply(int timeOut) {
363    asyncReply_ = 0;
364    std::unique_lock<std::mutex> lck(mutex_);
365    cv_.wait_for(lck, std::chrono::seconds(timeOut), [&] {
366        return asyncReply_ != 0;
367    });
368    return asyncReply_;
369}
370
371int IpcCApiProxyTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data,
372        OHIPCParcel *reply, void *userData) {
373    OH_LOG_INFO(LOG_APP, "start %u", code);
374    auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData);
375    if (proxyTest == nullptr || code != static_cast<uint32_t>(RequestCode::ASYNC_ADD_CODE)) {
376        OH_LOG_ERROR(LOG_APP, "check param failed!");
377        return OH_IPC_CHECK_PARAM_ERROR;
378    }
379    int32_t val = -1;
380    if (OH_IPCParcel_ReadInt32(data, &val) != OH_IPC_SUCCESS) {
381        OH_LOG_ERROR(LOG_APP, "OH_IPCParcel_ReadInt32 failed!");
382        return OH_IPC_PARCEL_READ_ERROR;
383    }
384    proxyTest->SendAsyncReply(val);
385    return OH_IPC_SUCCESS;
386}
387
388void IpcCApiProxyTest::ClearResource() {
389    // clear resource;
390}
391
392void IpcCApiProxyTest::OnDeathRecipientCB(void *userData) {
393    auto *proxyTest = reinterpret_cast<IpcCApiProxyTest *>(userData);
394    if (proxyTest != nullptr) {
395        proxyTest->ClearResource();
396    }
397    OH_LOG_INFO(LOG_APP, "the stub is dead!");
398}
399```
400#### 服务端调用入口,服务端文件"libipcCapiDemo.so"
401
402```C++
403IpcCApiStubTest g_ipcStubObj;
404
405#ifdef __cplusplus
406extern "C" {
407
408// 服务需要实现如下函数,具体可参考元能力接口说明
409OHIPCRemoteStub* NativeChildProcess_OnConnect() {
410    OH_LOG_INFO(LOG_APP, "NativeChildProcess_OnConnect");
411    return g_ipcStubObj.GetRemoteStub();
412}
413
414void NativeChildProcess_MainProc() {
415    OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc");
416    g_ipcStubObj.MainProc();
417    OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc End");
418}
419
420}
421#endif
422```
423
424#### 客户端调用入口
425
426```c++
427IpcCApiProxyTest *g_ipcProxy = nullptr;
428
429// 元能力打通IPC通道回调接口
430void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) {
431    OH_LOG_INFO(LOG_APP, "OnNativeChildProcessStarted proxy=%{public}p err=%{public}d", remoteProxy, errCode);
432    if (remoteProxy == nullptr) {
433        return;
434    }
435    g_ipcProxy = new (std::nothrow) IpcCApiProxyTest(remoteProxy);
436    if (g_ipcProxy == nullptr) {
437        OH_IPCRemoteProxy_Destroy(remoteProxy);
438        OH_LOG_ERROR(LOG_APP, "Alloc IpcCApiProxyTest object failed");
439        return;
440    }
441}
442
443int main(int argc, char *argv[]) {
444    // 调用元能力接口,创建子进程,并加载参数中指定的libipcCapiDemo.so文件,进程启动结果通过回调参数OnNativeChildProcessStarted异步通知,在该回调函数中获取Proxy对象
445    int32_t ret = OH_Ability_CreateNativeChildProcess("libipcCapiDemo.so", OnNativeChildProcessStarted);
446    if (ret != 0) {
447        return -1;
448    }
449    if (g_ipcProxy == nullptr) {
450        return -1;
451    }
452    int a = 2;
453    int b = 3;
454    int result = 0;
455    ret = g_ipcProxy->AsyncAdd(a, b, result);
456    OH_LOG_INFO(LOG_APP, "AsyncAdd: %d + %d = %d, ret=%d", a, b, result, ret);
457
458    // 触发Stub侧进程退出
459    ret = g_ipcProxy->RequestExitChildProcess();
460    // 此时,死亡通知回调函数(IpcCApiProxyTest::OnDeathRecipientCB)会被自动执行
461    if (g_ipcProxy != nullptr) {
462        delete g_ipcProxy;
463        g_ipcProxy = nullptr;
464    }
465    return 0;
466}
467```
468
469