To effectively reduce power consumption and ensure smooth user experience, the system manages background apps, including suspending and terminating processes. When an app is playing music or navigating, it will automatically run in the background if the user switches the app to the background, locks the screen, or switches to another app. The system provides a standard background task mechanism to ensure that apps can properly run in the background. This topic describes common issues and corresponding solutions for background apps, and provides guidance for you to effectively use background tasks to handle freezing scenarios by analyzing app development cases in the following scenarios: short-term switchover between the foreground and background and long-term running in the background.
Background Standards
The system strictly manages the resources used by apps that are switched to the background. The specific measures include process suspension and termination. If background processing is not performed, apps may run improperly. For details about the constraints and suggestions, see the following official guides and best practices:
For standard-system devices, the following types of constrained background tasks are provided: transient tasks, continuous tasks, deferred tasks, and agent-powered reminders. You can select an appropriate background task type to keep your app running after it moves to the background.

The table below describes these background tasks from different dimensions.
Application Scenario | Concept | Common Issues | Background App Status | Task Type |
|---|---|---|---|---|
No background task executed | The app does not execute any task and is switched to the background. | - | The app is suspended within several seconds. | No background |
Small file download, caching, and information sending | Tasks that have high requirements on real-time performance and can be completed in a short period of time | The app is switched to background for a short period of time, and the process is suspended. | Within the one-time quota, the app is not suspended until the task is canceled. If the one-time quota times out and the task is not canceled, the app process will be terminated. | Transient task |
Data transfer, audio playback, recording, positioning and navigation, Bluetooth-related tasks, WLAN-related tasks, multi-device connection, voice and video calls, and computing tasks | Background tasks that are perceivable and need to run for a long time | The app is interrupted after running in the background for a long time. | The app will not be suspended until the task is canceled. If the app process is not canceled when the task ends, the process will be terminated. | Continuous task |
Software update, information collection, and data processing | Tasks that do not have high requirements on real-time performance and can be executed later. If the conditions are met, the task is placed in the execution queue and will be scheduled by the system based on the memory and power consumption. | - | The app is suspended after it is switched to the background. If the preset conditions are met, the system starts the app in a unified manner and creates an Extension process to execute the task. A single callback can run for a maximum of 2 minutes. If the callback is not canceled when it times out, the system terminates the corresponding Extension process. | Deferred task |
Alarm clocks, countdown timer, and calendar events | System agent-powered reminder | - | The app is suspended or the process is terminated. When the conditions are met, the system sends reminders on behalf of the app. | Agent-powered reminder |
For service scenarios like small-file download/cache and message sending, if an app is briefly switched to the background (causing process suspension) and then back to the foreground, the service code logic in the foreground and background periodic callback will cause app abnormalities. In this case, you can request a transient task to solve this problem. The following uses the message sending scenario as an example to describe how to use ApplicationContext to subscribe to the callback for the app switchover between the foreground and background to request a transient task when the app is switched to the background. This solves the problem that the app fails to send messages due to a short switchover.

export interface SuspendTaskInfo {
id: number; // Short-time task ID
delayTime: number; // The remaining time of this request short assignment
} NavDestination() {
// ...
}
.title(this.builderTitle())
.onAppear(() => {
this.shortTermTaskModel.subscribeStateChange();
this.taskTimer = setInterval(() => {
this.messageCount++;
hilog.info(0x0000, TAG, `already sent :${this.messageCount} messages`);
}, 2000);
}) // Apply front - and back-end status monitoring
subscribeStateChange() {
let that = this;
// Obtain applicationContext.
let applicationContext = this.context.getApplicationContext();
let applicationStateChangeCallback: ApplicationStateChangeCallback = {
onApplicationForeground() {
hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationForeground');
},
onApplicationBackground() {
hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationBackground');
// Apply for short-time tasks when the application changes from foreground to background
that.suspendTaskInfo = SuspendTaskUtils.requestSuspendDelay('Suspend Task');
hilog.info(0x0000, TAG,
`requestSuspendDelay, id:${that.suspendTaskInfo.id}, delayTime:${that.suspendTaskInfo.delayTime}`);
}
}
try {
// Registers the background and pre - application status monitoring through applicationContext
applicationContext.on('applicationStateChange', applicationStateChangeCallback);
} catch (paramError) {
hilog.error(0x0000, TAG,
`error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
}
} /**
*
* @param reason Set the delay task suspension reason
* @returns
*/
requestSuspendDelay(reason: string): SuspendTaskInfo {
let id: number; // Apply for a short-time task ID
let delayTime: number; // The remaining time of this request short assignment
try {
// Request deferred task
let delayInfo = backgroundTaskManager.requestSuspendDelay(reason, () => {
// This function is used to call back the application when a short task requested by the application is about to time out.
hilog.info(0x0000, TAG, `Request suspension delay will time out.`);
backgroundTaskManager.cancelSuspendDelay(delayInfo.requestId);
})
id = delayInfo.requestId;
delayTime = delayInfo.actualDelayTime;
let taskInfo = {
id: id,
delayTime: delayTime
} as SuspendTaskInfo;
return taskInfo;
} catch (err) {
let taskInfo = {
id: 0,
delayTime: 0
} as SuspendTaskInfo;
return taskInfo;
}
} async getRemainingDelayTime(id: number): Promise<number> {
let delayTime: number = -1;
await backgroundTaskManager.getRemainingDelayTime(id).then((res: number) => {
delayTime = res;
hilog.info(0x0000, TAG, 'Operation getRemainingDelayTime succeeded. Data: ' + JSON.stringify(res));
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, 'Operation getRemainingDelayTime failed. Cause: ' + err.code);
});
return delayTime;
} cancelSuspendDelay(id: number): boolean {
try {
backgroundTaskManager.cancelSuspendDelay(id);
hilog.info(0x0000, TAG, 'cancelSuspendDelay succeeded.');
} catch (err) {
hilog.error(0x0000, TAG, `cancelSuspendDelay failed. Cause: ${JSON.stringify(err)}`);
return false;
}
return true;
} Demo


When an app involves multiple scenarios, such as data transfer, audio playback, recording, positioning and navigation, Bluetooth-related task, WLAN-related task, multi-device connection, voice and video calls, and complex computing tasks, the app needs to run in the background for a long period of time. To ensure a proper app running in the background, you can request a continuous task. The following example uses a continuous task to manage the location service of an app. In this way, the app can continuously obtain the location information of a device when the app is running in the background for a long period of time.

{
"module": {
// ...
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
// ...
"backgroundModes": [
'location'
]
}
],
// ...
"requestPermissions": [
{
"name": "ohos.permission.LOCATION",
// ...
},
{
"name": "ohos.permission.LOCATION_IN_BACKGROUND",
// ...
},
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
// ...
},
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
// ...
}
]
}
} // Apply for location-related permissions
requestPermissionsFromUser(): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let permissionList: Permissions[] = [
'ohos.permission.INTERNET',
'ohos.permission.LOCATION',
'ohos.permission.APPROXIMATELY_LOCATION'
];
atManager.requestPermissionsFromUser(this.context, permissionList)
.then((data: PermissionRequestResult) => {
hilog.info(0x0000, TAG, `data: ${JSON.stringify(data)}`);
})
.catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `requestPermissionsFromUser fail: ${JSON.stringify(err)}`);
});
} locationCallback = async (location: geoLocationManager.Location) => {
hilog.info(0x0000, TAG, `locationCallback: data: ${JSON.stringify(location)}`);
};
// Get the location
async getLocation() {
let request: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.FIRST_FIX, // Quick location acquisition is preferred
scenario: geoLocationManager.LocationRequestScenario.UNSET, // Indicates that no scenario information is set
timeInterval: 1, // Interval for reporting the location information
distanceInterval: 0, // Distance for reporting location information
maxAccuracy: 100 // The precision value required when the application requests location information from the system
};
try {
geoLocationManager.on('locationChange', request, this.locationCallback);
} catch (err) {
hilog.error(0x0000, TAG, `errCode: ${JSON.stringify(err)}`);
}
} // Start a long task
startLongTask(): void {
let wantAgentInfo: wantAgent.WantAgentInfo = {
wants: [
{
bundleName: this.context.abilityInfo.bundleName,
abilityName: this.context.abilityInfo.name
}
],
actionType: wantAgent.OperationType.START_ABILITY,
requestCode: 0,
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
try {
// wantAgent object is obtained by getWantAgent method in WantAgent module
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
backgroundTaskManager.startBackgroundRunning(this.context, backgroundTaskManager.BackgroundMode.LOCATION,
wantAgentObj)
.then(() => {
hilog.info(0x0000, TAG, `Operation startBackgroundRunning succeeded`);
})
.catch((error: BusinessError) => {
hilog.error(0x0000, TAG,
`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);
});
});
} catch (error) {
hilog.error(0x0000, TAG, `Operation getWantAgent failed. error is ${JSON.stringify(error)} `);
}
} geoLocationManager.off('locationChange'); // Stop a long task
stopLongTask(): void {
backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
hilog.info(0x0000, TAG, `Operation stopBackgroundRunning succeeded`);
}).catch((error: BusinessError) => {
hilog.error(0x0000, TAG, `Operation stopBackgroundRunning failed. error is ${JSON.stringify(error)} `);
});
} Demo

