Android 9 (API level 28) and higher support App Standby Buckets. App Standby Buckets help the system prioritize apps' requests for resources based on how recently and how frequently the apps are used. Based on app usage patterns, each app is placed in one of five priority buckets. The system limits the device resources available to each app based on which bucket the app is in.
Priority buckets
The system dynamically assigns each app to a priority bucket, reassigning the apps as needed. The system may rely on a preloaded app that uses machine learning to determine how likely each app is to be used, and assigns apps to the appropriate buckets. If the system app is not present on a device, the system defaults to sorting apps based on how recently they were used. More active apps are assigned to buckets that give the apps higher priority, making more system resources available to the app. In particular, the bucket determines how frequently the app's jobs run, and how often the app can trigger alarms. These restrictions apply only while the device is on battery power; the system does not impose these restrictions on apps while the device is charging.
Note: Every manufacturer can set their own criteria for how non-active apps are
assigned to buckets. You should not try to influence which bucket your app is
assigned to. Instead, focus on making sure your app behaves well in whatever
bucket it might be in. Your app can find out what bucket it's currently in by
calling
UsageStatsManager.getAppStandbyBucket()
.
The buckets are:
- Active: App is currently being used or was very recently used.
- Working set: App is in regular use.
- Frequent: App is often used, but not every day.
- Rare: App is not frequently used.
- Restricted: App consumes a great deal of system resources, or may exhibit undesirable behavior.
In addition, there's a special never bucket for apps that have been installed but have never been run. The system imposes severe restrictions on these apps.
Note: Apps that are on the Doze exemption list are exempted from the App Standby Bucket-based restrictions.
Note: The descriptions below are for the non-predictive case. By contrast, when the prediction uses machine learning to predict behavior, buckets are chosen in anticipation of the user's next actions rather than based on recency of usage. For example, a recently used app could end up in the rare bucket because machine learning predicts that the app won't be used for several hours.
Active
An app is in the active bucket if the user is currently using the app or very recently used the app. For example:
- The app has launched an activity
- The app is running a foreground service
- The app has a sync adapter associated with a content provider used by a foreground app
- The user clicks on a notification from the app
If an app is in the active bucket, the system does not place any restrictions on the app's jobs or alarms.
User interaction places apps in the "active" bucket
On Android 9 (API level 28) and higher, when the user interacts with your app in certain ways, the system temporarily places your app into the active bucket. Some time after the user stops interacting with your app, the system places it into a bucket based on usage history.
Examples of interactions that trigger this system behavior include the following:
The user taps on a notification that your app sends.
The user interacts with a foreground service in your app by pressing a media button.
The user connects to your app while interacting with Android Automotive OS, where your app uses either a foreground service or
CONNECTION_TYPE_PROJECTION
.
Working set
An app is in the working set bucket if it runs often but it is not currently active. For example, a social media app that the user launches most days is likely to be in the working set. Apps are also promoted to the working set bucket if they're used indirectly.
If an app is in the working set, the system imposes mild restrictions on its ability to run jobs and trigger alarms. For details, see Power management restrictions.
Frequent
An app is in the frequent bucket if it is used regularly, but not necessarily every day. For example, a workout-tracking app that the user runs at the gym might be in the frequent bucket.
If an app is in the frequent bucket, the system imposes stronger restrictions on its ability to run jobs and trigger alarms. For details, see Power management restrictions.
Rare
An app is in the rare bucket if it is not often used. For example, a hotel app that the user only runs while they're staying at that hotel might be in the rare bucket.
If an app is in the rare bucket, the system imposes strict restrictions on its ability to run jobs and trigger alarms. The system also limits the app's ability to connect to the internet. For details, see Power management restrictions.
Restricted
This bucket, added in Android 12 (API level 31), has the lowest priority (and the highest restrictions) of all the buckets. The system considers your app's behavior, such as how often the user interacts with it, to decide whether to place your app in the restricted bucket.
On Android 13 (API level 33) and higher, unless your app qualifies for an exemption, the system places your app in the restricted bucket in the following situations:
The user doesn't interact with your app for a specific number of days. On Android 12 (API level 31) and 12L (API level 32), the number of days is 45. Android 13 reduces this number to 8.
Your app invokes an excessive number of broadcasts or bindings during a 24-hour period.
If the system places your app in the restricted bucket, the following restrictions apply:
- You can run jobs once per day, in
a 10-minute batched session. During this session, the system groups your app's
jobs with other apps' jobs.
- Restricted jobs are not run by themselves – there must be at least one other job running/pending at the same time, which can include any other job.
- Your app can run fewer expedited jobs, compared to when the system places your app in a less-restrictive bucket.
- Your app can invoke one alarm per day. This alarm can be either an exact alarm or an inexact alarm.
Exemptions from entering the restricted bucket
The following types of apps are exempt from entering the "restricted" App Standby Bucket, and they bypass the inactivity trigger, even on Android 12 and higher:
- Companion device apps
- Apps running on a device in Demo Mode
- Device owner apps
- Profile owner apps
- Persistent apps
- VPN apps
- Apps that have the
ROLE_DIALER
role - Apps that the user has explicitly designated to provide "unrestricted" functionality in system settings
- Apps that have active widgets
- Apps that are visible in picture-in-picture (PiP) mode
- Apps that are one of the active apps on screen
- Apps that are granted at least one of the following permissions:
Best practices
If your app is already following best practices for Doze and app standby, handling the new power management features should not be difficult. However, some app behaviors which previously worked well might now cause problems.
- Do not try to manipulate the system into putting your app into one bucket or another. The system's bucketing methods can change, and every device manufacturer could choose to write their own bucketing app with its own algorithm. Instead, make sure your app behaves appropriately no matter which bucket it's in.
- If an app does not have a launcher activity, it might never be promoted to the active bucket. You might want to redesign your app to have such an activity.
- If the app's notifications aren't actionable, users won't be able to trigger the app's promotion to the active bucket by interacting with the notifications. In this case, you may want to redesign some appropriate notifications so they allow a response from the user. For some guidelines, see the Material Design Notifications design patterns.
- Similarly, if the app doesn't show a notification upon receiving a
high-priority
Firebase Cloud Messaging (FCM) message, it won't give the user a chance to
interact with the app and thus promote it to the active bucket. In fact, the
only intended use for high priority FCM messages is to push a notification to
the user, so this situation shouldn't occur. On 12L (API level 32)
and lower, if you inappropriately mark an FCM message as high priority when it
doesn't trigger user interaction, it can cause future messages to be
deprioritized.
Note: If the user repeatedly dismisses a notification, the system gives the user the option of blocking that notification in the future. Do not spam the user with notifications just to try to keep your app in the active bucket!
- If apps are split across multiple packages, those packages might be in different buckets and, thus, have different access levels. You should be sure to test such apps with the packages assigned to various buckets to make sure the app behaves properly.
Testing
To check which bucket your app has been placed into, do one of the following:
- Call
getAppStandbyBucket()
. -
Run the following command in a terminal window:
adb shell am get-standby-bucket PACKAGE_NAME
The system throttles your app whenever it's placed in an App Standby Bucket
whose value is greater than
STANDBY_BUCKET_ACTIVE
(10).