Understanding App Standby Buckets
App Standby Buckets, introduced in Android 9 (Pie), provide a dynamic power management system that prioritizes system resources based on how frequently and recently the user interacts with an app. Instead of a binary "active" or "standby" state, the system places apps into discrete buckets, applying progressively stricter restrictions on background operations.
The Standby Buckets
The UsageStatsManager categorizes apps into one of five primary buckets.
1. Active
An app is in the Active bucket if the user is currently using it or interacted with it very recently.
- Examples: An activity is in the foreground, a foreground service is running, or the user taps a notification from the app.
- Restrictions: None. The app can run jobs, trigger alarms, and access the network freely.
2. Working Set
An app is in the Working Set if it runs often but is not currently active.
- Examples: A social media app the user checks several times a day.
- Restrictions: Mild restrictions. Background jobs and alarms may be slightly delayed.
3. Frequent
An app is in the Frequent bucket if it is used regularly but not necessarily every day.
- Examples: A workout tracking app used 3-4 times a week.
- Restrictions: Stronger restrictions. Network access and background jobs are deferred to longer intervals. Exact alarms are limited.
4. Rare
An app is in the Rare bucket if it is rarely used.
- Examples: A hotel booking app used only during vacations.
- Restrictions: Severe restrictions. Background jobs, network access, and alarms are highly constrained. The system caps their background execution to rare maintenance windows.
5. Restricted
Introduced in Android 12, this bucket is for apps that consume excessive system resources in the background or exhibit buggy behavior.
- Restrictions: Maximum restrictions. The app is almost entirely prevented from running in the background unless launched by the user.
Bucket Assignment Algorithm
The bucket assignment is handled by the AppStandbyController within the system server. It uses machine learning models (often powered by the Device Personalization Services) and heuristics to predict user behavior.
Key factors influencing bucket assignment:
- Time since last launch.
- Frequency of launches.
- User interaction with notifications.
- Active foreground services.
// Querying the current standby bucket programmatically
UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
int currentBucket = usageStatsManager.getAppStandbyBucket();
switch (currentBucket) {
case UsageStatsManager.STANDBY_BUCKET_ACTIVE:
// App is active
break;
case UsageStatsManager.STANDBY_BUCKET_RARE:
// App is rarely used, expect severe delays for background work
break;
}
Job and Alarm Restrictions
The framework enforces bucket policies primarily through the JobScheduler and AlarmManager.
- JobScheduler: The system determines how many jobs an app can run per day based on its bucket. Rare apps might only get a few execution windows a day.
- AlarmManager: Alarms (even
setExact) are deferred. Frequent apps might be capped at a few exact alarms per hour, while Rare apps are capped at a few per day.
Testing and Debugging
Developers must test their applications across all standby buckets to ensure core functionality doesn't break when restricted.
Using ADB for Testing
You can manually force an app into a specific bucket using ADB commands:
# Make an app Rare
adb shell am set-standby-bucket com.example.myapp rare
# Make an app Active
adb shell am set-standby-bucket com.example.myapp active
# View the current bucket for all apps
adb shell am get-standby-bucket --all
By understanding and designing for App Standby Buckets, developers ensure their applications remain functional without becoming battery drains when the user isn't actively engaging with them.