• 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 and video 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| <!--DelRow-->WIFI_INTERACTION | WLAN-related task (for system applications only)| wifiInteraction  | Transfer a file over WLAN.|
28| <!--DelRow-->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 | <!--RP1-->Computing task (for specific devices only)<!--RP1End--> | taskKeeping  | Run antivirus software.|
30
31- Only applications that use the [network management](../network/net-mgmt-overview.md) service can request a continuous task of the DATA_TRANSFER type to upload and download data in the background and avoid being suspended. If an application calls the [upload and download agent API](../reference/apis-basic-services-kit/js-apis-request.md) to delegate the upload and download task to the system, the application will be suspended regardless of whether it has requested such a continuous task.
32- Only audio and video applications that use [AVSession](../media/avsession/avsession-overview.md) can request a continuous task of the AUDIO_PLAYBACK type to implement background playback.
33
34
35### Constraints
36
37- **Ability restrictions**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks.
38
39- **Quantity restrictions**: 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.
40
41- **Running restrictions**: The system verifies continuous tasks on mobile phones.
42   - Scenario 1: If an application requests a continuous task but does not execute or has finished the task of the requested type, 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 cancels the continuous task.
43   - Scenario 2: If an application does not request a continuous task of a given type but executes such a continuous task, the system performs certain control. For example, if the system detects that an application requests a continuous task of the AUDIO_PLAYBACK type, but the application is playing audio (corresponding to the AUDIO_PLAYBACK type) and recording (corresponding to the AUDIO_RECORDING type), the system performs control on the application.
44   - Scenario 3: If the background load of the process that runs a continuous task is higher than the corresponding typical load for a long period of time, the system performs certain control.
45
46> **NOTE**
47>
48> 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.
49>
50> When an application that plays audio stops a continuous task in the background, it must suspend or stop the audio stream. Otherwise, the application will be forcibly terminated by the system.
51
52## Available APIs
53
54The 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-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md).
55
56**Table 2** Main APIs for continuous tasks
57
58| API| Description|
59| -------- | -------- |
60| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md)): Promise&lt;void&gt; | Requests a continuous task.|
61| stopBackgroundRunning(context: Context): Promise&lt;void&gt; | Cancels a continuous task.|
62
63## How to Develop
64
65The following walks you through how to request a continuous task for recording. In this example, the application provides two buttons: **Request Continuous Task** and **Cancel Continuous Task**.
66- When a user touches **Request Continuous Task**, the application requests a continuous task for recording, and a message is displayed in the notification bar, indicating that a recording task is running.
67- When a user touches **Cancel Continuous Task**, the application cancels the continuous task, and the notification message is removed.
68
69### Stage Model
70
711. Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
72
732. Declare the continuous task type.
74
75   Declare the type of the continuous task for the target UIAbility in the **module.json5** file. (Set the corresponding configuration item in the configuration file.)
76
77   ```json
78    "module": {
79        "abilities": [
80            {
81                "backgroundModes": [
82                 // Configuration item of the continuous task type
83                "audioRecording"
84                ],
85            }
86        ],
87        ...
88    }
89   ```
90
913. Import the modules.
92
93   Import the modules related to continuous tasks: @ohos.resourceschedule.backgroundTaskManager and @ohos.app.ability.wantAgent. Import other modules based on the project requirements.
94
95   ```ts
96    import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
97    import UIAbility from '@ohos.app.ability.UIAbility';
98    import window from '@ohos.window';
99    import AbilityConstant from '@ohos.app.ability.AbilityConstant';
100    import Want from '@ohos.app.ability.Want';
101    import rpc from '@ohos.rpc';
102    import { BusinessError } from '@ohos.base';
103    import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent';
104   ```
105
1064. Request and cancel a continuous task.
107
108   - 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.<!--RP2--><!--RP2End-->
109   <!--Del-->
110   - 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).<!--DelEnd-->
111
112   The code snippet below shows how an application requests a continuous task for itself.
113
114   ```ts
115    @Entry
116    @Component
117    struct Index {
118      @State message: string = 'ContinuousTask';
119     // Use getContext to obtain the context of the UIAbility for the page.
120      private context: Context = getContext(this);
121
122      startContinuousTask() {
123        let wantAgentInfo: wantAgent.WantAgentInfo = {
124          // List of operations to be executed after the notification is clicked.
125          // Add the bundleName and abilityName of the application to start.
126          wants: [
127            {
128              bundleName: "com.example.myapplication",
129              abilityName: "com.example.myapplication.MainAbility"
130            }
131          ],
132          // Specify the action to perform (starting the ability) after the notification message is clicked.
133          actionType: wantAgent.OperationType.START_ABILITY,
134          // Custom request code.
135          requestCode: 0,
136          // Execution attribute of the operation to perform after the notification is clicked.
137          wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
138        };
139
140        // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
141        wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
142           backgroundTaskManager.startBackgroundRunning(this.context,
143             backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
144             console.info(`Succeeded in operationing startBackgroundRunning.`);
145           }).catch((err: BusinessError) => {
146             console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
147           });
148        });
149      }
150
151      stopContinuousTask() {
152         backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
153           console.info(`Succeeded in operationing stopBackgroundRunning.`);
154         }).catch((err: BusinessError) => {
155           console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
156         });
157      }
158
159      build() {
160        Row() {
161          Column() {
162            Text("Index")
163              .fontSize(50)
164              .fontWeight(FontWeight.Bold)
165
166           Button() {
167              Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold)
168            }
169            .type(ButtonType.Capsule)
170            .margin({ top: 10 })
171            .backgroundColor('#0D9FFB')
172            .width(250)
173            .height(40)
174            .onClick(() => {
175              // Request a continuous task by clicking a button.
176              this.startContinuousTask();
177
178              // Execute the continuous task logic, for example, music playback.
179            })
180
181            Button() {
182              Text ('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold)
183            }
184            .type(ButtonType.Capsule)
185            .margin({ top: 10 })
186            .backgroundColor('#0D9FFB')
187            .width(250)
188            .height(40)
189            .onClick(() => {
190              // Stop the continuous task.
191
192              // Cancel the continuous task by clicking a button.
193              this.stopContinuousTask();
194            })
195          }
196          .width('100%')
197        }
198        .height('100%')
199      }
200    }
201   ```
202   <!--Del-->
203   The code snippet below shows how an application requests a continuous task across devices or applications.
204
205   ```ts
206    const MSG_SEND_METHOD: string = 'CallSendMsg'
207
208    let mContext: Context;
209
210    function startContinuousTask() {
211      let wantAgentInfo : wantAgent.WantAgentInfo = {
212        // List of operations to be executed after the notification is clicked.
213        wants: [
214          {
215            bundleName: "com.example.myapplication",
216            abilityName: "com.example.myapplication.MainAbility",
217          }
218        ],
219        // Type of the operation to perform after the notification is clicked.
220        actionType: wantAgent.OperationType.START_ABILITY,
221        // Custom request code.
222        requestCode: 0,
223        // Execution attribute of the operation to perform after the notification is clicked.
224        wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
225      };
226
227      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
228      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => {
229        backgroundTaskManager.startBackgroundRunning(mContext,
230          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
231          console.info(`Succeeded in operationing startBackgroundRunning.`);
232        }).catch((err: BusinessError) => {
233          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
234        });
235      });
236    }
237
238    function stopContinuousTask() {
239      backgroundTaskManager.stopBackgroundRunning(mContext).then(() => {
240        console.info(`Succeeded in operationing stopBackgroundRunning.`);
241      }).catch((err: BusinessError) => {
242        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
243      });
244    }
245
246    class MyParcelable implements rpc.Parcelable {
247      num: number = 0;
248      str: string = '';
249
250      constructor(num: number, string: string) {
251        this.num = num;
252        this.str = string;
253      }
254
255      marshalling(messageSequence: rpc.MessageSequence) {
256        messageSequence.writeInt(this.num);
257        messageSequence.writeString(this.str);
258        return true;
259      }
260
261      unmarshalling(messageSequence: rpc.MessageSequence) {
262        this.num = messageSequence.readInt();
263        this.str = messageSequence.readString();
264        return true;
265      }
266    }
267
268    function sendMsgCallback(data: rpc.MessageSequence) {
269      console.info('BgTaskAbility funcCallBack is called ' + data);
270      let receivedData: MyParcelable = new MyParcelable(0, '');
271      data.readParcelable(receivedData);
272      console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);
273      // You can execute different methods based on the str value in the sequenceable data sent by the caller object.
274      if (receivedData.str === 'start_bgtask') {
275        // Request a continuous task.
276        startContinuousTask();
277      } else if (receivedData.str === 'stop_bgtask') {
278        // Cancel the continuous task.
279        stopContinuousTask();
280      }
281      return new MyParcelable(10, 'Callee test');
282    }
283
284    export default class BgTaskAbility extends UIAbility {
285      // Create an ability.
286      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
287        console.info("[Demo] BgTaskAbility onCreate");
288        try {
289          this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
290        } catch (error) {
291          console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
292        }
293        mContext = this.context;
294      }
295
296      // Destroy an ability.
297      onDestroy() {
298        console.info('[Demo] BgTaskAbility onDestroy');
299      }
300
301      onWindowStageCreate(windowStage: window.WindowStage) {
302        console.info('[Demo] BgTaskAbility onWindowStageCreate');
303
304        windowStage.loadContent('pages/Index', (error, data) => {
305          if (error.code) {
306            console.error(`load content failed with error ${JSON.stringify(error)}`);
307            return;
308          }
309          console.info(`load content succeed with data ${JSON.stringify(data)}`);
310        });
311      }
312
313      onWindowStageDestroy() {
314        console.info('[Demo] BgTaskAbility onWindowStageDestroy');
315      }
316
317      onForeground() {
318        console.info('[Demo] BgTaskAbility onForeground');
319      }
320
321      onBackground() {
322        console.info('[Demo] BgTaskAbility onBackground');
323      }
324    };
325   ```
326   <!--DelEnd-->
327
328### FA Model
329
3301. Start and connect to a ServiceAbility.
331
332   - 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.
333
334   - 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.
335
3362. Configure permissions and declare the continuous task type.
337
338   Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission in the **config.json** file. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). In addition, declare the continuous task type for the ServiceAbility.
339
340   ```json
341   "module": {
342       "package": "com.example.myapplication",
343       "abilities": [
344           {
345               "backgroundModes": [
346               "audioRecording",
347               ], // Background mode
348               "type": "service"  // The ability type is Service.
349           }
350       ],
351       "reqPermissions": [
352           {
353               "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission
354           }
355       ]
356   }
357   ```
358
3593. Import the modules.
360
361   ```js
362    import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager';
363    import featureAbility from '@ohos.ability.featureAbility';
364    import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent';
365    import rpc from "@ohos.rpc";
366    import { BusinessError } from '@ohos.base';
367    import Want from '@ohos.app.ability.Want';
368   ```
369
3704. Request and cancel a continuous task. In the ServiceAbility, call **startBackgroundRunning()** and **stopBackgroundRunning()** to request and cancel a continuous task. Use JS code to implement this scenario.
371
372   ```js
373    function startContinuousTask() {
374      let wantAgentInfo: wantAgent.WantAgentInfo = {
375        // List of operations to be executed after the notification is clicked.
376        wants: [
377          {
378            bundleName: "com.example.myapplication",
379            abilityName: "com.example.myapplication.MainAbility"
380          }
381        ],
382        // Type of the operation to perform after the notification is clicked.
383        actionType: wantAgent.OperationType.START_ABILITY,
384        // Custom request code.
385        requestCode: 0,
386        // Execution attribute of the operation to perform after the notification is clicked.
387        wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
388      };
389
390      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
391      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
392        backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(),
393          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
394          console.info(`Succeeded in operationing startBackgroundRunning.`);
395        }).catch((err: BusinessError) => {
396          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
397        });
398      });
399    }
400
401    function stopContinuousTask() {
402      backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => {
403        console.info(`Succeeded in operationing stopBackgroundRunning.`);
404      }).catch((err: BusinessError) => {
405        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
406      });
407    }
408
409    async function processAsyncJobs() {
410      // Execute the continuous task.
411
412      // After the continuous task is complete, call the API to release resources.
413      stopContinuousTask();
414    }
415
416    let mMyStub: MyStub;
417
418    // Start the service by calling connectAbility().
419    class MyStub extends rpc.RemoteObject {
420      constructor(des: string) {
421        super(des);
422      }
423
424      onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) {
425        console.log('ServiceAbility onRemoteRequest called');
426        // Custom request code.
427        if (code === 1) {
428          // Receive the request code for requesting a continuous task.
429          startContinuousTask();
430          // Execute the continuous task.
431        } else if (code === 2) {
432          // Receive the request code for canceling the continuous task.
433          stopContinuousTask();
434        } else {
435          console.log('ServiceAbility unknown request code');
436        }
437        return true;
438      }
439    }
440
441    // Start the service by calling startAbility().
442    class ServiceAbility {
443      onStart(want: Want) {
444        console.info('ServiceAbility onStart');
445        mMyStub = new MyStub("ServiceAbility-test");
446        // Call the API to start the task.
447        startContinuousTask();
448        processAsyncJobs();
449      }
450
451      onStop() {
452        console.info('ServiceAbility onStop');
453      }
454
455      onConnect(want: Want) {
456        console.info('ServiceAbility onConnect');
457        return mMyStub;
458      }
459
460      onReconnect(want: Want) {
461        console.info('ServiceAbility onReconnect');
462      }
463
464      onDisconnect() {
465        console.info('ServiceAbility onDisconnect');
466      }
467
468      onCommand(want: Want, startId: number) {
469        console.info('ServiceAbility onCommand');
470      }
471    }
472
473    export default new ServiceAbility();
474    ```
475
476