• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# IPC与RPC通信开发指导(C/C++)
2<!--Kit: IPC Kit-->
3<!--Subsystem: Communication-->
4<!--Owner: @xdx19211@luodonghui0157-->
5<!--Designer: @zhaopeng_gitee-->
6<!--Tester: @maxiaorong-->
7<!--Adviser: @zhang_yixin13-->
8
9## 场景介绍
10
11IPC让运行在不同进程间的Proxy和Stub实现互相通信。IPC CAPI是IPC Kit提供的C语言接口。
12IPC CAPI接口不直接提供获取通信代理对象的能力,该功能由[Ability Kit](../application-models/abilitykit-overview.md)提供。
13
14![图](./figures/_i_p_c_architecture_diagram.png)
15
16进程间IPC通道的建立,请参考[Native子进程开发指导(C/C++)](../application-models/capi_nativechildprocess_development_guideline.md)。本文重点介绍IPC CAPI的使用。
17
18## 接口说明
19
20**表1** IPC CAPI侧关键接口
21
22| 接口名                               | 描述                                                             |
23| ------------------------------------ | ---------------------------------------------------------------- |
24|typedef int (\*OH_OnRemoteRequestCallback)<br>(uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> void \*userData);|Stub端用于处理远端数据请求的回调函数。|
25| OHIPCRemoteStub\* OH_IPCRemoteStub_Create<br>(const char \*descriptor, OH_OnRemoteRequestCallback requestCallback,<br>OH_OnRemoteDestroyCallback destroyCallback, void \*userData); | 创建OHIPCRemoteStub对象。 |
26|int OH_IPCRemoteProxy_SendRequest(const OHIPCRemoteProxy \*proxy,<br> uint32_t code, const OHIPCParcel \*data, OHIPCParcel \*reply,<br> const OH_IPC_MessageOption \*option);|IPC消息发送函数。|
27|struct OHIPCRemoteProxy;|用于向远端发送请求的OHIPCRemoteProxy对象,需要依赖元能力接口返回。|
28|OHIPCDeathRecipient\* OH_IPCDeathRecipient_Create<br>(OH_OnDeathRecipientCallback deathRecipientCallback,<br> OH_OnDeathRecipientDestroyCallback destroyCallback,<br>void \*userData);|创建用于监听远端OHIPCRemoteStub对象死亡的通知对象(OHIPCDeathRecipient对象)。|
29|int OH_IPCRemoteProxy_AddDeathRecipient(OHIPCRemoteProxy \*proxy,<br>OHIPCDeathRecipient \*recipient);|向OHIPCRemoteProxy对象注册死亡监听,用于接收远端OHIPCRemoteStub对象死亡时的回调通知。|
30
31详细的接口说明请参考[IPCKit](../reference/apis-ipc-kit/capi-ipckit.md)。
32
33## 开发步骤
34
35先创建服务端Stub对象,通过元能力获取其客户端代理Proxy对象,然后用Proxy对象与服务端Stub对象进行IPC通信,同时再注册远端对象的死亡通知回调,用于Proxy侧感知服务端Stub对象所在进程的死亡状态。
36
37### 添加动态链接库
38
39CMakeLists.txt中添加以下lib。
40
41```txt
42# ipc capi
43libipc_capi.so
44# 元能力,ability capi
45libchild_process.so
46```
47
48### 头文件
49
50```c++
51// ipc capi
52#include <IPCKit/ipc_kit.h>
53// 元能力,ability capi。
54#include <AbilityKit/native_child_process.h>
55```
56
57### 异步调用场景
58
59**公共数据及函数定义**
60
61```c++
62#include <string>
63#include <thread>
64#include <mutex>
65#include <chrono>
66#include <condition_variable>
67#include <IPCKit/ipc_kit.h>
68#include <AbilityKit/native_child_process.h>
69#include <hilog/log.h>
70#undef LOG_DOMAIN
71#undef LOG_TAG
72#define LOG_DOMAIN 0x0201
73#define LOG_TAG "IPCCApiSample"
74
75enum RequestCode {
76    ASYNC_ADD_CODE = 1,
77    REQUEST_EXIT_CODE = 2,
78    OTHER_CODE
79};
80static constexpr int MAX_MEMORY_SIZE = 204800;
81static const std::string INTERFACE_DESCRIPTOR = "INTERFACE_DESCRIPTOR";
82static const std::string NATIVE_REMOTE_STUB_TEST_TOKEN = "native.remote.stub";
83static const std::string NATIVE_REMOTE_STUB_ASYNC_CALL_TEST_TOKEN = "native.remote.stub.async.call";
84
85// 定义内存分配函数。
86static void* LocalMemoryAllocator(int32_t len) {
87    if (len < 0 || len > MAX_MEMORY_SIZE ) {
88        return nullptr;
89    }
90    void *buffer = malloc(len);
91    if (buffer == nullptr) {
92        return nullptr;
93    }
94    memset(buffer, 0, len);
95    return buffer;
96}
97```
98
99**服务端对象: 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    // 创建stub对象。
120    stub_ = OH_IPCRemoteStub_Create(INTERFACE_DESCRIPTOR.c_str(), &IpcCApiStubTest::OnRemoteRequest,
121        nullptr, this);
122}
123
124IpcCApiStubTest::~IpcCApiStubTest() {
125    if (stub_ != nullptr) {
126        // 当stub对象不再使用时,销毁该对象。
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// 服务端的请求处理函数,客户端发送的请求在该函数中处理。
141int IpcCApiStubTest::OnRemoteRequest(uint32_t code, const OHIPCParcel *data, OHIPCParcel *reply, void *userData) {
142    int readLen = 0;
143    char *token = nullptr;
144    // 根据客户端传过来的interfaceToken校验当前通信是否合法。
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    // 此处获取proxy对象,用于后续的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    // 此处开启线程异步完成功能实现并利用proxyCallBack完成结果响应,如果同步调用,则直接通过replyData写入响应结果即可。
187    std::thread th([proxyCallBack, a, b] {
188        auto data = OH_IPCParcel_Create();
189        if (data == nullptr) {
190            // 当创建parcel失败,则销毁获取到的proxyCallBack对象。
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        // 异步线程处理结果通过IPC同步调用方式返回给业务请求方。
207        OH_IPC_MessageOption option = { OH_IPC_REQUEST_MODE_SYNC, 0 };
208        OH_LOG_INFO(LOG_APP, "thread start sendCallBack!");
209        // 发送IPC通信请求。
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**客户端代理对象: IpcCApiProxyTest**
234
235```cpp
236// 用户自定义错误码。
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    // 注意:OnRemoteRequest方法是Stub对象需要实现的处理IPC请求消息的回调函数,Proxy侧不需要实现该函数。
251    // 此处的OnRemoteRequest是用来给异步回调对象(下文中的replyStub_)配套使用的处理IPC请求消息的回调函数。
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, "create reply stub failed!");
274        return;
275    }
276    // 创建死亡回调对象。
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    // 向Proxy注册死亡回调对象,用于感知服务端Stub对象的死亡状态。
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    // 写入接口校验token。
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    // 异步发送使用replyStub_进行响应结果接收,异步处理需要写入用于接收结果的OHIPCRemoteStub对象。
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
406**服务端调用入口,服务端文件"libipcCapiDemo.so"**
407
408```C++
409IpcCApiStubTest g_ipcStubObj;
410
411#ifdef __cplusplus
412extern "C" {
413
414// 服务需要实现如下函数,具体可参考元能力接口说明。
415OHIPCRemoteStub* NativeChildProcess_OnConnect() {
416    OH_LOG_INFO(LOG_APP, "NativeChildProcess_OnConnect");
417    return g_ipcStubObj.GetRemoteStub();
418}
419
420void NativeChildProcess_MainProc() {
421    OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc");
422    g_ipcStubObj.MainProc();
423    OH_LOG_INFO(LOG_APP, "NativeChildProcess_MainProc End");
424}
425
426}
427#endif
428```
429
430**客户端调用入口**
431
432```c++
433IpcCApiProxyTest *g_ipcProxy = nullptr;
434
435// 元能力打通IPC通道回调接口。
436void OnNativeChildProcessStarted(int errCode, OHIPCRemoteProxy *remoteProxy) {
437    OH_LOG_INFO(LOG_APP, "OnNativeChildProcessStarted proxy=%{public}p err=%{public}d", remoteProxy, errCode);
438    if (remoteProxy == nullptr) {
439        return;
440    }
441    g_ipcProxy = new (std::nothrow) IpcCApiProxyTest(remoteProxy);
442    if (g_ipcProxy == nullptr) {
443        OH_IPCRemoteProxy_Destroy(remoteProxy);
444        OH_LOG_ERROR(LOG_APP, "Alloc IpcCApiProxyTest object failed");
445        return;
446    }
447}
448
449int main(int argc, char *argv[]) {
450    // 调用元能力接口,创建子进程,并加载参数中指定的libipcCapiDemo.so文件,进程启动结果通过回调参数OnNativeChildProcessStarted异步通知,在该回调函数中获取Proxy对象。
451    int32_t ret = OH_Ability_CreateNativeChildProcess("libipcCapiDemo.so", OnNativeChildProcessStarted);
452    if (ret != 0) {
453        return -1;
454    }
455    if (g_ipcProxy == nullptr) {
456        return -1;
457    }
458    int a = 2;
459    int b = 3;
460    int result = 0;
461    ret = g_ipcProxy->AsyncAdd(a, b, result);
462    OH_LOG_INFO(LOG_APP, "AsyncAdd: %d + %d = %d, ret=%d", a, b, result, ret);
463
464    // 触发Stub侧进程退出。
465    ret = g_ipcProxy->RequestExitChildProcess();
466    // 此时,死亡通知回调函数(IpcCApiProxyTest::OnDeathRecipientCB)会被自动执行。
467    if (g_ipcProxy != nullptr) {
468        delete g_ipcProxy;
469        g_ipcProxy = nullptr;
470    }
471    return 0;
472}
473```
474