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| Example Scenario| 20| -------- | -------- | -------- | 21| DATA_TRANSFER | Data transfer| The browser downloads a large file in the background.| 22| AUDIO_PLAYBACK | Audio playback| A music application plays music in the background.| 23| AUDIO_RECORDING | Audio recording| A recorder records audio in the background.| 24| LOCATION | Positioning and navigation| A navigation application provides navigation in the background.| 25| BLUETOOTH_INTERACTION | Bluetooth-related task| Transfer a file through Bluetooth.| 26| MULTI_DEVICE_CONNECTION | Multi-device connection| Carry out distributed service connection.| 27| WIFI_INTERACTION | WLAN-related task (for system applications only)| Transfer a file over Wi-Fi.| 28| VOIP | Voice and video calls (for system applications only)| Use a system chat application to make an audio call in the background.| 29| TASK_KEEPING | Computing task (for specific devices only)| 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 ```ts 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 wantAgent from '@ohos.app.ability.wantAgent'; 88 ``` 89 904. Request and cancel a continuous task. 91 92 - 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. 93 94 - 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). 95 96 The code snippet below shows how an application requests a continuous task for itself. 97 98 ```ts 99 @Entry 100 @Component 101 struct Index { 102 @State message: string = 'ContinuousTask'; 103 // Use getContext to obtain the context of the UIAbility for the page. 104 private context = getContext(this); 105 106 startContinuousTask() { 107 let wantAgentInfo = { 108 // List of operations to be executed after the notification is clicked. 109 wants: [ 110 { 111 bundleName: "com.example.myapplication", 112 abilityName: "com.example.myapplication.MainAbility" 113 } 114 ], 115 // Type of the operation to perform after the notification is clicked. 116 operationType: wantAgent.OperationType.START_ABILITY, 117 // Custom request code. 118 requestCode: 0, 119 // Execution attribute of the operation to perform after the notification is clicked. 120 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 121 }; 122 123 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 124 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 125 try { 126 backgroundTaskManager.startBackgroundRunning(this.context, 127 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 128 console.info(`Succeeded in operationing startBackgroundRunning.`); 129 }).catch((err) => { 130 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 131 }); 132 } catch (error) { 133 console.error(`Failed to start background running. Code is ${error.code} message is ${error.message}`); 134 } 135 }); 136 } 137 138 stopContinuousTask() { 139 try { 140 backgroundTaskManager.stopBackgroundRunning(this.context).then(() => { 141 console.info(`Succeeded in operationing stopBackgroundRunning.`); 142 }).catch((err) => { 143 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 144 }); 145 } catch (error) { 146 console.error(`Failed to stop background running. Code is ${error.code} message is ${error.message}`); 147 } 148 } 149 150 build() { 151 Row() { 152 Column() { 153 Text("Index") 154 .fontSize(50) 155 .fontWeight(FontWeight.Bold) 156 157 Button() { 158 Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold) 159 } 160 .type(ButtonType.Capsule) 161 .margin({ top: 10 }) 162 .backgroundColor('#0D9FFB') 163 .width(250) 164 .height(40) 165 .onClick(() => { 166 // Request a continuous task by clicking a button. 167 this.startContinuousTask(); 168 169 // Execute the continuous task logic, for example, music playback. 170 }) 171 172 Button() { 173 Text ('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold) 174 } 175 .type(ButtonType.Capsule) 176 .margin({ top: 10 }) 177 .backgroundColor('#0D9FFB') 178 .width(250) 179 .height(40) 180 .onClick(() => { 181 // Stop the continuous task. 182 183 // Cancel the continuous task by clicking a button. 184 this.stopContinuousTask(); 185 }) 186 } 187 .width('100%') 188 } 189 .height('100%') 190 } 191 } 192 ``` 193 194 The code snippet below shows how an application requests a continuous task across devices or applications. 195 196 ```ts 197 import UIAbility from '@ohos.app.ability.UIAbility'; 198 199 const MSG_SEND_METHOD: string = 'CallSendMsg' 200 201 let mContext = null; 202 203 function startContinuousTask() { 204 let wantAgentInfo = { 205 // List of operations to be executed after the notification is clicked. 206 wants: [ 207 { 208 bundleName: "com.example.myapplication", 209 abilityName: "com.example.myapplication.MainAbility", 210 } 211 ], 212 // Type of the operation to perform after the notification is clicked. 213 operationType: wantAgent.OperationType.START_ABILITY, 214 // Custom request code. 215 requestCode: 0, 216 // Execution attribute of the operation to perform after the notification is clicked. 217 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 218 }; 219 220 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 221 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 222 try { 223 backgroundTaskManager.startBackgroundRunning(mContext, 224 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 225 console.info(`Succeeded in operationing startBackgroundRunning.`); 226 }).catch((err) => { 227 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 228 }); 229 } catch (err) { 230 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 231 } 232 }); 233 } 234 235 function stopContinuousTask() { 236 try { 237 backgroundTaskManager.stopBackgroundRunning(mContext).then(() => { 238 console.info(`Succeeded in operationing stopBackgroundRunning.`); 239 }).catch((err) => { 240 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 241 }); 242 } catch (err) { 243 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 244 } 245 } 246 247 class MyParcelable { 248 num: number = 0; 249 str: String = ''; 250 251 constructor(num, string) { 252 this.num = num; 253 this.str = string; 254 } 255 256 marshalling(messageSequence) { 257 messageSequence.writeInt(this.num); 258 messageSequence.writeString(this.str); 259 return true; 260 } 261 262 unmarshalling(messageSequence) { 263 this.num = messageSequence.readInt(); 264 this.str = messageSequence.readString(); 265 return true; 266 } 267 } 268 269 function sendMsgCallback(data) { 270 console.info('BgTaskAbility funcCallBack is called ' + data) 271 let receivedData = new MyParcelable(0, '') 272 data.readParcelable(receivedData) 273 console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`) 274 // You can execute different methods based on the str value in the sequenceable data sent by the caller object. 275 if (receivedData.str === 'start_bgtask') { 276 startContinuousTask() 277 } else if (receivedData.str === 'stop_bgtask') { 278 stopContinuousTask(); 279 } 280 return new MyParcelable(10, 'Callee test'); 281 } 282 283 export default class BgTaskAbility extends UIAbility { 284 onCreate(want, launchParam) { 285 console.info("[Demo] BgTaskAbility onCreate") 286 this.callee.on('test', sendMsgCallback); 287 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 onDestroy() { 297 console.info('[Demo] BgTaskAbility onDestroy') 298 } 299 300 onWindowStageCreate(windowStage) { 301 console.info('[Demo] BgTaskAbility onWindowStageCreate') 302 303 windowStage.loadContent("pages/index").then((data) => { 304 console.info(`load content succeed with data ${JSON.stringify(data)}`) 305 }).catch((error) => { 306 console.error(`load content failed with error ${JSON.stringify(error)}`) 307 }) 308 } 309 310 onWindowStageDestroy() { 311 console.info('[Demo] BgTaskAbility onWindowStageDestroy') 312 } 313 314 onForeground() { 315 console.info('[Demo] BgTaskAbility onForeground') 316 } 317 318 onBackground() { 319 console.info('[Demo] BgTaskAbility onBackground') 320 } 321 }; 322 ``` 323 324 325### FA Model 326 3271. Start and connect to a ServiceAbility. 328 329 - 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. 330 331 - 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. 332 3332. Configure permissions and declare the continuous task type. 334 335 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. 336 337 338 ```js 339 "module": { 340 "package": "com.example.myapplication", 341 "abilities": [ 342 { 343 "backgroundModes": [ 344 "audioRecording", 345 ], // Background mode 346 "type": "service" // The ability type is Service. 347 } 348 ], 349 "reqPermissions": [ 350 { 351 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission 352 } 353 ] 354 } 355 ``` 356 3573. Import the modules. 358 359 ```js 360 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 361 import featureAbility from '@ohos.ability.featureAbility'; 362 import wantAgent from '@ohos.app.ability.wantAgent'; 363 import rpc from "@ohos.rpc"; 364 ``` 365 3664. Request and cancel a continuous task. In the ServiceAbility, call **startBackgroundRunning()** and **startBackgroundRunning()** to request and cancel a continuous task. 367 368 ```js 369 function startContinuousTask() { 370 let wantAgentInfo = { 371 // List of operations to be executed after the notification is clicked. 372 wants: [ 373 { 374 bundleName: "com.example.myapplication", 375 abilityName: "com.example.myapplication.MainAbility" 376 } 377 ], 378 // Type of the operation to perform after the notification is clicked. 379 operationType: wantAgent.OperationType.START_ABILITY, 380 // Custom request code. 381 requestCode: 0, 382 // Execution attribute of the operation to perform after the notification is clicked. 383 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 384 }; 385 386 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 387 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { 388 try { 389 backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(), 390 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 391 console.info(`Succeeded in operationing startBackgroundRunning.`); 392 }).catch((err) => { 393 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 394 }); 395 } catch (error) { 396 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 397 } 398 }); 399 } 400 401 function stopContinuousTask() { 402 try { 403 backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => { 404 console.info(`Succeeded in operationing stopBackgroundRunning.`); 405 }).catch((err) => { 406 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 407 }); 408 } catch (error) { 409 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 410 } 411 } 412 413 async function processAsyncJobs() { 414 // Execute the continuous task. 415 416 // After the continuous task is complete, call the API to release resources. 417 stopContinuousTask(); 418 } 419 420 let mMyStub; 421 422 class MyStub extends rpc.RemoteObject { 423 constructor(des) { 424 if (typeof des === 'string') { 425 super(des); 426 } else { 427 return null; 428 } 429 } 430 431 onRemoteRequest(code, data, reply, option) { 432 console.log('ServiceAbility onRemoteRequest called'); 433 // Custom request code. 434 if (code === 1) { 435 // Receive the request code for requesting a continuous task. 436 startContinuousTask(); 437 // Execute the continuous task. 438 } else if (code === 2) { 439 // Receive the request code for canceling the continuous task. 440 stopContinuousTask(); 441 } else { 442 console.log('ServiceAbility unknown request code'); 443 } 444 return true; 445 } 446 } 447 448 export default { 449 onStart(want) { 450 console.info('ServiceAbility onStart'); 451 mMyStub = new MyStub("ServiceAbility-test"); 452 // Call the API to start the task. 453 startContinuousTask(); 454 processAsyncJobs(); 455 }, 456 onStop() { 457 console.info('ServiceAbility onStop'); 458 }, 459 onConnect(want) { 460 console.info('ServiceAbility onConnect'); 461 return mMyStub; 462 }, 463 onReconnect(want) { 464 console.info('ServiceAbility onReconnect'); 465 }, 466 onDisconnect() { 467 console.info('ServiceAbility onDisconnect'); 468 }, 469 onCommand(want, restart, startId) { 470 console.info('ServiceAbility onCommand'); 471 } 472 }; 473 ``` 474 475