• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Continuous Task
2
3
4## Overview
5
6
7### Introduction
8
9If an application has a perceivable task that needs to run in an extended period of time in the background, it can request a continuous task to prevent itself from being suspended. Examples of continuous tasks include music playback and navigation in the background.
10
11After an application requests a continuous task, the system verifies whether the application is actually executing the continuous task. It also attaches a notification to the continuous task. If the user deletes the notification, the system automatically stops the task.
12
13
14### Use Cases
15
16The table below lists the types of continuous tasks, which are used in various scenarios. You can select a task type suitable for your case based on the description.
17
18**Table 1** Continuous task types
19| Name| Description| Item| Example Scenario|
20| -------- | -------- | -------- | -------- |
21| DATA_TRANSFER | Data transfer| dataTransfer | The browser downloads a large file in the background.|
22| AUDIO_PLAYBACK | Audio playback| audioPlayback | A music application plays music in the background.|
23| AUDIO_RECORDING | Audio recording| audioRecording | A recorder records audio in the background.|
24| LOCATION | Positioning and navigation| location | A navigation application provides navigation in the background.|
25| BLUETOOTH_INTERACTION | Bluetooth-related task| bluetoothInteraction | Transfer a file through Bluetooth.|
26| MULTI_DEVICE_CONNECTION | Multi-device connection| multiDeviceConnection | Carry out distributed service connection.|
27| WIFI_INTERACTION | WLAN-related task (for system applications only)| wifiInteraction  | Transfer a file over WLAN.|
28| VOIP | Voice and video calls (for system applications only)| voip  | Use a system chat application to make an audio call in the background.|
29| TASK_KEEPING | Computing task (for specific devices only)| taskKeeping  | Run antivirus software.|
30
31
32- When an application requests a continuous task of the DATA_TRANSFER type, the system increases the priority of the application process to reduce the probability of terminating the process. However, it still suspends the process. To use the upload and download feature, the application must call the [upload and download agent API](../reference/apis/js-apis-request.md) so that the system functions as the agent.
33- To implement background playback, the application must request an [AV session](../media/avsession-overview.md) in addition to a continuous task of the AUDIO_PLAYBACK type.
34
35
36### Constraints
37
38- **Ability limit**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks.
39
40- **Quantity limit**: A UIAbility (ServiceAbility in the FA model) can request only one continuous task at a time. If a UIAbility has a running continuous task, it can request another one only after the running task is finished. If an application needs to request multiple continuous tasks at the same time, it must create multiple UIAbilities. After a UIAbility requests a continuous task, all the processes of the application are not suspended.
41
42- **Running verification**: The system performs continuous task verification. If an application requests a continuous task but does not execute the task of the requested type or finishes the task, the system performs certain control. For example, if the system detects that an application has requested a continuous task of the AUDIO_PLAYBACK type but does not play audio, the system terminates the application process.
43
44> **NOTE**
45>
46> The application shall proactively cancel a continuous task when it is finished. Otherwise, the system will forcibly cancel the task. For example, when a user taps the UI to pause music playback, the application must cancel the continuous task in a timely manner. When the user taps the UI again to continue music playback, the application needs to request a continuous task.
47
48## Available APIs
49
50The table below uses promise as an example to describe the APIs used for developing continuous tasks. For details about more APIs and their usage, see [Background Task Management](../reference/apis/js-apis-resourceschedule-backgroundTaskManager.md).
51
52**Table 2** Main APIs for continuous tasks
53
54| API| Description|
55| -------- | -------- |
56| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis/js-apis-app-ability-wantAgent.md)): Promise<void> | Requests a continuous task.|
57| stopBackgroundRunning(context: Context): Promise<void> | Cancels a continuous task.|
58
59## How to Develop
60
61### Stage Model
62
631. Request the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
64
652. Declare the continuous task type.
66
67   Declare the continuous task type for the target UIAbility in the **module.json5** file.
68
69
70   ```json
71    "module": {
72        "abilities": [
73            {
74                "backgroundModes": [
75                "audioRecording"
76                ], // Background mode
77            }
78        ],
79        ...
80    }
81   ```
82
833. Import the modules.
84
85   ```ts
86   import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
87   import UIAbility from '@ohos.app.ability.UIAbility';
88   import window from '@ohos.window';
89   import AbilityConstant from '@ohos.app.ability.AbilityConstant';
90   import Want from '@ohos.app.ability.Want';
91   import rpc from '@ohos.rpc';
92   import { BusinessError } from '@ohos.base';
93   import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent';
94   ```
95
964. Request and cancel a continuous task.
97
98   - In the stage model, an application can request a continuous task for itself or another application either on the local device or on a remote device.
99
100   - When a continuous task is executed across devices or applications in the background, the UIAbility can be created and run in the background in call mode. For details, see [Using Call to Implement UIAbility Interaction (for System Applications Only)](../application-models/uiability-intra-device-interaction.md#using-call-to-implement-uiability-interaction-for-system-applications-only) and [Using Cross-Device Call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).
101
102   The code snippet below shows how an application requests a continuous task for itself.
103
104   ```ts
105    @Entry
106    @Component
107    struct Index {
108      @State message: string = 'ContinuousTask';
109     // Use getContext to obtain the context of the UIAbility for the page.
110      private context: Context = getContext(this);
111
112      startContinuousTask() {
113        let wantAgentInfo: wantAgent.WantAgentInfo = {
114          // List of operations to be executed after the notification is clicked.
115          wants: [
116            {
117              bundleName: "com.example.myapplication",
118              abilityName: "com.example.myapplication.MainAbility"
119            }
120          ],
121          // Type of the operation to perform after the notification is clicked.
122          operationType: wantAgent.OperationType.START_ABILITY,
123          // Custom request code.
124          requestCode: 0,
125          // Execution attribute of the operation to perform after the notification is clicked.
126          wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
127        };
128
129        // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
130        wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
131           backgroundTaskManager.startBackgroundRunning(this.context,
132             backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
133             console.info(`Succeeded in operationing startBackgroundRunning.`);
134           }).catch((err: BusinessError) => {
135             console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
136           });
137        });
138      }
139
140      stopContinuousTask() {
141         backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
142           console.info(`Succeeded in operationing stopBackgroundRunning.`);
143         }).catch((err: BusinessError) => {
144           console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
145         });
146      }
147
148      build() {
149        Row() {
150          Column() {
151            Text("Index")
152              .fontSize(50)
153              .fontWeight(FontWeight.Bold)
154
155           Button() {
156              Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold)
157            }
158            .type(ButtonType.Capsule)
159            .margin({ top: 10 })
160            .backgroundColor('#0D9FFB')
161            .width(250)
162            .height(40)
163            .onClick(() => {
164              // Request a continuous task by clicking a button.
165              this.startContinuousTask();
166
167              // Execute the continuous task logic, for example, music playback.
168            })
169
170            Button() {
171              Text ('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold)
172            }
173            .type(ButtonType.Capsule)
174            .margin({ top: 10 })
175            .backgroundColor('#0D9FFB')
176            .width(250)
177            .height(40)
178            .onClick(() => {
179              // Stop the continuous task.
180
181              // Cancel the continuous task by clicking a button.
182              this.stopContinuousTask();
183            })
184          }
185          .width('100%')
186        }
187        .height('100%')
188      }
189    }
190   ```
191
192   The code snippet below shows how an application requests a continuous task across devices or applications.
193
194   ```ts
195   const MSG_SEND_METHOD: string = 'CallSendMsg'
196
197   let mContext: Context;
198
199   function startContinuousTask() {
200     let wantAgentInfo : wantAgent.WantAgentInfo = {
201       // List of operations to be executed after the notification is clicked.
202       wants: [
203         {
204           bundleName: "com.example.myapplication",
205           abilityName: "com.example.myapplication.MainAbility",
206         }
207       ],
208       // Type of the operation to perform after the notification is clicked.
209       operationType: wantAgent.OperationType.START_ABILITY,
210       // Custom request code.
211       requestCode: 0,
212       // Execution attribute of the operation to perform after the notification is clicked.
213       wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
214     };
215
216     // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
217     wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => {
218       backgroundTaskManager.startBackgroundRunning(mContext,
219         backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
220         console.info(`Succeeded in operationing startBackgroundRunning.`);
221       }).catch((err: BusinessError) => {
222         console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
223       });
224     });
225   }
226
227   function stopContinuousTask() {
228     backgroundTaskManager.stopBackgroundRunning(mContext).then(() => {
229       console.info(`Succeeded in operationing stopBackgroundRunning.`);
230     }).catch((err: BusinessError) => {
231       console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
232     });
233   }
234
235   class MyParcelable implements rpc.Parcelable {
236     num: number = 0;
237     str: string = '';
238
239     constructor(num: number, string: string) {
240       this.num = num;
241       this.str = string;
242     }
243
244     marshalling(messageSequence: rpc.MessageSequence) {
245       messageSequence.writeInt(this.num);
246       messageSequence.writeString(this.str);
247       return true;
248     }
249
250     unmarshalling(messageSequence: rpc.MessageSequence) {
251       this.num = messageSequence.readInt();
252       this.str = messageSequence.readString();
253       return true;
254     }
255   }
256
257   function sendMsgCallback(data: rpc.MessageSequence) {
258     console.info('BgTaskAbility funcCallBack is called ' + data);
259     let receivedData: MyParcelable = new MyParcelable(0, '');
260     data.readParcelable(receivedData);
261     console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);
262     // You can execute different methods based on the str value in the sequenceable data sent by the caller object.
263     if (receivedData.str === 'start_bgtask') {
264       startContinuousTask();
265     } else if (receivedData.str === 'stop_bgtask') {
266       stopContinuousTask();
267     }
268     return new MyParcelable(10, 'Callee test');
269   }
270
271   export default class BgTaskAbility extends UIAbility {
272     onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
273       console.info("[Demo] BgTaskAbility onCreate");
274       this.callee.on('test', sendMsgCallback);
275
276       try {
277         this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
278       } catch (error) {
279         console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
280       }
281       mContext = this.context;
282     }
283
284     onDestroy() {
285       console.info('[Demo] BgTaskAbility onDestroy');
286     }
287
288     onWindowStageCreate(windowStage: window.WindowStage) {
289       console.info('[Demo] BgTaskAbility onWindowStageCreate');
290
291       windowStage.loadContent('pages/Index', (error, data) => {
292         if (error.code) {
293           console.error(`load content failed with error ${JSON.stringify(error)}`);
294           return;
295         }
296         console.info(`load content succeed with data ${JSON.stringify(data)}`);
297       });
298     }
299
300     onWindowStageDestroy() {
301       console.info('[Demo] BgTaskAbility onWindowStageDestroy');
302     }
303
304     onForeground() {
305       console.info('[Demo] BgTaskAbility onForeground');
306     }
307
308     onBackground() {
309       console.info('[Demo] BgTaskAbility onBackground');
310     }
311   };
312   ```
313
314### FA Model
315
3161. Start and connect to a ServiceAbility.
317
318   - If no user interaction is required, use **startAbility()** to start the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). In the **onStart** callback of the ServiceAbility, call the APIs to request and cancel continuous tasks.
319
320   - If user interaction is required (for example, in music playback scenarios), use **connectAbility()** to start and connect to the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). After obtaining the agent of the ServiceAbility, the application can communicate with the ServiceAbility and control the request and cancellation of continuous tasks.
321
3222. Configure permissions and declare the continuous task type.
323
324   Configure the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission in the **config.json** file. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file). In addition, declare the continuous task type for the ServiceAbility.
325
326     ```json
327      "module": {
328          "package": "com.example.myapplication",
329          "abilities": [
330              {
331                  "backgroundModes": [
332                  "audioRecording",
333                  ], // Background mode
334                  "type": "service"  // The ability type is Service.
335              }
336          ],
337          "reqPermissions": [
338              {
339                  "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission
340              }
341          ]
342      }
343     ```
344
3453. Import the modules.
346
347     ```js
348     import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
349     import featureAbility from '@ohos.ability.featureAbility';
350     import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent';
351     import rpc from "@ohos.rpc";
352     import { BusinessError } from '@ohos.base';
353     import Want from '@ohos.app.ability.Want';
354     ```
355
3564. Request and cancel a continuous task. In the ServiceAbility, call **startBackgroundRunning()** and **startBackgroundRunning()** to request and cancel a continuous task. Use JS code to implement this scenario.
357
358     ```js
359     function startContinuousTask() {
360       let wantAgentInfo: wantAgent.WantAgentInfo = {
361         // List of operations to be executed after the notification is clicked.
362         wants: [
363           {
364             bundleName: "com.example.myapplication",
365             abilityName: "com.example.myapplication.MainAbility"
366           }
367         ],
368         // Type of the operation to perform after the notification is clicked.
369         operationType: wantAgent.OperationType.START_ABILITY,
370         // Custom request code.
371         requestCode: 0,
372         // Execution attribute of the operation to perform after the notification is clicked.
373         wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
374       };
375
376       // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
377       wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
378         backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(),
379           backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
380           console.info(`Succeeded in operationing startBackgroundRunning.`);
381         }).catch((err: BusinessError) => {
382           console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
383         });
384       });
385     }
386
387     function stopContinuousTask() {
388       backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => {
389         console.info(`Succeeded in operationing stopBackgroundRunning.`);
390       }).catch((err: BusinessError) => {
391         console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
392       });
393     }
394
395     async function processAsyncJobs() {
396       // Execute the continuous task.
397
398       // After the continuous task is complete, call the API to release resources.
399       stopContinuousTask();
400     }
401
402     let mMyStub: MyStub;
403
404     class MyStub extends rpc.RemoteObject {
405       constructor(des: string) {
406         super(des);
407       }
408
409       onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) {
410         console.log('ServiceAbility onRemoteRequest called');
411         // Custom request code.
412         if (code === 1) {
413           // Receive the request code for requesting a continuous task.
414           startContinuousTask();
415           // Execute the continuous task.
416         } else if (code === 2) {
417           // Receive the request code for canceling the continuous task.
418           stopContinuousTask();
419         } else {
420           console.log('ServiceAbility unknown request code');
421         }
422         return true;
423       }
424     }
425
426     class ServiceAbility {
427       onStart(want: Want) {
428         console.info('ServiceAbility onStart');
429         let mMyStub: MyStub = new MyStub("ServiceAbility-test");
430         // Call the API to start the task.
431         startContinuousTask();
432         processAsyncJobs();
433       }
434
435       onStop() {
436         console.info('ServiceAbility onStop');
437       }
438
439       onConnect(want: Want) {
440         console.info('ServiceAbility onConnect');
441         return mMyStub;
442       }
443
444       onReconnect(want: Want) {
445         console.info('ServiceAbility onReconnect');
446       }
447
448       onDisconnect() {
449         console.info('ServiceAbility onDisconnect');
450       }
451
452       onCommand(want: Want, startId: number) {
453         console.info('ServiceAbility onCommand');
454       }
455     }
456
457     export default new ServiceAbility();
458     ```
459
460