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 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