• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# IPC & RPC Development
2
3## When to Use
4
5IPC/RPC enables a proxy and a stub that run on different processes to communicate with each other, regardless of whether they run on the same or different devices.
6
7
8## Available APIs
9
10Table 1 Native IPC APIs
11
12| Class| API| Description|
13| -------- | -------- | -------- |
14| [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr<IRemoteObject> AsObject() | Holder of a remote proxy object. If you call this API on the stub, the **RemoteObject** is returned; if you call this API on the proxy, the proxy object is returned.|
15| IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) | Callback used to process a request from the proxy and return the result. Derived classes need to override this API.|
16| IRemoteProxy |  | Service proxy class, which is derived from the **IRemoteProxy** class.|
17
18
19## How to Develop
20
21### **Using Native APIs**
22
231. Add dependencies.
24
25   SDK dependency:
26
27   ```
28   #IPC scenario
29   external_deps = [
30     "ipc:ipc_single",
31   ]
32
33   #RPC scenario
34   external_deps = [
35     "ipc:ipc_core",
36   ]
37   ```
38
39   In addition, the refbase implementation on which IPC/RPC depends is stored in **//utils**. Add the dependency on the Utils source code.
40
41   ```
42   external_deps = [
43     "c_utils:utils",
44   ]
45   ```
46
472. Define the IPC interface **ITestAbility**.
48
49   **ITestAbility** inherits the IPC base class **IRemoteBroker** and defines descriptors, functions, and message code. The functions need to be implemented on both the proxy and stub.
50
51   ```c++
52   #include "iremote_broker.h"
53
54   // Define message codes.
55   const int TRANS_ID_PING_ABILITY = 5
56
57   const std::string DESCRIPTOR = "test.ITestAbility";
58
59   class ITestAbility : public IRemoteBroker {
60   public:
61       // DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string.
62       DECLARE_INTERFACE_DESCRIPTOR(to_utf16(DESCRIPTOR));
63       virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions.
64   };
65   ```
66
673. Define and implement service provider **TestAbilityStub**.
68
69   This class is related to the IPC framework and needs to inherit **IRemoteStub<ITestAbility>**. You need to override **OnRemoteRequest** on the stub to receive requests from the proxy.
70
71   ```c++
72   #include "iability_test.h"
73   #include "iremote_stub.h"
74
75   class TestAbilityStub : public IRemoteStub<ITestAbility> {
76   public:
77       virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
78       int TestPingAbility(const std::u16string &dummy) override;
79    };
80
81   int TestAbilityStub::OnRemoteRequest(uint32_t code,
82       MessageParcel &data, MessageParcel &reply, MessageOption &option)
83   {
84       switch (code) {
85           case TRANS_ID_PING_ABILITY: {
86               std::u16string dummy = data.ReadString16();
87               int result = TestPingAbility(dummy);
88               reply.WriteInt32(result);
89               return 0;
90           }
91           default:
92               return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
93       }
94   }
95   ```
96
974. Define the **TestAbility** class that implements functions for the stub.
98
99   ```c++
100   #include "iability_server_test.h"
101
102   class TestAbility : public TestAbilityStub {
103   public:
104       int TestPingAbility(const std::u16string &dummy);
105   }
106
107   int TestAbility::TestPingAbility(const std::u16string &dummy) {
108       return 0;
109   }
110   ```
111
1125. Define and implement **TestAbilityProxy**.
113
114   This class is implemented on the proxy and inherits **IRemoteProxy&lt;ITestAbility&gt;**. You can call **SendRequest** to send a request to the stub and expose the capabilities provided by the stub.
115
116   ```c++
117   #include "iability_test.h"
118   #include "iremote_proxy.h"
119   #include "iremote_object.h"
120
121   class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
122   public:
123       explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
124       int TestPingAbility(const std::u16string &dummy) override;
125   private:
126       static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
127   }
128
129   TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
130       : IRemoteProxy<ITestAbility>(impl)
131   {
132   }
133
134   int TestAbilityProxy::TestPingAbility(const std::u16string &dummy){
135       MessageOption option;
136       MessageParcel dataParcel, replyParcel;
137       dataParcel.WriteString16(dummy);
138       int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
139       int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
140       return result;
141   }
142   ```
143
1446. Register and start an SA.
145
146   Call **AddSystemAbility** to register the **TestAbilityStub** instance of the SA with **SystemAbilityManager**. The registration parameters vary depending on whether the **SystemAbilityManager** resides on the same device as the SA.
147
148   ```c++
149   // Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
150   auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
151   samgr->AddSystemAbility(saId, new TestAbility());
152
153   // Register the TestAbilityStub instance with the SystemAbilityManager on a different device.
154   auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
155   ISystemAbilityManager::SAExtraProp saExtra;
156   saExtra.isDistributed = true; // Set a distributed SA.
157   int result = samgr->AddSystemAbility(saId, new TestAbility(), saExtra);
158   ```
159
1607. Obtain the SA.
161
162   Call the **GetSystemAbility** function of the **SystemAbilityManager** class to obtain the **IRemoteObject** for the SA, and create a **TestAbilityProxy** instance.
163
164   ```c++
165   // Obtain the proxy of the SA registered on the local device.
166   sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
167   sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
168   sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type.
169
170   // Obtain the proxy of the SA registered with any other devices.
171   sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
172
173   // networkId is the device identifier and can be obtained through GetLocalNodeDeviceInfo.
174   sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, networkId);
175   sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy.
176   ```
177
178### **Using JS APIs**
179
1801. Add dependencies.
181
182   ```ts
183   import rpc from "@ohos.rpc"
184   import featureAbility from "@ohos.ability.featureAbility"
185   ```
186
187
188
1892. Bind the desired ability.
190
191   Construct the **want** variable, and specify the bundle name and component name of the application where the ability is located. If cross-device communication is involved, also specify the network ID of the target device, which can be obtained through **deviceManager**. Then, construct the **connect** variable, and specify the callback that is called when the binding is successful, the binding fails, or the ability is disconnected. After that, call the API provided by **featureAbility** to bind an ability.
192
193   ```ts
194   import rpc from "@ohos.rpc"
195   import featureAbility from "@ohos.ability.featureAbility"
196
197   let proxy = null
198   let connectId = null
199
200   // Bind the ability on a single device.
201   let want = {
202       // Enter the bundle name and ability name.
203       "bundleName": "ohos.rpc.test.server",
204       "abilityName": "ohos.rpc.test.server.ServiceAbility",
205   }
206   let connect = {
207       onConnect:function(elementName, remote) {
208           proxy = remote
209       },
210       onDisconnect:function(elementName) {
211       },
212       onFailed:function() {
213           proxy = null
214       }
215   }
216   connectId = featureAbility.connectAbility(want, connect)
217
218   // If you're binding the ability across devices, use deviceManager to obtain the network ID of the target device.
219   import deviceManager from '@ohos.distributedHardware.deviceManager'
220   function deviceManagerCallback(deviceManager) {
221       let deviceList = deviceManager.getTrustedDeviceListSync()
222       let networkId = deviceList[0].networkId
223       let want = {
224           "bundleName": "ohos.rpc.test.server",
225           "abilityName": "ohos.rpc.test.service.ServiceAbility",
226           "networkId": networkId,
227           "flags": 256
228       }
229       connectId = featureAbility.connectAbility(want, connect)
230   }
231   // The first parameter specifies the bundle name of the application, and the second parameter specifies the callback used to return the device ID obtained by using DeviceManager.
232   deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback)
233   ```
234
235
236
2373. Process requests sent from the client.
238
239   Call the **onConnect** API to return a proxy object inherited from **rpc.RemoteObject** after the ability is successfully bound. Implement the **onRemoteMessageRequest** API for the proxy object to process requests sent from the client.
240
241   ```ts
242   onConnect(want: Want) {
243       var robj:rpc.RemoteObject = new Stub("rpcTestAbility")
244       return robj
245   }
246   class Stub extends rpc.RemoteObject {
247       constructor(descriptor) {
248           super(descriptor)
249       }
250       onRemoteMessageRequest(code, data, reply, option) {
251           // Process requests sent from the client based on the code.
252           return true
253       }
254   }
255   ```
256
257
258
2594. Process responses sent from the server.
260
261   Obtain the proxy object from the **onConnect** callback, call **sendRequestAsync** to send a request, and receive the response using a callback or a promise (an object representing the eventual completion or failure of an asynchronous operation and its result value).
262
263   ```ts
264   // Use a promise.
265   let option = new rpc.MessageOption()
266   let data = rpc.MessageParcel.create()
267   let reply = rpc.MessageParcel.create()
268   // Write parameters to data.
269   proxy.sendRequestAsync(1, data, reply, option)
270       .then(function(result) {
271           if (result.errCode != 0) {
272               console.error("send request failed, errCode: " + result.errCode)
273               return
274           }
275           // Read the result from result.reply.
276       })
277       .catch(function(e) {
278           console.error("send request got exception: " + e)
279       }
280       .finally(() => {
281           data.reclaim()
282           reply.reclaim()
283       })
284
285   // Use a callback.
286   function sendRequestCallback(result) {
287       try {
288           if (result.errCode != 0) {
289               console.error("send request failed, errCode: " + result.errCode)
290               return
291           }
292           // Read the result from result.reply.
293       } finally {
294           result.data.reclaim()
295           result.reply.reclaim()
296       }
297   }
298   let option = new rpc.MessageOption()
299   let data = rpc.MessageParcel.create()
300   let reply = rpc.MessageParcel.create()
301   // Write parameters to data.
302   proxy.sendRequest(1, data, reply, option, sendRequestCallback)
303   ```
304
3055. Tear down the connection.
306
307   Use the API provided by **featureAbility** to tear down the connection when the communication is over.
308
309   ```ts
310   import rpc from "@ohos.rpc"
311   import featureAbility from "@ohos.ability.featureAbility"
312   function disconnectCallback() {
313       console.info("disconnect ability done")
314   }
315   featureAbility.disconnectAbility(connectId, disconnectCallback)
316   ```
317