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