• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..17-Mar-2025-

config/H17-Mar-2025-5447

example/rust_test/H17-Mar-2025-472335

figures/H17-Mar-2025-

interfaces/H17-Mar-2025-10,7295,985

ipc/H17-Mar-2025-68,44452,613

services/dbinder/H17-Mar-2025-12,3628,710

test/resource/H17-Mar-2025-9264

utils/H17-Mar-2025-232162

.gitattributesH A D17-Mar-2025631 1615

.gitignoreH A D17-Mar-2025630 1816

BUILD.gnH A D17-Mar-20251.3 KiB3834

CODEOWNERSH A D17-Mar-20251.2 KiB4533

Cargo.tomlH A D17-Mar-2025664 1917

LICENSEH A D17-Mar-20259.9 KiB179150

OAT.xmlH A D17-Mar-20253.9 KiB6412

README.mdH A D17-Mar-202512.2 KiB263197

README_zh.mdH A D17-Mar-202529.2 KiB772598

bundle.jsonH A D17-Mar-20255.3 KiB162161

config.gniH A D17-Mar-2025684 1816

rustfmt.tomlH A D17-Mar-2025774 2018

README.md

1# communication\_ipc<a name="EN-US_TOPIC_0000001103602398"></a>
2
3-   [Introduction](#section11660541593)
4-   [Architecture](#section1950291414611)
5-   [Directory Structure](#section161941989596)
6-   [Constraints](#section119744591305)
7-   [Compilation and Building](#section137768191623)
8-   [Usage](#section1312121216216)
9    -   [Available APIs](#section1551164914237)
10    -   [Usage Guidelines](#section129654513264)
11
12-   [Repositories Involved](#section1371113476307)
13
14## Introduction<a name="section11660541593"></a>
15
16The inter-process communication \(IPC\) and remote procedure call \(RPC\) mechanisms are used to implement cross-process communication. The difference between them lies in that IPC uses the Binder driver to implement cross-process communication within a device, whereas RPC uses the DSoftBus driver to implement cross-process communication across devices. IPC and RPC generally use a client-server model. The service requester \(client\) can obtain the proxy of the service provider \(server\) and use the proxy to read and write data, thus implementing data communication between processes. Generally, the server registers system abilities \(SAs\) with the system ability manager \(SAMgr\), which manages the SAs and provides APIs for the client. To communicate with a specific SA, the client must obtain the proxy of the SA from SAMgr. In this document, Proxy represents the service requester, and Stub represents the service provider.
17
18## Architecture<a name="section1950291414611"></a>
19
20**Figure  1**  IPC architecture<a name="fig312319321710"></a>
21![](figures/ipc-architecture.png "ipc-architecture")
22
23## Directory Structure<a name="section161941989596"></a>
24
25```
26/foundation/communication/ipc
27├── interfaces        # APIs exposed externally
28│   └── innerkits     # Header files for internal subsystems
29│       ├── ipc_core     # IPC APIs
30│       └── libdbinder   # dbinder APIs
31├── ipc            # IPC framework
32│   ├── native     # IPC native implementation
33│       ├── src    # IPC native source code
34│       └── test   # IPC native unit test cases
35│   └── test       # IPC native module test cases
36├── service        # dbinder implementation
37│   └── dbinder    # dbinder source code
38```
39
40## Constraints<a name="section119744591305"></a>
41
42Currently, cross-device RPC communication is not supported.
43
44## Compilation and Building<a name="section137768191623"></a>
45
46**Native Dependency**
47
48SDK dependency:
49
50```
51external_deps = [
52  "ipc:ipc_core",
53]
54```
55
56In addition, the refbase implementation on which IPC/RPC depends is stored in  **//utils**. Add the dependency on the Utils source code.
57
58```
59deps = [
60  "//utils/native/base:utils",
61]
62```
63
64## Usage<a name="section1312121216216"></a>
65
66The procedure for implementing cross-process communication using native APIs is similar to that using Java APIs.
67
681.  Define an interface.
69
70    The interface inherits  **IRemoteBroker**  and defines descriptors, functions, and message code.
71
722.  Implement the server provider \(stub\).
73
74    The stub inherits  **IRemoteStub\(Native\)**  or  **RemoteObject\(Java\)**  as well as  **AsObject**  and  **OnRemoteRequest**.
75
763.  Implement the service requester \(proxy\).
77
78    The proxy inherits  **IRemoteProxy\(Native\)**  or  **RemoteProxy\(Java\)**, encapsulates functions, and calls  **SendRequest**  to send requests to the stub.
79
804.  Register an SA.
81
82    After the process where the service provider resides starts, apply for the unique SA ID and register the stub with SAMgr.
83
845.  Obtain the SA.
856.  Obtain the proxy from the SAMgr based on the SA ID and device ID, and implement cross-process communication with the stub through the proxy.
86
87### Available APIs<a name="section1551164914237"></a>
88
89**Table  1**  Native IPC APIs
90
91<a name="table178849240013"></a>
92<table><thead align="left"><tr id="row6884924608"><th class="cellrowborder" valign="top" width="14.12141214121412%" id="mcps1.2.4.1.1"><p id="p98846241706"><a name="p98846241706"></a><a name="p98846241706"></a>Class/Interface</p>
93</th>
94<th class="cellrowborder" valign="top" width="52.54525452545254%" id="mcps1.2.4.1.2"><p id="p1488482414020"><a name="p1488482414020"></a><a name="p1488482414020"></a>Method</p>
95</th>
96<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p388516244016"><a name="p388516244016"></a><a name="p388516244016"></a>Description</p>
97</th>
98</tr>
99</thead>
100<tbody><tr id="row15885824402"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p08859241008"><a name="p08859241008"></a><a name="p08859241008"></a>IRemoteBroker</p>
101</td>
102<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 "><p id="p388572412010"><a name="p388572412010"></a><a name="p388572412010"></a>sptr&lt;IRemoteObject&gt; AsObject()</p>
103</td>
104<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p13885724405"><a name="p13885724405"></a><a name="p13885724405"></a>Obtains the holder of a remote proxy object. This method must be implemented by the derived classes of <strong id="b9012379013"><a name="b9012379013"></a><a name="b9012379013"></a>IRemoteBroker</strong>. If you call this method on the stub, the <strong id="b11613719015"><a name="b11613719015"></a><a name="b11613719015"></a>RemoteObject</strong> is returned; if you call this method on the proxy, the proxy object is returned.</p>
105</td>
106</tr>
107<tr id="row138859241808"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p1888515245012"><a name="p1888515245012"></a><a name="p1888515245012"></a>IRemoteStub</p>
108</td>
109<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 "><p id="p1388516240011"><a name="p1388516240011"></a><a name="p1388516240011"></a>virtual int OnRemoteRequest(uint32_t code, MessageParcel &amp;data, MessageParcel &amp;reply, MessageOption &amp;option)</p>
110</td>
111<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1188582414016"><a name="p1188582414016"></a><a name="p1188582414016"></a>Called to process a request from the proxy and return the result. Derived classes need to override this method.</p>
112</td>
113</tr>
114<tr id="row108856241904"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p6885924609"><a name="p6885924609"></a><a name="p6885924609"></a>IRemoteProxy</p>
115</td>
116<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 ">&nbsp;&nbsp;</td>
117<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p688592413018"><a name="p688592413018"></a><a name="p688592413018"></a>Service proxy classes are derived from the <strong id="b8934204311212"><a name="b8934204311212"></a><a name="b8934204311212"></a>IRemoteProxy</strong> class.</p>
118</td>
119</tr>
120</tbody>
121</table>
122
123### Usage Guidelines<a name="section129654513264"></a>
124
125**Native**
126
127Define the IPC interface  **ITestAbility**.
128
129**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.
130
131```
132class ITestAbility : public IRemoteBroker {
133public:
134// DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string.
135DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility");
136int TRANS_ID_PING_ABILITY = 1; // Define the message code.
137virtual int TestPingAbility(const std::u16string &dummy) = 0; // Define functions.
138};
139```
140
141Define and implement service provider  **TestAbilityStub**.
142
143This 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.
144
145```
146class TestAbilityStub : public IRemoteStub<ITestAbility> {
147public:
148    virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
149    int TestPingAbility(const std::u16string &dummy) override;
150};
151
152int TestServiceStub::OnRemoteRequest(uint32_t code,
153    MessageParcel &data, MessageParcel &reply, MessageOption &option)
154{
155    switch (code) {
156        case TRANS_ID_PING_ABILITY: {
157            std::u16string dummy = data.ReadString16();
158            int result = TestPingAbility(dummy);
159            reply.WriteInt32(result);
160            return 0;
161        }
162        default:
163            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
164    }
165}
166```
167
168Define the  **TestAbility**  class that implements functions for the stub.
169
170```
171class TestAbility : public TestAbilityStub {
172public:
173    int TestPingAbility(const std::u16string &dummy);
174}
175
176int TestAbility::TestPingAbility(const std::u16string &dummy) {
177    return 0;
178}
179```
180
181Define and implement  **TestAbilityProxy**.
182
183This class is implemented on the proxy and inherits  **IRemoteProxy<ITestAbility\>**. You can call  **SendRequest**  to send a request to the stub and expose the capabilities provided by the stub.
184
185```
186class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
187public:
188    explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
189    int TestPingService(const std::u16string &dummy) override;
190private:
191    static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
192}
193
194TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
195    : IRemoteProxy<ITestAbility>(impl)
196{
197}
198
199int TestAbilityProxy::TestPingService(const std::u16string &dummy) {
200    MessageOption option;
201    MessageParcel dataParcel, replyParcel;
202    dataParcel.WriteString16(dummy);
203    int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
204    int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
205    return result;
206}
207```
208
209Send a request synchronously or asynchronously.
210
211The  **MessageOption**  parameter for the  **sendRequest\(\)**  method can be set to  **TF\_SYNC**,  **TF\_ASYNC**, using the  **MessageOption**  constructor or  **void SetFlags\(int flags\)**. The default value is  **TF\_SYNC**.
212
213```
214int SendRequest(uint32_t code, MessageParcel &data,
215    MessageParcel &reply, MessageOption &option) override;
216MessageOption option;
217option.setFlags(option.TF_ASYNC);
218```
219
220Register and start an SA.
221
222Call  **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.
223
224```
225// Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
226auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
227samgr->AddSystemAbility(said, new TestAbility());
228
229// Register the TestAbilityStub instance with the SystemAbilityManager on a different device.
230auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
231ISystemAbilityManager::SAExtraProp saExtra;
232saExtra.isDistributed = true; // Set a distributed SA.
233int result = samgr->AddSystemAbility(said, new TestAbility(), saExtra);
234```
235
236Obtain the SA.
237
238Call the  **GetSystemAbility**  function of the  **SystemAbilityManager**  class to obtain the  **IRemoteObject**  for the SA, and create a  **TestAbilityProxy**  instance.
239
240```
241// Obtain the proxy of the SA registered on the local device.
242sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
243sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(said);
244sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type.
245
246// Obtain the proxies of the SAs registered with other devices.
247sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
248sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(sdid, deviceId); // deviceId identifies a device.
249sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy.
250```
251
252## Repositories Involved<a name="section1371113476307"></a>
253
254DSoftBus subsystem
255
256**communication\_ipc**
257
258[commonlibrary\_c\_utils](https://gitee.com/openharmony/commonlibrary_c_utils)
259
260[distributedschedule\_samgr](https://gitee.com/openharmony/distributedschedule_samgr)
261
262
263

README_zh.md

1# IPC/RPC组件<a name="ZH-CN_TOPIC_0000001103602398"></a>
2
3-   [简介](#section11660541593)
4-   [系统架构](#section1950291414611)
5-   [目录](#section161941989596)
6-   [约束](#section119744591305)
7-   [编译构建](#section137768191623)
8-   [说明](#section1312121216216)
9    -   [接口说明](#section1551164914237)
10    -   [使用说明](#section129654513264)
11
12-   [相关仓](#section1371113476307)
13
14## 简介<a name="section11660541593"></a>
15
16IPC(Inter-Process Communication)与RPC(Remote Procedure Call)机制用于实现跨进程通信,不同的是前者使用Binder驱动,用于设备内的跨进程通信,而后者使用软总线驱动,用于跨设备跨进程通信。IPC和RPC通常采用客户端-服务器(Client-Server)模型,服务请求方(Client)可获取提供服务提供方(Server)的代理 (Proxy),并通过此代理读写数据来实现进程间的数据通信。通常,系统能力(System Ability)Server侧会先注册到系统能力管理者(System Ability Manager,缩写SAMgr)中,SAMgr负责管理这些SA并向Client提供相关的接口。Client要和某个具体的SA通信,必须先从SAMgr中获取该SA的代理,然后使用代理和SA通信。三方应用可以使用FA提供的接口绑定服务提供方的Ability,获取代理,进行通信。下文使用Proxy表示服务请求方,Stub表示服务提供方。
17
18## 系统架构<a name="section1950291414611"></a>
19
20**图 1**  IPC通信机制架构图<a name="fig312319321710"></a>
21![](figures/ipc-architecture.png "IPC通信机制架构图")
22
23## 目录<a name="section161941989596"></a>
24
25```
26/foundation/communication/ipc
27├── interfaces        # 对外接口存放目录
28│   └── innerkits     # 对内部子系统暴露的头文件存放目录
29│       ├── ipc_core     # ipc 接口存放目录
30│       └── libdbinder   # dbinder 接口存放目录
31├── ipc            # ipc 框架代码
32│   ├── native     # ipc native 实现存放目录
33│       ├── src    # ipc native 源代码存放目录
34│       └── test   # ipc native 单元测试用例存放目录
35│   └── test       # ipc native 模块测试用例存放目录
36├── service        # dbinder 实现存放目录
37│   └── dbinder    # dbinder 源代码存放目录
38```
39
40## 约束<a name="section119744591305"></a>
41
421. 单个设备上跨进程通信时,传输的数据量最大约为1MB,过大的数据量请使用匿名共享内存。
432. 不支持把跨设备的Proxy对象传递回该Proxy对象所指向的Stub对象所在的设备。
44
45## 编译构建<a name="section137768191623"></a>
46
47**JS侧依赖**
48
49```
50import rpc from "@ohos.rpc"
51```
52
53**Native侧编译依赖**
54
55sdk依赖:
56
57```
58external_deps = [
59  "ipc:ipc_core",
60]
61```
62
63此外, IPC/RPC依赖的refbase实现在公共基础库下,请增加对utils的依赖:
64
65```
66external_deps = [
67  "c_utils:utils",
68]
69```
70
71**Rust侧编译依赖**
72
73```
74external_deps = [ "ipc:ipc_rust" ]
75```
76
77## 说明<a name="section1312121216216"></a>
78
79**JS侧实现跨进程通信基本步骤:**
80
811. 获取代理
82
83   使用ohos.app.ability.UIAbility提供的globalThis.context.connectServiceExtensionAbility方法绑定Ability,在参数里指定要绑定的Ability所在应用的包名、组件名,如果是跨设备的情况,还需要指定所在设备的NetworkId。用户需要在服务端的onConnect方法里返回一个继承自ohos.rpc.RemoteObject的对象,此对象会在其onRemoteMessageRequest方法里接收到请求。
84
852. 发送请求
86
87   客户端在globalThis.context.connectServiceExtensionAbility参数指定的回调函数接收到代理对象后,使用ohos.rpc模块提供的方法完成RPC通信,其中MessageParcel提供了读写各种类型数据的方法,IRemoteObject提供了发送请求的方法,RemoteObject提供了处理请求的方法onRemoteRequest,用户需要重写。
88
89**Native侧实现跨进程通信的基本步骤:**
90
911. 定义接口类
92
93   接口类继承IRemoteBroker,定义描述符、业务函数和消息码。
94
952. 实现服务提供端\(Stub\)
96
97   Stub继承IRemoteStub\(Native\),除了接口类中未实现方法外,还需要实现AsObject方法及OnRemoteRequest方法。
98
993. 实现服务请求端\(Proxy\)
100
101   Proxy继承IRemoteProxy\(Native\),封装业务函数,调用SendRequest将请求发送到Stub。
102
1034. 注册SA
104
105   服务提供方所在进程启动后,申请SA的唯一标识,将Stub注册到SAMgr。
106
1075. 获取SA
108
1096. 通过SA的标识和设备NetworkId,从SAMgr获取Proxy,通过Proxy实现与Stub的跨进程通信。
110
111**Rust侧实现跨进程通信的基本步骤:**
112
1131. 定义接口
114
115   继承IPC框架的IRemoteBroker特征,定义一个业务自己的trait,在此trait中定义proxy和stub之间的IPC方法。
116
1172. 定义服务
118
119   和c++ 定义的服务类似,Rust服务相关的类型有两个;
120
121   1)由业务提供名字,通过宏define_remote_object定义。
122
123   2)由业务定义,框架不关心其内容,只要求其必须实现步骤1中定义的接口trait。
124
1253. 定义代理
126
127   代理的定义由业务提供名字,通过宏define_remote_object定义代理的类型。
128
1294. 创建并注册服务
130
131   服务定义完成后,只有注册到samgr后,其他进程才能获取该服务的代理,完成和该服务的通信。
132
1335. 获取代理
134
135   通过向samgr发起请求,可以获取到指定服务的代理对象,之后便可以调用该代理对象的IPC方法实现和服务的通信。
136
1376. 测试服务能力
138
139### 接口说明<a name="section1551164914237"></a>
140
141**表 1**  JS侧IPC关键API
142
143| 模块                       | 方法                                                         | 功能说明                                    |
144| -------------------------- | ------------------------------------------------------------ | ------------------------------------------- |
145| ohos.app.ability.UIAbility | globalThis.context.connectServiceExtensionAbility(want: Want, options:ConnectOptions ): number | 绑定指定的Ability,在回调函数里接收代理对象 |
146| ohos.rpc.RemoteObject      | onRemoteMessageRequest(code: number, data: MessageParcel, reply: MessageParcel, options: MessageOption): boolean \| Promise<boolean> | 服务端处理请求,返回结果                    |
147| ohos.rpc.IRemoteObject     | sendRequest(code: number, data: MessageParcel, reply: MessageParcel, options: MessageOption): Promise<SendRequestResult> | 发送请求,在期约里接收结果                  |
148| ohos.rpc.IRemoteObject     | sendRequest(code: number, data: MessageParcel, reply: MessageParcel, options: MessageOption, callback: AsyncCallback<SendRequestResult>): void | 发送请求,在回调函数里接收结果              |
149| ohos.rpc.MessageParcel     | writeRemoteObject(object: IRemoteObject): boolean            | 序列化IRemoteObject对象                     |
150| ohos.rpc.MessageParcel     | readRemoteObject(): IRemoteObject                            | 反序列化IRemoteObject对象                   |
151
152
153
154**表 2**  Native侧IPC接口
155
156<a name="table178849240013"></a>
157
158<table><thead align="left"><tr id="row6884924608"><th class="cellrowborder" valign="top" width="14.12141214121412%" id="mcps1.2.4.1.1"><p id="p98846241706"><a name="p98846241706"></a><a name="p98846241706"></a>类/接口</p>
159</th>
160<th class="cellrowborder" valign="top" width="52.54525452545254%" id="mcps1.2.4.1.2"><p id="p1488482414020"><a name="p1488482414020"></a><a name="p1488482414020"></a>方法</p>
161</th>
162<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p388516244016"><a name="p388516244016"></a><a name="p388516244016"></a>功能说明</p>
163</th>
164</tr>
165</thead>
166<tbody><tr id="row15885824402"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p08859241008"><a name="p08859241008"></a><a name="p08859241008"></a>IRemoteBroker</p>
167</td>
168<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 "><p id="p388572412010"><a name="p388572412010"></a><a name="p388572412010"></a>sptr&lt;IRemoteObject&gt; AsObject()</p>
169</td>
170<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p13885724405"><a name="p13885724405"></a><a name="p13885724405"></a>返回通信对象。派生类需要实现,Stub端返回RemoteObject对象本身,Proxy端返回代理对象。</p>
171</td>
172</tr>
173<tr id="row138859241808"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p1888515245012"><a name="p1888515245012"></a><a name="p1888515245012"></a>IRemoteStub</p>
174</td>
175<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 "><p id="p1388516240011"><a name="p1388516240011"></a><a name="p1388516240011"></a>virtual int OnRemoteRequest(uint32_t code, MessageParcel &amp;data, MessageParcel &amp;reply, MessageOption &amp;option)</p>
176</td>
177<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1188582414016"><a name="p1188582414016"></a><a name="p1188582414016"></a>请求处理方法,派生类需要重写,处理Proxy的请求并返回结果。</p>
178</td>
179</tr>
180<tr id="row108856241904"><td class="cellrowborder" valign="top" width="14.12141214121412%" headers="mcps1.2.4.1.1 "><p id="p6885924609"><a name="p6885924609"></a><a name="p6885924609"></a>IRemoteProxy</p>
181</td>
182<td class="cellrowborder" valign="top" width="52.54525452545254%" headers="mcps1.2.4.1.2 ">&nbsp;&nbsp;</td>
183<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p688592413018"><a name="p688592413018"></a><a name="p688592413018"></a>业务Proxy类派生自IRemoteProxy类。</p>
184</td>
185</tr>
186</tbody>
187</table>
188
189### 使用说明<a name="section129654513264"></a>
190
191**JS侧使用说明**
192
1931. 客户端构造变量want,指定要绑定的Ability所在应用的包名、组件名,如果是跨设备的场景,还需要目标设备NetworkId。构造变量connect,指定绑定成功、绑定失败、断开连接时的回调函数。使用UIAbility提供的接口绑定Ability。
194
195   ```
196   import rpc from "@ohos.rpc"
197
198   let proxy = null
199   let connectId = null
200
201   // 单个设备
202   let want = {
203       // 包名和组件名写实际的值
204       "bundleName": "ohos.rpc.test.server",
205       "abilityName": "ohos.rpc.test.server.ServiceAbility",
206   }
207   let connect = {
208       onConnect:function(elementName, remote) {
209           proxy = remote
210       },
211       onDisconnect:function(elementName) {
212       },
213       onFailed:function() {
214           proxy = null
215       }
216   }
217   connectId = globalThis.context.connectServiceExtensionAbility(want, connect)
218
219   // 如果是跨设备绑定,可以使用deviceManager获取目标设备NetworkId
220   import deviceManager from '@ohos.distributedHardware.deviceManager'
221   function deviceManagerCallback(deviceManager) {
222       let deviceList = deviceManager.getTrustedDeviceListSync()
223       let deviceId = deviceList[0].deviceId
224       let want = {
225           "bundleName": "ohos.rpc.test.server",
226           "abilityName": "ohos.rpc.test.service.ServiceAbility",
227           "deviceId": deviceId,
228           "flags": 256
229       }
230       connectId = globalThis.context.connectServiceExtensionAbility(want, connect)
231   }
232   // 第一个参数是本应用的包名,第二个参数是接收deviceManager的回调函数
233   deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback)
234   ```
235
236
237
2382. 服务端被绑定的Ability在onConnect方法里返回继承自rpc.RemoteObject的对象,该对象需要实现onRemoteMessageRequest方法,处理客户端的请求。
239
240   ```
241   import rpc from "@ohos.rpc"
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           // 根据code处理客户端的请求
252           return true
253       }
254   }
255   ```
256
257
258
2593. 客户端在onConnect回调里接收到代理对象,调用sendRequest方法发起请求,在期约或者回调函数里接收结果。
260
261   ```
262   import rpc from "@ohos.rpc"
263   // 使用期约
264   let option = new rpc.MessageOption()
265   let data = rpc.MessageParcel.create()
266   let reply = rpc.MessageParcel.create()
267   // 往data里写入参数
268   proxy.sendRequest(1, data, reply, option)
269       .then(function(result) {
270           if (result.errCode != 0) {
271               console.error("send request failed, errCode: " + result.errCode)
272               return
273           }
274           // 从result.reply里读取结果
275       })
276       .catch(function(e) {
277           console.error("send request got exception: " + e)
278       }
279       .finally(() => {
280           data.reclaim()
281           reply.reclaim()
282       })
283
284   // 使用回调函数
285   function sendRequestCallback(result) {
286       try {
287           if (result.errCode != 0) {
288               console.error("send request failed, errCode: " + result.errCode)
289               return
290           }
291           // 从result.reply里读取结果
292       } finally {
293           result.data.reclaim()
294           result.reply.reclaim()
295       }
296   }
297   let option = new rpc.MessageOption()
298   let data = rpc.MessageParcel.create()
299   let reply = rpc.MessageParcel.create()
300   // 往data里写入参数
301   proxy.sendRequest(1, data, reply, option, sendRequestCallback)
302   ```
303
304
305
3064. IPC通信结束后,使用UIAbility的接口断开连接。
307
308   ```
309   import rpc from "@ohos.rpc"
310   globalThis.context.disconnectServiceExtensionAbility(connectionId).then((data) => {
311       console.info('disconnectServiceExtensionAbility success');
312   }).catch((error) => {
313       console.error('disconnectServiceExtensionAbility failed');
314   })
315   ```
316
317
318
319**Native侧使用说明**
320
3211. 定义IPC接口ITestAbility
322
323   IPC接口继承IPC基类接口IRemoteBroker,接口里定义描述符、业务函数和消息码,其中业务函数在Proxy端和Stub端都需要实现。
324
325   ```
326   class ITestAbility : public IRemoteBroker {
327   public:
328   // DECLARE_INTERFACE_DESCRIPTOR是必须的, 入参需使用std::u16string;
329   DECLARE_INTERFACE_DESCRIPTOR(u"test.ITestAbility"); // DESCRIPTOR接口描述符建议使用"组件名.类名"的格式
330   int TRANS_ID_PING_ABILITY = 1; // 定义消息码
331   virtual int TestPingAbility(const std::u16string &dummy) = 0; // 定义业务函数
332   };
333   ```
334
335
336
3372. 定义和实现服务端TestAbilityStub
338
339   该类是和IPC框架相关的实现,需要继承自IRemoteStub<ITestAbility\>。Stub端作为接收请求的一端,需重写OnRemoteRequest方法用于接收客户端调用。
340
341   ```
342   class TestAbilityStub : public IRemoteStub<ITestAbility> {
343   public:
344       virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
345       int TestPingAbility(const std::u16string &dummy) override;
346   };
347
348   int TestAbilityStub::OnRemoteRequest(uint32_t code,
349       MessageParcel &data, MessageParcel &reply, MessageOption &option)
350   {
351       if (data.ReadInterfaceToken() != GetDescriptor()) { // 校验是否为本服务的接口描述符,避免中继攻击
352           return -1;
353       }
354       switch (code) {
355           case TRANS_ID_PING_ABILITY: {
356               std::u16string dummy = data.ReadString16();
357               int result = TestPingAbility(dummy);
358               reply.WriteInt32(result);
359               return 0;
360           }
361           default:
362               return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
363       }
364   }
365   ```
366
367
368
3693. 定义服务端业务函数具体实现类TestAbility
370
371   ```
372   class TestAbility : public TestAbilityStub {
373   public:
374       int TestPingAbility(const std::u16string &dummy);
375   }
376
377   int TestAbility::TestPingAbility(const std::u16string &dummy) {
378       return 0;
379   }
380   ```
381
382
383
3844. 定义和实现客户端TestAbilityProxy
385
386   该类是Proxy端实现,继承自IRemoteProxy<ITestAbility\>,调用SendRequest接口向Stub端发送请求,对外暴露服务端提供的能力。
387
388   ```
389   class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
390   public:
391       explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
392       int TestPingService(const std::u16string &dummy) override;
393   private:
394       static inline BrokerDelegator<TestAbilityProxy> delegator_; // 方便使用iface_cast宏
395   }
396
397   TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
398       : IRemoteProxy<ITestAbility>(impl)
399   {
400   }
401
402   int TestAbilityProxy::TestPingService(const std::u16string &dummy) {
403       MessageOption option;
404       MessageParcel dataParcel, replyParcel;
405       if(!dataParcel.WriteInterfaceToken(GetDescriptor())) { // 所有对外接口的proxy实现都要写入接口描述符,用于stub端检验
406           return -1;
407       }
408       if(!dataParcel.WriteString16(dummy)) {
409           return -1;
410       }
411       int error = Remote()->SendRequest(TRANS_ID_PING_ABILITY, dataParcel, replyParcel, option);
412       int result = (error == ERR_NONE) ? replyParcel.ReadInt32() : -1;
413       return result;
414   }
415   ```
416
417
418
4195. 同步调用与异步调用
420
421   MessageOption作为发送接口(原型如下)的入参,可设定同步(TF\_SYNC)、异步(TF\_ASYNC),默认情况下设定为同步,其余可通过MessageOption构造方法或void SetFlags\(int flags\)设定。
422
423   ```
424   int SendRequest(uint32_t code, MessageParcel &data,
425       MessageParcel &reply, MessageOption &option) override;
426   MessageOption option;
427   option.setFlags(option.TF_ASYNC);
428   ```
429
430
431
4326. SA注册与启动
433
434   SA需要将自己的TestAbilityStub实例通过AddSystemAbility接口注册到SystemAbilityManager,设备内与分布式的注册参数不同。
435
436   ```
437   // 注册到本设备内
438   auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
439   samgr->AddSystemAbility(said, new TestAbility());
440
441   // 在组网场景下,会被同步到其他设备上
442   auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
443   ISystemAbilityManager::SAExtraProp saExtra;
444   saExtra.isDistributed = true; // 设置为分布式SA
445   int result = samgr->AddSystemAbility(said, new TestAbility(), saExtra);
446   ```
447
448
449
4507. SA获取与调用
451
452   通过SystemAbilityManager的GetSystemAbility方法可获取到对应SA的代理IRemoteObject,然后构造TestAbilityProxy即可。
453
454   ```
455   // 获取本设备内注册的SA的proxy
456   sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
457   sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(said);
458   sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // 使用iface_cast宏转换成具体类型
459
460   // 获取其他设备注册的SA的Proxy
461   sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
462   sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(sdid, deviceId); // deviceId是指定设备的标识符
463   sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // 直接构造具体Proxy
464   ```
465
466**Rust侧使用说明**
467
468以下为CALCULATOR服务的完整开发步骤。
469
4701. 定义接口
471
472   继承IPC框架IRemoteBroker特征,定义一个业务自己的trait,该trait中定义proxy和stub之间的IPC方法。示例如下定义了ICalc trait:
473
474   ```
475   /// Function between proxy and stub of ICalcService
476   pub trait ICalc: IRemoteBroker {
477       /// Calc add num1 + num2
478       fn add(&self, num1: i32, num2: i32) -> IpcResult<i32>;
479       /// Calc sub num1 + num2
480       fn sub(&self, num1: i32, num2: i32) -> IpcResult<i32>;
481       /// Calc mul num1 + num2
482       fn mul(&self, num1: i32, num2: i32) -> IpcResult<i32>;
483       /// Calc div num1 + num2
484       fn div(&self, num1: i32, num2: i32) -> IpcResult<i32>;
485   }
486   ```
487
488   1.1 定义枚举ICalcCode
489
490   ICalcCode枚举中的变体表示calculator服务的不同功能。当然这一步不是必须的,但是为了提高代码的可读性,建议按照如下方法为每一个IPC方法定义code,示例如下:
491
492   ```
493   /// Function code of ICalcService
494   pub enum ICalcCode {
495       /// add
496       CodeAdd = FIRST_CALL_TRANSACTION, // 由IPC框架定义,值为1,建议业务使用该值作为第一个IPC方法的code
497       /// sub
498       CodeSub,
499       /// mul
500       CodeMul,
501       /// div
502       CodeDiv,
503   }
504   ```
505
506   1.2 ICalCode转换
507
508   ICalCode实现TryFrom trait,可以实现u32类型到CalCode枚举类型的转换。
509
510   ```
511   impl TryFrom<u32> for ICalcCode {
512       type Error = IpcStatusCode;
513       fn try_from(code: u32) -> IpcResult<Self> {
514           match code {
515               _ if code == ICalcCode::CodeAdd as u32 => Ok(ICalcCode::CodeAdd),
516               _ if code == ICalcCode::CodeSub as u32 => Ok(ICalcCode::CodeSub),
517               _ if code == ICalcCode::CodeMul as u32 => Ok(ICalcCode::CodeMul),
518               _ if code == ICalcCode::CodeDiv as u32 => Ok(ICalcCode::CodeDiv),
519               _ => Err(IpcStatusCode::Failed),
520           }
521       }
522   }
523   ```
524
5252. 定义服务
526
527   和c++ 定义的服务类似,Rust服务相关的类型有两个:
528
529   1)由业务提供名字,通过宏define_remote_object!定义,如本例中的CalcStub。
530
531   2)由业务定义,框架不关心其内容,只要求其必须实现步骤1中定义的接口trait,如本例中的CalcService。
532
533   2.1 定义CalcService服务
534
535   CalcService的定义如下所示,实现了ICalc和IRemoteBroker特征,服务中没有任何成员,如有需要可以根据业务需要进行定义。
536
537   ```
538   /// example.calc.ipc.ICalcService type
539   pub struct CalcService;
540   // 实现ICalc特征
541   impl ICalc for CalcService {
542       fn add(&self, num1: i32, num2: i32) -> IpcResult<i32> {
543           Ok(add(&num1, &num2))
544       }
545       fn sub(&self, num1: i32, num2: i32) -> IpcResult<i32> {
546           Ok(sub(&num1, &num2))
547       }
548       fn mul(&self, num1: i32, num2: i32) -> IpcResult<i32> {
549           Ok(mul(&num1, &num2))
550       }
551       fn div(&self, num1: i32, num2: i32) -> IpcResult<i32> {
552           Ok(div(&num1, &num2))
553       }
554   }
555   // 实现IRemoteBroker特征
556   impl IRemoteBroker for CalcService {}
557   /// add num1 + num2
558   pub fn add(num1: &i32, num2: &i32) -> i32 {
559       num1 + num2
560   }
561   /// sub num1 + num2
562   pub fn sub(num1: &i32, num2: &i32) -> i32 {
563       num1 - num2
564   }
565   /// mul num1 + num2
566   pub fn mul(num1: &i32, num2: &i32) -> i32 {
567       num1 * num2
568   }
569   /// div num1 + num2
570   pub fn div(num1: &i32, num2: &i32) -> i32 {
571       match num2 {
572           0 => {
573               println!("Zero cannot be divided");
574               -1
575           },
576           _ => num1 / num2,
577       }
578   }
579   ```
580
581   2.2 实现on_icalc_remote_request()方法
582
583   当服务收到IPC请求,IPC框架会回调该方法,业务在该方法中完成如下处理:
584
585   1)完成参数的解析。
586
587   2)调用具体的服务IPC方法。
588
589   3)将处理结果写会reply。
590
591   示例代码如下:
592
593   ```
594   fn on_icalc_remote_request(stub: &dyn ICalc, code: u32, data: &BorrowedMsgParcel,
595       reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
596       match code.try_into()? {
597           ICalcCode::CodeAdd => {
598               let num1: i32 = data.read().expect("Failed to read num1 in addition operation");
599               let num2: i32 = data.read().expect("Failed to read num2 in addition operation");
600               let ret = stub.add(num1, num2)?;
601               reply.write(&ret)?;
602               Ok(())
603           }
604           ICalcCode::CodeSub => {
605               let num1: i32 = data.read().expect("Failed to read num1 in subtraction operation");
606               let num2: i32 = data.read().expect("Failed to read num1 in subtraction operation");
607               let ret = stub.sub(num1, num2)?;
608               reply.write(&ret)?;
609               Ok(())
610           }
611           ICalcCode::CodeMul => {
612               let num1: i32 = data.read().expect("Failed to read num1 in multiplication operation");
613               let num2: i32 = data.read().expect("Failed to read num1 in multiplication operation");
614               let ret = stub.mul(num1, num2)?;
615               reply.write(&ret)?;
616               Ok(())
617           }
618           ICalcCode::CodeDiv => {
619               let num1: i32 = data.read().expect("Failed to read num1 in division  operation");
620               let num2: i32 = data.read().expect("Failed to read num1 in division  operation");
621               let ret = stub.div(num1, num2)?;
622               reply.write(&ret)?;
623               Ok(())
624           }
625       }
626   }
627   ```
628
6293. 定义代理
630
631   代理的定义由业务提供名字,通过宏define_remote_object定义代理的类型,业务需要为代理实现ICalc。示例如下:
632
633   ```
634   impl ICalc for CalcProxy {
635       fn add(&self, num1: i32, num2: i32) -> IpcResult<i32> {
636           let mut data = MsgParcel::new().expect("MsgParcel should success");
637           data.write(&num1)?;
638           data.write(&num2)?;
639           let reply = self.remote.send_request(ICalcCode::CodeAdd as u32,
640               &data, false)?;
641           let ret: i32 = reply.read().expect("need reply i32");
642           Ok(ret)
643       }
644       fn sub(&self, num1: i32, num2: i32) -> IpcResult<i32> {
645           let mut data = MsgParcel::new().expect("MsgParcel should success");
646           data.write(&num1)?;
647           data.write(&num2)?;
648           let reply = self.remote.send_request(ICalcCode::CodeSub as u32,
649               &data, false)?;
650           let ret: i32 = reply.read().expect("need reply i32");
651           Ok(ret)
652       }
653       fn mul(&self, num1: i32, num2: i32) -> IpcResult<i32> {
654           let mut data = MsgParcel::new().expect("MsgParcel should success");
655           data.write(&num1)?;
656           data.write(&num2)?;
657           let reply = self.remote.send_request(ICalcCode::CodeMul as u32,
658               &data, false)?;
659           let ret: i32 = reply.read().expect("need reply i32");
660           Ok(ret)
661       }
662       fn div(&self, num1: i32, num2: i32) -> IpcResult<i32> {
663           let mut data = MsgParcel::new().expect("MsgParcel should success");
664           data.write(&num1)?;
665           data.write(&num2)?;
666           let reply = self.remote.send_request(ICalcCode::CodeDiv as u32,
667               &data, false)?;
668           let ret: i32 = reply.read().expect("need reply i32");
669           Ok(ret)
670       }
671   }
672   ```
673
674   上述对象最终通过宏define_remote_object调用,将业务定义的类型和IPC框架进行结合,宏define_remote_object提供了如下几个关键信息:
675
676   1)服务的接口特征ICalc。
677
678   2)服务的描述符为“example.calc.ipc.ICalcService”。
679
680   3)Rust服务类型名为CalcStub。
681
682   4)服务处理IPC请求的入口方法为on_icalc_remote_request。
683
684   5)代理类型为CalcProxy。
685
686   示例代码如下:
687
688   ```
689   define_remote_object!(
690       ICalc["example.calc.ipc.ICalcService"] {
691           stub: CalcStub(on_icalc_remote_request),
692           proxy: CalcProxy,
693       }
694   );
695   ```
696
6974.  创建并注册服务
698
699   服务定义完成后,只有注册到samgr后,其他进程才能获取该服务的代理,然后完成和该服务的通信。示例代码如下:
700
701   ```
702   fn main() {
703       init_access_token();
704       // 创建服务对象,最终的服务对象为CalcStub
705       let service = CalcStub::new_remote_stub(CalcService).expect("create CalcService success");
706       // 向samgr注册服务
707       add_service(&service.as_object().expect("get ICalc service failed"),
708           EXAMPLE_IPC_CALC_SERVICE_ID).expect("add server to samgr failed");
709       println!("join to ipc work thread");
710       // 将主线程转换为IPC线程,至此服务所在进程陷入循环
711       join_work_thread();
712   }
713   ```
714
715   注意:add_service为IPC 框架提供的临时调试接口,该接口应该由samgr模块提供。
716
7175. 获取代理
718
719   通过向samgr发起请求,可以获取到指定服务的代理对象,之后便可以调用该代理对象的IPC方法实现和服务的通信。示例代码如下:
720
721   ```
722   fn get_calc_service() -> RemoteObjRef<dyn ICalc>
723   {
724       let object = get_service(EXAMPLE_IPC_CALC_SERVICE_ID).expect("get icalc service failed");
725       let remote = <dyn ICalc as FromRemoteObj>::try_from(object);
726       let remote = match remote {
727           Ok(x) => x,
728           Err(error) => {
729               println!("convert RemoteObj to CalcProxy failed: {}", error);
730               panic!();
731           }
732       };
733       remote
734   }
735   ```
736
737   注意:示例中的get_service()为IPC框架提供的临时接口,该接口由samgr模块提供。
738
7396. 测试Calculartor服务能力
740
741   当测试用例Calculator_Ability pass表示CalcService 服务能力ok。
742
743   ```
744   #[test]
745   fn calculator_ability() {
746       let remote = get_calc_service();
747       // add
748       let ret = remote.add(5, 5).expect("add failed");
749       assert_eq!(ret, 10);
750       // sub
751       let ret = remote.sub(5, 5).expect("sub failed");
752       assert_eq!(ret, 0);
753       // mul
754       let ret = remote.mul(5, 5).expect("mul failed");
755       assert_eq!(ret, 25);
756       // div
757       let ret = remote.div(5, 5).expect("div failed");
758       assert_eq!(ret, 1);
759   }
760   ```
761
762## 相关仓<a name="section1371113476307"></a>
763
764分布式软总线子系统
765
766**communication\_ipc**
767
768[commonlibrary\_c\_utils](https://gitee.com/openharmony/commonlibrary_c_utils)
769
770[distributedschedule\_samgr](https://gitee.com/openharmony/distributedschedule_samgr)
771
772