• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ServiceExtensionAbility
2<!--Kit: Ability Kit-->
3<!--Subsystem: Ability-->
4<!--Owner: @yewei0794-->
5<!--Designer: @jsjzju-->
6<!--Tester: @lixueqing513-->
7<!--Adviser: @huipeizi-->
8
9## Overview
10
11[ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) is an [ExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-extensionAbility.md) component of the SERVICE type that provides capabilities related to background services. It holds an internal [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md), which provides a variety of APIs for external systems.
12
13In this document, the component that starts or connects to a ServiceExtensionAbility is called the client, and the ServiceExtensionAbility is called the server.
14
15A ServiceExtensionAbility can be started or connected by other components to process transactions in the background based on the request of the caller. System applications can call the [startServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#startserviceextensionability) method to start background services or call the [connectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability) method to connect to background services. Third-party applications can call only **connectServiceExtensionAbility()** to connect to background services. The differences between starting and connecting to a ServiceExtensionAbility are as follows:
16
17- **Starting**: In the case that AbilityA starts ServiceB, they are weakly associated. After AbilityA exits, ServiceB remains running.
18
19- **Connecting**: In the case that AbilityA connects to ServiceB, they are strongly associated. After AbilityA exits, ServiceB also exits.
20
21Note the following:
22
23- If a ServiceExtensionAbility is started only by means of connecting, its lifecycle is controlled by the client. A new connection is set up each time the client calls the **connectServiceExtensionAbility()** method. When the client exits or calls the [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectserviceextensionability) method, the connection is interrupted. After all connections are interrupted, the ServiceExtensionAbility automatically exits.
24
25- Once a ServiceExtensionAbility is started by means of starting, it will not exit automatically. System applications can call the [stopServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#stopserviceextensionability) method to stop it.
26
27- The connection or disconnection operation can be performed only in the main thread, but not in the **Worker** and **TaskPool** threads.
28
29> **NOTE**
30>
31> Currently, third-party applications cannot implement a ServiceExtensionAbility. To implement transaction processing in the background, they can use [background tasks](../task-management/background-task-overview.md).
32>
33> A UIAbility of a third-party application can connect to a ServiceExtensionAbility provided by a system application through the context.
34>
35> Third-party applications can connect to a ServiceExtensionAbility provided by a system application only when they gain focus in the foreground.
36
37## Lifecycle
38
39The [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) class provides the lifecycle callbacks [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#oncreate), [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onrequest), [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect), [onDisconnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#ondisconnect), and [onDestroy()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#ondestroy). Override them as required. The following figure shows the ServiceExtensionAbility lifecycle.
40
41**Figure 1** ServiceExtensionAbility lifecycle
42
43![ServiceExtensionAbility-lifecycle](figures/ServiceExtensionAbility-lifecycle.png)
44
45- **onCreate**
46
47  This callback is triggered when a ServiceExtensionAbility is created for the first time. You can perform initialization operations, for example, registering a common event listener.
48
49  > **NOTE**
50  >
51  > If a ServiceExtensionAbility has been created, starting it again does not trigger the **onCreate()** callback.
52
53- **onRequest**
54
55  This callback is triggered when another component calls the [startServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#startserviceextensionability) method to start a ServiceExtensionAbility. After being started, the ServiceExtensionAbility runs in the background. This callback is triggered each time the **startServiceExtensionAbility()** method is called.
56
57- **onConnect**
58
59  This callback is triggered when another component calls the [connectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability) method to connect to a ServiceExtensionAbility. In this method, a remote proxy object, namely, [IRemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#iremoteobject), is returned, through which the client communicates with the server by means of RPC. At the same time, the system stores the IRemoteObject. If another component calls the **connectServiceExtensionAbility()** method to connect to this ServiceExtensionAbility, the system returns the saved IRemoteObject, without triggering the callback.
60
61- **onDisconnect**
62
63  This callback is triggered when the last connection is interrupted. A connection is interrupted when the client exits or [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectserviceextensionability) is called.
64
65- **onDestroy**
66
67  This callback is triggered when a ServiceExtensionAbility is no longer used and the instance is ready for destruction. You can clear resources in this callback, for example, deregistering the listener.
68
69## Implementing a Background Service (for System Applications Only)
70
71### Preparations
72
73Only system applications can implement a [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md). You must make the following preparations before development:
74
75- **Switching to the full SDK**: All the APIs provided by the **ServiceExtensionAbility** class are marked as system APIs and hidden by default. Therefore, you must manually obtain the full SDK from the mirror and switch to it in DevEco Studio. For details, see [Switching to Full SDK](../faqs/full-sdk-switch-guide.md).
76
77- **Requesting the AllowAppUsePrivilegeExtension privilege**: Only applications with the **AllowAppUsePrivilegeExtension** privilege can implement a ServiceExtensionAbility. For details about how to request the privilege, see [Application Privilege Configuration](../../device-dev/subsystems/subsys-app-privilege-config-guide.md).
78
79### Defining IDL APIs
80
81As a background service, a ServiceExtensionAbility needs to provide APIs that can be called by external systems. You can define the APIs in IDL files and use the [IDL tool](../IDL/idl-guidelines.md) to generate proxy and stub files. The following demonstrates how to define a file named **IIdlServiceExt.idl**:
82
83```cpp
84interface OHOS.IIdlServiceExt {
85  int ProcessData([in] int data);
86  void InsertDataToMap([in] String key, [in] int val);
87}
88```
89
90Create the **IdlServiceExt** directory in the **ets** directory of a module in a DevEco Studio project, and copy the files generated by the [IDL tool](../IDL/idl-guidelines.md) to this directory. Then create a file named **idl_service_ext_impl.ts** to implement the IDL APIs.
91
92```
93├── ets
94│ ├── IdlServiceExt
95│ │   ├── i_idl_service_ext.ts      # File generated by the IDL tool.
96│ │   ├── idl_service_ext_proxy.ts  # File generated by the IDL tool.
97│ │   ├── idl_service_ext_stub.ts   # File generated by the IDL tool.
98│ │   ├── idl_service_ext_impl.ts   # Customize this file to implement IDL APIs.
99│ └
100101```
102
103An example of **idl_service_ext_impl.ts** is as follows:
104
105```ts
106import IdlServiceExtStub from './idl_service_ext_stub';
107import hilog from '@ohos.hilog';
108import type { insertDataToMapCallback } from './i_idl_service_ext';
109import type { processDataCallback } from './i_idl_service_ext';
110
111const ERR_OK = 0;
112const TAG: string = "[IdlServiceExtImpl]";
113const DOMAIN_NUMBER: number = 0xFF00;
114
115// You need to implement APIs in this type.
116export default class ServiceExtImpl extends IdlServiceExtStub {
117  processData(data: number, callback: processDataCallback): void {
118    // Implement service logic.
119    hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`);
120    callback(ERR_OK, data + 1); // The verification is successful, and service logic is executed normally.
121  }
122
123  insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
124    // Implement service logic.
125    hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key}  val: ${val}`);
126    callback(ERR_OK);
127  }
128}
129```
130
131### Creating a ServiceExtensionAbility
132
133To manually create a ServiceExtensionAbility in the DevEco Studio project, perform the following steps:
134
1351. In the **ets** directory of a module in the project, right-click and choose **New > Directory** to create a directory named **ServiceExtAbility**.
136
1372. In the **ServiceExtAbility** directory, right-click and choose **New > ArkTS File** to create a file named **ServiceExtAbility.ets**.
138
139    ```
140    ├── ets
141    │ ├── IdlServiceExt
142    │ │   ├── i_idl_service_ext.ets      # File generated by the IDL tool.
143    │ │   ├── idl_service_ext_proxy.ets  # File generated by the IDL tool.
144    │ │   ├── idl_service_ext_stub.ets   # File generated by the IDL tool.
145    │ │   ├── idl_service_ext_impl.ets   # Customize this file to implement IDL APIs.
146    │ ├── ServiceExtAbility
147    │ │   ├── ServiceExtAbility.ets
148149    ```
150
1513. In the **ServiceExtAbility.ets** file, import the [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) module. Customize a class that inherits from ServiceExtensionAbility and implement the lifecycle callbacks. Return the previously defined ServiceExtImpl object in the [onConnect](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#oncreate) lifecycle callback.
152
153    ```ts
154    import { ServiceExtensionAbility, Want } from '@kit.AbilityKit';
155    import { rpc } from '@kit.IPCKit';
156    import { hilog } from '@kit.PerformanceAnalysisKit';
157    import ServiceExtImpl from '../IdlServiceExt/idl_service_ext_impl';
158
159    const TAG: string = '[ServiceExtAbility]';
160    const DOMAIN_NUMBER: number = 0xFF00;
161
162    export default class ServiceExtAbility extends ServiceExtensionAbility {
163      serviceExtImpl: ServiceExtImpl = new ServiceExtImpl('ExtImpl');
164
165      onCreate(want: Want): void {
166        let serviceExtensionContext = this.context;
167        hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`);
168      };
169
170      onRequest(want: Want, startId: number): void {
171        hilog.info(DOMAIN_NUMBER, TAG, `onRequest, want: ${want.abilityName}`);
172      };
173
174      onConnect(want: Want): rpc.RemoteObject {
175        hilog.info(DOMAIN_NUMBER, TAG, `onConnect, want: ${want.abilityName}`);
176        // Return the ServiceExtImpl object, through which the client can communicate with the ServiceExtensionAbility.
177        return this.serviceExtImpl as rpc.RemoteObject;
178      };
179
180      onDisconnect(want: Want): void {
181        hilog.info(DOMAIN_NUMBER, TAG, `onDisconnect, want: ${want.abilityName}`);
182      };
183
184      onDestroy(): void {
185        hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');
186      };
187    };
188    ```
189
1904. Register the ServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) of the module in the project. Set **type** to **"service"** and **srcEntry** to the code path of the ServiceExtensionAbility component.
191
192    ```json
193    {
194      "module": {
195        // ...
196        "extensionAbilities": [
197          {
198            "name": "ServiceExtAbility",
199            "icon": "$media:icon",
200            "description": "service",
201            "type": "service",
202            "exported": true,
203            "srcEntry": "./ets/ServiceExtAbility/ServiceExtAbility.ets"
204          }
205        ]
206      }
207    }
208    ```
209
210## Starting a Background Service (for System Applications Only)
211
212A system application uses the [startServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#startserviceextensionability) method to start a background service. The [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onrequest) callback is invoked, through which the background service receives the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object passed by the caller. After the background service is started, its lifecycle is independent of the client. In other words, even if the client is destroyed, the background service remains alive. Therefore, the background service must be stopped by calling [terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md#serviceextensioncontextterminateself) when its work is complete. Alternatively, another component can call [stopServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#stopserviceextensionability) to stop the background service.
213
214> **NOTE**
215>
216> **startServiceExtensionAbility()**, **stopServiceExtensionAbility()**, and **terminateSelf()** provided by the **ServiceExtensionContext** class are system APIs and cannot be called by third-party applications.
217
2181. Start a new [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) in a system application. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
219
220    ```ts
221    import { common, Want } from '@kit.AbilityKit';
222    import { hilog } from '@kit.PerformanceAnalysisKit';
223    import { BusinessError } from '@kit.BasicServicesKit';
224
225    const TAG: string = '[Page_ServiceExtensionAbility]';
226    const DOMAIN_NUMBER: number = 0xFF00;
227
228    @Entry
229    @Component
230    struct Page_ServiceExtensionAbility {
231      build() {
232        Column() {
233          //...
234          List({ initialIndex: 0 }) {
235            ListItem() {
236              Row() {
237                //...
238              }
239              .onClick(() => {
240                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
241                let want: Want = {
242                  deviceId: '',
243                  bundleName: 'com.samples.stagemodelabilitydevelop',
244                  abilityName: 'ServiceExtAbility'
245                };
246                context.startServiceExtensionAbility(want).then(() => {
247                  hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ServiceExtensionAbility.');
248                  // The background service is started.
249                  this.getUIContext().getPromptAction().showToast({
250                    message: 'SuccessfullyStartBackendService'
251                  });
252                }).catch((err: BusinessError) => {
253                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
254                });
255              })
256            }
257            //...
258          }
259          //...
260        }
261        //...
262      }
263    }
264    ```
265
2662. Stop the [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) in the system application.
267
268    ```ts
269    import { common, Want } from '@kit.AbilityKit';
270    import { hilog } from '@kit.PerformanceAnalysisKit';
271    import { BusinessError } from '@kit.BasicServicesKit';
272
273    const TAG: string = '[Page_ServiceExtensionAbility]';
274    const DOMAIN_NUMBER: number = 0xFF00;
275
276    @Entry
277    @Component
278    struct Page_ServiceExtensionAbility {
279      build() {
280        Column() {
281          //...
282          List({ initialIndex: 0 }) {
283            ListItem() {
284              Row() {
285                //...
286              }
287              .onClick(() => {
288                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
289                let want: Want = {
290                  deviceId: '',
291                  bundleName: 'com.samples.stagemodelabilitydevelop',
292                  abilityName: 'ServiceExtAbility'
293                };
294                context.stopServiceExtensionAbility(want).then(() => {
295                  hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in stopping ServiceExtensionAbility.');
296                  this.getUIContext().getPromptAction().showToast({
297                    message: 'SuccessfullyStoppedAStartedBackendService'
298                  });
299                }).catch((err: BusinessError) => {
300                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to stop ServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
301                });
302              })
303            }
304            //...
305          }
306          //...
307        }
308        //...
309      }
310    }
311    ```
312
3133. Enable the [ServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md) to stop itself.
314
315    ```ts
316    import { common } from '@kit.AbilityKit';
317    import { hilog } from '@kit.PerformanceAnalysisKit';
318    import { BusinessError } from '@kit.BasicServicesKit';
319
320    const TAG: string = '[Page_ServiceExtensionAbility]';
321    const DOMAIN_NUMBER: number = 0xFF00;
322
323    @Entry
324    @Component
325    struct Page_ServiceExtensionAbility {
326      build() {
327        Column() {
328          //...
329          List({ initialIndex: 0 }) {
330            ListItem() {
331              Row() {
332                //...
333              }
334              .onClick(() => {
335                let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
336                context.terminateSelf().then(() => {
337                  hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in terminating self.');
338                  // The background service is stopped.
339                  this.getUIContext().getPromptAction().showToast({
340                    message: 'SuccessfullyStopStartedBackendService'
341                  });
342                }).catch((err: BusinessError) => {
343                  hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`);
344                });
345              })
346            }
347            //...
348          }
349          //...
350        }
351        //...
352      }
353    }
354    ```
355
356> **NOTE**
357>
358> Background services remain alive in the background for a long time. To minimize resource usage, destroy a background service in time in either of the following ways when it finishes the requested task:
359>
360> - The background service calls the [terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md#serviceextensioncontextterminateself) method to automatically stop itself.
361> - Another component calls the [stopServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext-sys.md#stopserviceextensionability) method to stop the background service.
362> After either method is called, the system destroys the background service.
363
364## Connecting to a Background Service
365
366Either a system application or a third-party application can connect to a background service (specified in the Want object) through [connectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability). The [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) callback is invoked, through which the background service receives the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object passed by the caller. In this way, a persistent connection is established.
367
368The ServiceExtensionAbility returns an [IRemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#iremoteobject) in the **onConnect()** callback. Through this IRemoteObject, you can define communication interfaces for RPC interaction between the client and server. Multiple clients can simultaneously connect to the same background service. After a client finishes the interaction, it must call [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectserviceextensionability) to disconnect from the service. If all clients connected to a background service are disconnected, the system destroys the service.
369
370- Call [connectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability) to establish a connection to a background service. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
371
372  ```ts
373  import { common, Want } from '@kit.AbilityKit';
374  import { rpc } from '@kit.IPCKit';
375  import { hilog } from '@kit.PerformanceAnalysisKit';
376  // The client needs to import idl_service_ext_proxy.ts provided by the server to the local project.
377  import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy';
378
379  const TAG: string = '[Page_ServiceExtensionAbility]';
380  const DOMAIN_NUMBER: number = 0xFF00;
381
382  let connectionId: number;
383  let want: Want = {
384    deviceId: '',
385    bundleName: 'com.samples.stagemodelabilitydevelop',
386    abilityName: 'ServiceExtAbility'
387  };
388
389  let options: common.ConnectOptions = {
390    onConnect(elementName, remote: rpc.IRemoteObject): void {
391      hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
392      if (remote === null) {
393        hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
394        return;
395      }
396      let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote);
397      // Communication is carried out by API calling, without exposing RPC details.
398      serviceExtProxy.processData(1, (errorCode: number, retVal: number) => {
399        hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`);
400      });
401      serviceExtProxy.insertDataToMap('theKey', 1, (errorCode: number) => {
402        hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, errorCode: ${errorCode}`);
403      })
404    },
405    onDisconnect(elementName): void {
406      hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
407    },
408    onFailed(code: number): void {
409      hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code));
410    }
411  };
412  @Entry
413  @Component
414  struct Page_ServiceExtensionAbility {
415    build() {
416      Column() {
417        //...
418        List({ initialIndex: 0 }) {
419          ListItem() {
420            Row() {
421              //...
422            }
423            .onClick(() => {
424              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
425              // The ID returned after the connection is set up must be saved. The ID will be used for disconnection.
426              connectionId = context.connectServiceExtensionAbility(want, options);
427              // The background service is connected.
428              this.getUIContext().getPromptAction().showToast({
429                message: 'SuccessfullyConnectBackendService'
430              });
431              // connectionId = context.connectAbility(want, options);
432              hilog.info(DOMAIN_NUMBER, TAG, `connectionId is : ${connectionId}`);
433            })
434          }
435          //...
436        }
437        //...
438      }
439      //...
440    }
441  }
442  ```
443
444- Call [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectserviceextensionability) to disconnect from the background service.
445
446  ```ts
447  import { common } from '@kit.AbilityKit';
448  import { hilog } from '@kit.PerformanceAnalysisKit';
449  import { BusinessError } from '@kit.BasicServicesKit';
450
451  const TAG: string = '[Page_ServiceExtensionAbility]';
452  const DOMAIN_NUMBER: number = 0xFF00;
453
454  let connectionId: number;
455  @Entry
456  @Component
457  struct Page_ServiceExtensionAbility {
458    build() {
459      Column() {
460        //...
461        List({ initialIndex: 0 }) {
462          ListItem() {
463            Row() {
464              //...
465            }
466            .onClick(() => {
467              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
468              // connectionId is returned when connectServiceExtensionAbility is called and needs to be manually maintained.
469              context.disconnectServiceExtensionAbility(connectionId).then(() => {
470                hilog.info(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility success');
471                // The background service is disconnected.
472                this.getUIContext().getPromptAction().showToast({
473                  message: 'SuccessfullyDisconnectBackendService'
474                });
475              }).catch((error: BusinessError) => {
476                hilog.error(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility failed');
477              });
478            })
479          }
480          //...
481        }
482        //...
483      }
484      //...
485    }
486  }
487  ```
488
489## Communication Between the Client and Server
490
491After obtaining the [rpc.IRemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#iremoteobject) from the [onConnect()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#onconnect) lifecycle callback, the client can communicate with the ServiceExtensionAbility in either of the following ways:
492
493- Using the IDL APIs provided by the server for communication (recommended)
494
495  ```ts
496  // The client needs to import idl_service_ext_proxy.ts provided by the server to the local project.
497  import { common } from '@kit.AbilityKit';
498  import { rpc } from '@kit.IPCKit';
499  import { hilog } from '@kit.PerformanceAnalysisKit';
500  import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy';
501
502  const TAG: string = '[Page_ServiceExtensionAbility]';
503  const DOMAIN_NUMBER: number = 0xFF00;
504
505  let options: common.ConnectOptions = {
506    onConnect(elementName, remote: rpc.IRemoteObject): void {
507      hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
508      if (remote === null) {
509        hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
510        return;
511      }
512      let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote);
513      // Communication is carried out by API calling, without exposing RPC details.
514      serviceExtProxy.processData(1, (errorCode: number, retVal: number) => {
515        hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`);
516      });
517      serviceExtProxy.insertDataToMap('theKey', 1, (errorCode: number) => {
518        hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, errorCode: ${errorCode}`);
519      })
520    },
521    onDisconnect(elementName): void {
522      hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
523    },
524    onFailed(code: number): void {
525      hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code));
526    }
527  };
528  ```
529
530- Calling [sendMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#sendmessagerequest9) to send messages to the server (not recommended)
531
532  ```ts
533  import { common } from '@kit.AbilityKit';
534  import { rpc } from '@kit.IPCKit';
535  import { hilog } from '@kit.PerformanceAnalysisKit';
536  import { BusinessError } from '@kit.BasicServicesKit';
537
538  const TAG: string = '[Page_CollaborateAbility]';
539  const DOMAIN_NUMBER: number = 0xFF00;
540  const REQUEST_CODE = 1;
541  let options: common.ConnectOptions = {
542    onConnect(elementName, remote): void {
543      hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
544      if (remote === null) {
545        hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
546        return;
547      }
548      let option = new rpc.MessageOption();
549      let data = new rpc.MessageSequence();
550      let reply = new rpc.MessageSequence();
551
552      data.writeInt(99);
553      // You can send data to the target application for corresponding operations.
554      // @param code Indicates the service request code sent by the client.
555      // @param data Indicates the {@link MessageSequence} object sent by the client.
556      // @param reply Indicates the response message object sent by the remote service.
557      // @param options Specifies whether the operation is synchronous or asynchronous.
558      // @return Returns {@code true} if the operation is successful; returns {@code false} otherwise.
559
560      remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
561        let errCode = reply.readInt(); // Receive the information (100) returned by the target device if the connection is successful.
562        let msg: number = 0;
563        if (errCode === 0) {
564          msg = reply.readInt();
565        }
566        // The background service is connected.
567        hilog.info(DOMAIN_NUMBER, TAG, `sendRequest success, msg: ${msg}`);
568      }).catch((error: BusinessError) => {
569        hilog.info(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`);
570      });
571    },
572    onDisconnect(elementName): void {
573      hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
574    },
575    onFailed(code): void {
576      hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback');
577    }
578  };
579  //...
580  ```
581
582## Client Identity Verification by the Server
583
584When a ServiceExtensionAbility is used to provide sensitive services, the client identity must be verified. You can implement the verification on the IDL stub. For details about the IDL API implementation, see [Defining IDL APIs](#defining-idl-apis). Two verification modes are recommended:
585
586- **Verifying the client identity based on callerUid**
587
588  Call the [getCallingUid()](../reference/apis-ipc-kit/js-apis-rpc.md#getcallinguid) method to obtain the UID of the client, and then call the [getBundleNameByUid()](../reference/apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagergetbundlenamebyuid14) method to obtain the corresponding bundle name. In this way, the client identity is verified. Note that [getBundleNameByUid()](../reference/apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagergetbundlenamebyuid14) is asynchronous, and therefore the server cannot return the verification result to the client. This verification mode applies when the client sends an asynchronous task request to the server. The sample code is as follows:
589
590  ```ts
591  import { bundleManager } from '@kit.AbilityKit';
592  import { rpc } from '@kit.IPCKit';
593  import { hilog } from '@kit.PerformanceAnalysisKit';
594  import { BusinessError } from '@kit.BasicServicesKit';
595  import IdlServiceExtStub from './idl_service_ext_stub';
596  import type { InsertDataToMapCallback } from './i_idl_service_ext';
597  import type { ProcessDataCallback } from './i_idl_service_ext';
598
599  const ERR_OK = 0;
600  const ERR_DENY = -1;
601  const TAG: string = "[IdlServiceExtImpl]";
602  const DOMAIN_NUMBER: number = 0xFF00;
603
604  // You need to implement APIs in this type.
605  export default class ServiceExtImpl extends IdlServiceExtStub {
606    processData(data: number, callback: ProcessDataCallback): void {
607      // Implement service logic.
608      hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`);
609      let callerUid = rpc.IPCSkeleton.getCallingUid();
610      bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
611        hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
612        // Identify the bundle name of the client.
613        if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // The verification fails.
614          hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
615          return;
616        }
617        // The verification is successful, and service logic is executed normally.
618      }).catch((err: BusinessError) => {
619        hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
620      });
621      //...
622    };
623
624    insertDataToMap(key: string, val: number, callback: InsertDataToMapCallback): void {
625      // Implement service logic.
626      hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key}  val: ${val}`);
627      callback(ERR_OK);
628    };
629  };
630  ```
631
632- **Verifying the client identity based on callerTokenId**
633
634  Call the [getCallingTokenId()](../reference/apis-ipc-kit/js-apis-rpc.md#getcallingtokenid8) method to obtain the token ID of the client, and then call the [verifyAccessTokenSync()](../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#verifyaccesstokensync9) method to check whether the client has the required permission. Currently, the system does not support permission customization. Therefore, only [system-defined permissions](../security/AccessToken/app-permissions.md) can be verified. The sample code is as follows:
635
636  ```ts
637  import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
638  import { rpc } from '@kit.IPCKit';
639  import { hilog } from '@kit.PerformanceAnalysisKit';
640  import { BusinessError } from '@kit.BasicServicesKit';
641  import IdlServiceExtStub from './idl_service_ext_stub';
642  import type { InsertDataToMapCallback } from './i_idl_service_ext';
643  import type { ProcessDataCallback } from './i_idl_service_ext';
644
645  const ERR_OK = 0;
646  const ERR_DENY = -1;
647  const TAG: string = '[IdlServiceExtImpl]';
648  const DOMAIN_NUMBER: number = 0xFF00;
649
650  // You need to implement APIs in this type.
651  export default class ServiceExtImpl extends IdlServiceExtStub {
652    processData(data: number, callback: ProcessDataCallback): void {
653      // Implement service logic.
654      hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`);
655
656      let callerUid = rpc.IPCSkeleton.getCallingUid();
657      bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
658        hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
659        // Identify the bundle name of the client.
660        if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // The verification fails.
661          hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
662          return;
663        }
664        // The verification is successful, and service logic is executed normally.
665      }).catch((err: BusinessError) => {
666        hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
667      });
668
669      let callerTokenId = rpc.IPCSkeleton.getCallingTokenId();
670      let accessManger = abilityAccessCtrl.createAtManager();
671      // The permission to be verified varies depending on the service requirements. ohos.permission.GET_BUNDLE_INFO_PRIVILEGED is only an example.
672      let grantStatus = accessManger.verifyAccessTokenSync(callerTokenId, 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED');
673      if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
674        hilog.info(DOMAIN_NUMBER, TAG, 'PERMISSION_DENIED');
675        callback(ERR_DENY, data); // The verification fails and an error is returned.
676        return;
677      }
678      hilog.info(DOMAIN_NUMBER, TAG, 'verify access token success.');
679      callback(ERR_OK, data + 1); // The verification is successful, and service logic is executed normally.
680    };
681
682    insertDataToMap(key: string, val: number, callback: InsertDataToMapCallback): void {
683      // Implement service logic.
684      hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key}  val: ${val}`);
685      callback(ERR_OK);
686    };
687  };
688  ```
689
690