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