• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using AppServiceExtensionAbility for Background Services
2<!--Kit: Ability Kit-->
3<!--Subsystem: Ability-->
4<!--Owner: @yewei0794-->
5<!--Designer: @jsjzju-->
6<!--Tester: @lixueqing513-->
7<!--Adviser: @huipeizi-->
8
9## Overview
10
11Starting from API version 20, you can use the [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) component to provide backend services. This component is designed primarily for common enterprise applications on 2-in-1 devices, for example, EDR software for network security or MDM software for fleet management.
12
13## Available APIs
14
15You can invoke an AppServiceExtensionAbility from a UIAbility in two ways: starting or connecting. The comparison between the two methods is as follows.
16
17| Invocation Method| API| Description|
18| -------- | -------- | -------- |
19| Start| [startAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startappserviceextensionability20) | After a UIAbility starts an AppServiceExtensionAbility, they have a weak association. The AppServiceExtensionAbility keeps running even after the UIAbility exits.|
20| Connect| [connectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectappserviceextensionability20) | After a UIAbility connects to an AppServiceExtensionAbility, they have a strong association. The AppServiceExtensionAbility exits along with the UIAbility when the latter exits.|
21
22## Constraints
23
24- The AppServiceExtensionAbility takes effect only on 2-in-1 devices.
25
26- To integrate an AppServiceExtensionAbility, applications must request the ACL permission (ohos.permission.SUPPORT_APP_SERVICE_EXTENSION). This ACL permission is available only for enterprise applications.
27
28- If the [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) instance is not started, the caller must be the application to which the [AppServiceExtensionAbility](js-apis-app-ability-appServiceExtensionAbility.md) instance belongs or an application in the application list supported by the AppServiceExtensionAbility instance (configured in the **appIdentifierAllowList** property of [extensionAbilities](../quick-start/module-configuration-file.md#extensionabilities)).
29
30- APIs related to [Window](../reference/apis-arkui/arkts-apis-window.md) cannot be called in the AppServiceExtensionAbility.
31
32## Working Principles
33
34- In this document, the component that starts or connects to an AppServiceExtensionAbility is called the client, and the AppServiceExtensionAbility is called the server.
35
36- If an AppServiceExtensionAbility 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 [connectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectappserviceextensionability20). When the client exits or calls [disconnectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectappserviceextensionability20), the connection is interrupted. After all connections are interrupted, the AppServiceExtensionAbility automatically exits.
37
38- Once an AppServiceExtensionAbility is started by means of starting, it will not exit automatically. Applications can call [stopAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#stopappserviceextensionability20) to stop it.
39
40- When the AppServiceExtensionAbility is started by means of starting and has no active connections, its process may be suspended. For details, see [Introduction to Background Tasks Kit](../task-management/background-task-overview.md).
41
42## Implementing a Background Service
43
44### Creating a Background Service
45
46To manually create an AppServiceExtensionAbility in the DevEco Studio project, perform the following steps:
47
481. In the **ets** directory of a module in the project, right-click and choose **New > Directory** to create a directory named **AppServiceExtAbility**.
49
502. Right-click the **AppServiceExtAbility** directory, and choose **New > ArkTS File** to create a file named **AppServiceExtAbility.ets**.
51
52    ```
53    ├── ets
54    │ ├── AppServiceExtAbility
55    │ │   ├── AppServiceExtAbility.ets
5657    ```
58
593. In the **AppServiceExtAbility.ets** file, import the [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) module. Customize a class that inherits from AppServiceExtensionAbility and implement the lifecycle callbacks.
60
61    ```ts
62    import { AppServiceExtensionAbility, Want } from '@kit.AbilityKit';
63    import { rpc } from '@kit.IPCKit';
64    import { hilog } from '@kit.PerformanceAnalysisKit';
65
66    const TAG: string = '[AppServiceExtAbility]';
67    const DOMAIN_NUMBER: number = 0xFF00;
68
69    class StubTest extends rpc.RemoteObject {
70      constructor(des: string) {
71        super(des);
72      }
73    }
74
75    export default class AppServiceExtAbility extends AppServiceExtensionAbility {
76      onCreate(want: Want): void {
77        let appServiceExtensionContext = this.context;
78        hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`);
79      };
80
81      onRequest(want: Want, startId: number): void {
82        hilog.info(DOMAIN_NUMBER, TAG, `onRequest, want: ${want.abilityName}`);
83      };
84
85      onConnect(want: Want): rpc.RemoteObject {
86        hilog.info(DOMAIN_NUMBER, TAG, `onConnect, want: ${want.abilityName}`);
87        return new StubTest("test");
88      };
89
90      onDisconnect(want: Want): void {
91        hilog.info(DOMAIN_NUMBER, TAG, `onDisconnect, want: ${want.abilityName}`);
92      };
93
94      onDestroy(): void {
95        hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');
96      };
97    };
98    ```
99
1004. Register the AppServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) of the module in the project. Set **type** to **"appService"** and **srcEntry** to the code path of the AppServiceExtensionAbility component.
101
102    ```json
103    {
104      "module": {
105        // ...
106        "extensionAbilities": [
107          {
108            "name": "AppServiceExtAbility",
109            "icon": "$media:icon",
110            "description": "appService",
111            "type": "appService",
112            "exported": true,
113            "srcEntry": "./ets/AppServiceExtAbility/AppServiceExtAbility.ets"
114          }
115        ]
116      }
117    }
118    ```
119
120### Starting a Background Service
121
122An application uses [startAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startappserviceextensionability20) to start a background service. The [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.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-appServiceExtensionContext.md#terminateself) when its work is complete. Alternatively, another component can call [stopAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#stopappserviceextensionability20) to stop the background service.
123
124
125- Start a new [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) in an application. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
126
127  ```ts
128  import { common, Want } from '@kit.AbilityKit';
129  import { hilog } from '@kit.PerformanceAnalysisKit';
130  import { BusinessError } from '@kit.BasicServicesKit';
131
132  const TAG: string = '[Page_AppServiceExtensionAbility]';
133  const DOMAIN_NUMBER: number = 0xFF00;
134
135  @Entry
136  @Component
137  struct Page_AppServiceExtensionAbility {
138    build() {
139      Column() {
140        //...
141        List({ initialIndex: 0 }) {
142          ListItem() {
143            Row() {
144              //...
145            }
146            .onClick(() => {
147              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
148              let want: Want = {
149                deviceId: '',
150                bundleName: 'com.samples.stagemodelabilitydevelop',
151                abilityName: 'AppServiceExtAbility'
152              };
153              context.startAppServiceExtensionAbility(want).then(() => {
154                hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting AppServiceExtensionAbility.');
155                // The background service is started.
156                this.getUIContext().getPromptAction().showToast({
157                  message: 'SuccessfullyStartBackendService'
158                });
159              }).catch((err: BusinessError) => {
160                hilog.error(DOMAIN_NUMBER, TAG,
161                  `Failed to start AppServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
162              });
163            })
164          }
165
166          //...
167        }
168
169        //...
170      }
171
172      //...
173    }
174  }
175  ```
176
177- Stop the [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) in the application.
178
179  ```ts
180  import { common, Want } from '@kit.AbilityKit';
181  import { hilog } from '@kit.PerformanceAnalysisKit';
182  import { BusinessError } from '@kit.BasicServicesKit';
183
184  const TAG: string = '[Page_AppServiceExtensionAbility]';
185  const DOMAIN_NUMBER: number = 0xFF00;
186
187  @Entry
188  @Component
189  struct Page_AppServiceExtensionAbility {
190    build() {
191      Column() {
192        //...
193        List({ initialIndex: 0 }) {
194          ListItem() {
195            Row() {
196              //...
197            }
198            .onClick(() => {
199              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
200              let want: Want = {
201                deviceId: '',
202                bundleName: 'com.samples.stagemodelabilitydevelop',
203                abilityName: 'AppServiceExtAbility'
204              };
205              context.stopAppServiceExtensionAbility(want).then(() => {
206                hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in stopping AppServiceExtensionAbility.');
207                this.getUIContext().getPromptAction().showToast({
208                  message: 'SuccessfullyStoppedAStartedBackendService'
209                });
210              }).catch((err: BusinessError) => {
211                hilog.error(DOMAIN_NUMBER, TAG,
212                  `Failed to stop AppServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`);
213              });
214            })
215          }
216
217          //...
218        }
219
220        //...
221      }
222
223      //...
224    }
225  }
226  ```
227
228- Enable the [AppServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.md) to stop itself.
229
230    ```ts
231    import { AppServiceExtensionAbility } from '@kit.AbilityKit';
232    import { BusinessError } from '@kit.BasicServicesKit';
233    import { hilog } from '@kit.PerformanceAnalysisKit';
234
235    const TAG: string = '[AppServiceExtensionAbility]';
236
237    export default class AppServiceExtension extends AppServiceExtensionAbility {
238      onCreate() {
239      // Execute the service logic.
240        this.context.terminateSelf().then(() => {
241          hilog.info(0x0000, TAG, '----------- terminateSelf succeed -----------');
242        }).catch((error: BusinessError) => {
243          hilog.error(0x0000, TAG, `terminateSelf failed, error.code: ${error.code}, error.message: $   {error.message}`);
244        });
245      }
246    }
247    ```
248
249### Connecting to a Background Service
250
251The client can connect to a background service (specified in the Want object) through [connectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectappserviceextensionability20). The [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-appServiceExtensionAbility.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 client. In this way, a persistent connection is established.
252
253The AppServiceExtensionAbility returns an [IRemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#iremoteobject) object in [onConnect()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#onconnect). This object is then delivered as an input parameter to the client's [onConnect()](../reference/apis-ability-kit/js-apis-inner-ability-connectOptions.md#onconnect). 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 [disconnectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectappserviceextensionability20) to disconnect from the service. If all clients connected to a background service are disconnected, the system destroys the service.
254
255- Call [connectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectappserviceextensionability20) 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).
256
257  ```ts
258  import { common, Want } from '@kit.AbilityKit';
259  import { rpc } from '@kit.IPCKit';
260  import { hilog } from '@kit.PerformanceAnalysisKit';
261
262  const TAG: string = '[Page_AppServiceExtensionAbility]';
263  const DOMAIN_NUMBER: number = 0xFF00;
264
265  let connectionId: number;
266  let want: Want = {
267    deviceId: '',
268    bundleName: 'com.samples.stagemodelabilitydevelop',
269    abilityName: 'AppServiceExtAbility'
270  };
271
272  let options: common.ConnectOptions = {
273    onConnect(elementName, remote: rpc.IRemoteObject): void {
274      hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
275      if (remote === null) {
276        hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
277        return;
278      }
279      // Use remote for communication.
280    },
281    onDisconnect(elementName): void {
282      hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
283    },
284    onFailed(code: number): void {
285      hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code));
286    }
287  };
288
289  @Entry
290  @Component
291  struct Page_AppServiceExtensionAbility {
292    build() {
293      Column() {
294        //...
295        List({ initialIndex: 0 }) {
296          ListItem() {
297            Row() {
298              //...
299            }
300            .onClick(() => {
301              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
302              // Save the connection ID, which will be used when the background service is disconnected.
303              connectionId = context.connectAppServiceExtensionAbility(want, options);
304              // The background service is connected.
305              this.getUIContext().getPromptAction().showToast({
306                message: 'SuccessfullyConnectBackendService'
307              });
308              hilog.info(DOMAIN_NUMBER, TAG, `connectionId is : ${connectionId}`);
309            })
310          }
311
312          //...
313        }
314
315        //...
316      }
317
318      //...
319    }
320  }
321  ```
322
323- Use [disconnectAppServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectappserviceextensionability20) to disconnect from the background service.
324
325  ```ts
326  import { common } from '@kit.AbilityKit';
327  import { hilog } from '@kit.PerformanceAnalysisKit';
328  import { BusinessError } from '@kit.BasicServicesKit';
329
330  const TAG: string = '[Page_AppServiceExtensionAbility]';
331  const DOMAIN_NUMBER: number = 0xFF00;
332
333  let connectionId: number;
334
335  @Entry
336  @Component
337  struct Page_AppServiceExtensionAbility {
338    build() {
339      Column() {
340        //...
341        List({ initialIndex: 0 }) {
342          ListItem() {
343            Row() {
344              //...
345            }
346            .onClick(() => {
347              let context = this.getUIContext().getHostContext() as common.UIAbilityContext; // UIAbilityContext
348              // connectionId is returned when connectServiceExtensionAbility is called and needs to be manually maintained.
349              context.disconnectAppServiceExtensionAbility(connectionId).then(() => {
350                hilog.info(DOMAIN_NUMBER, TAG, 'disconnectAppServiceExtensionAbility success');
351                // The background service is disconnected.
352                this.getUIContext().getPromptAction().showToast({
353                  message: 'SuccessfullyDisconnectBackendService'
354                });
355              }).catch((error: BusinessError) => {
356                hilog.error(DOMAIN_NUMBER, TAG, 'disconnectAppServiceExtensionAbility failed');
357              });
358            })
359          }
360
361          //...
362        }
363
364        //...
365      }
366
367      //...
368    }
369  }
370  ```
371
372## Communication Between the Client and Server
373
374After 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 AppServiceExtensionAbility.
375
376Call [sendMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#sendmessagerequest9) to send messages to the server.
377
378```ts
379import { common } from '@kit.AbilityKit';
380import { rpc } from '@kit.IPCKit';
381import { hilog } from '@kit.PerformanceAnalysisKit';
382import { BusinessError } from '@kit.BasicServicesKit';
383
384const TAG: string = '[Page_CollaborateAbility]';
385const DOMAIN_NUMBER: number = 0xFF00;
386const REQUEST_CODE = 1;
387let options: common.ConnectOptions = {
388  onConnect(elementName, remote): void {
389    hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
390    if (remote === null) {
391      hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);
392      return;
393    }
394    let option = new rpc.MessageOption();
395    let data = new rpc.MessageSequence();
396    let reply = new rpc.MessageSequence();
397
398    data.writeInt(99);
399    // You can send data to the target application for corresponding operations.
400    // @param code Indicates the service request code sent by the client.
401    // @param data Indicates the {@link MessageSequence} object sent by the client.
402    // @param reply Indicates the response message object sent by the remote service.
403    // @param options Specifies whether the operation is synchronous or asynchronous.
404    // @return Returns {@code true} if the operation is successful; returns {@code false} otherwise.
405
406    remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
407      let errCode = reply.readInt(); // Receive the information (100) returned by the target device if the connection is successful.
408      let msg: number = 0;
409      if (errCode === 0) {
410        msg = reply.readInt();
411      }
412      // The background service is connected.
413      hilog.info(DOMAIN_NUMBER, TAG, `sendRequest success, msg:${msg}`);
414    }).catch((error: BusinessError) => {
415      hilog.info(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`);
416    });
417  },
418  onDisconnect(elementName): void {
419    hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
420  },
421  onFailed(code): void {
422    hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback');
423  }
424};
425// Call the code related to connectAppServiceExtension.
426```
427
428## Client Identity Verification by the Server
429
430If your AppServiceExtensionAbility provides sensitive operations, verify the client's identity with one of the following approaches.
431
432<!--Del-->
433### Verifying the Client Identity Based on callerUid
434
435Call [getCallingUid()](../reference/apis-ipc-kit/js-apis-rpc.md#getcallinguid) to obtain the UID of the client, and then call [getBundleNameByUid()](../reference/apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagergetbundlenamebyuid14) 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:
436
437```ts
438import { AppServiceExtensionAbility } from '@kit.AbilityKit';
439import { bundleManager } from '@kit.AbilityKit';
440import { rpc } from '@kit.IPCKit';
441import { hilog } from '@kit.PerformanceAnalysisKit';
442import { BusinessError } from '@kit.BasicServicesKit';
443
444const TAG: string = "[AppServiceExtImpl]";
445const DOMAIN_NUMBER: number = 0xFF00;
446
447// You need to implement APIs in this class.
448class Stub extends rpc.RemoteObject {
449  onRemoteMessageRequest(
450    code: number,
451    data: rpc.MessageSequence,
452    reply: rpc.MessageSequence,
453    options: rpc.MessageOption): boolean | Promise<boolean> {
454    // Implement service logic.
455    let callerUid = rpc.IPCSkeleton.getCallingUid();
456    bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
457      hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
458      // Identify the bundle name of the client.
459      if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // The verification fails.
460        hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
461        return;
462      }
463      // The verification is successful, and service logic is executed normally.
464    }).catch((err: BusinessError) => {
465      hilog.error(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
466    });
467    return true;
468  }
469}
470
471export default class AppServiceExtension extends AppServiceExtensionAbility {
472  onConnect(want: Want): rpc.RemoteObject {
473      return new Stub('test');
474  }
475  // Other lifecycle states.
476}
477```
478<!--DelEnd-->
479
480### Verifying the Client Identity Based on callerTokenId
481
482Call [getCallingTokenId()](../reference/apis-ipc-kit/js-apis-rpc.md#getcallingtokenid8) to obtain the token ID of the client, and then call [verifyAccessTokenSync()](../reference/apis-ability-kit/js-apis-abilityAccessCtrl.md#verifyaccesstokensync9) 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:
483
484```ts
485import { AppServiceExtensionAbility } from '@kit.AbilityKit';
486import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
487import { rpc } from '@kit.IPCKit';
488import { hilog } from '@kit.PerformanceAnalysisKit';
489import { BusinessError } from '@kit.BasicServicesKit';
490
491const TAG: string = '[AppServiceExtImpl]';
492const DOMAIN_NUMBER: number = 0xFF00;
493
494// You need to implement APIs in this class.
495
496class Stub extends rpc.RemoteObject {
497  onRemoteMessageRequest(
498    code: number,
499    data: rpc.MessageSequence,
500    reply: rpc.MessageSequence,
501    options: rpc.MessageOption): boolean | Promise<boolean> {
502    // Implement service logic.
503    hilog.info(DOMAIN_NUMBER, TAG, `onRemoteMessageRequest: ${data}`);
504    let callerUid = rpc.IPCSkeleton.getCallingUid();
505    bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
506      hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
507      // Identify the bundle name of the client.
508      if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // The verification fails.
509        hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
510        return;
511      }
512    // The verification is successful, and service logic is executed normally.
513    }).catch((err: BusinessError) => {
514      hilog.error(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
515    });
516
517    let callerTokenId = rpc.IPCSkeleton.getCallingTokenId();
518    let accessManger = abilityAccessCtrl.createAtManager();
519    // The permission to be verified varies depending on the service requirements. ohos.permission.GET_BUNDLE_INFO_PRIVILEGED is only an example.
520    let grantStatus = accessManger.verifyAccessTokenSync(callerTokenId, 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED');
521    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
522      hilog.error(DOMAIN_NUMBER, TAG, 'PERMISSION_DENIED');
523      return false;
524    }
525    hilog.info(DOMAIN_NUMBER, TAG, 'verify access token success.');
526    return true;
527  }
528}
529
530export default class AppServiceExtension extends AppServiceExtensionAbility {
531  onConnect(want: Want): rpc.RemoteObject {
532      return new Stub('test');
533  }
534  // Other lifecycle states.
535}
536```
537