Advanced AOSP Subsystems
3 min read

App Standby Buckets

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.