Trevor Johns | 682c24e | 2016-04-12 10:13:47 -0700 | [diff] [blame] | 1 | page.title=Optimizing for Doze and App Standby |
| 2 | page.metaDescription=Test and optimize your app for the power-saving features in Android 6.0. |
| 3 | page.tags=doze, app standby, marshmallow, alarms |
| 4 | meta.tags="battery", "marshmallow", "alarms" |
| 5 | page.image=images/cards/card-doze_16-9_2x.png |
| 6 | |
| 7 | |
| 8 | parent.link=index.html |
| 9 | |
| 10 | trainingnavtop=true |
| 11 | next.title=Monitoring the Battery Level and Charging State |
| 12 | next.link=battery-monitoring.html |
| 13 | @jd:body |
| 14 | |
| 15 | <div id="tb-wrapper"> |
| 16 | <div id="tb"> |
| 17 | <h2>In this document</h2> |
| 18 | <ol> |
| 19 | <li><a href="#understand_doze">Understanding Doze</a> |
| 20 | <ol> |
| 21 | <li><a href="#restrictions">Doze restrictions</a></li> |
| 22 | <li><a href="#assessing_your_app">Adapting your app to Doze</a></li> |
| 23 | </ol> |
| 24 | </li> |
| 25 | <li><a href="#understand_app_standby">Understanding App Standby</a></li> |
| 26 | <li><a href="#using_gcm">Using GCM to Interact with Your App</a></li> |
| 27 | <li><a href="#support_for_other_use_cases">Support for Other Use Cases</a></li> |
| 28 | <li><a href="#testing_doze_and_app_standby">Testing with Doze and App |
| 29 | Standby</a> |
| 30 | <ol> |
| 31 | <li><a href="#testing_doze">Testing your app with Doze</a></li> |
| 32 | <li><a href="#testing_your_app_with_app_standby">Testing your app with App Standby</a></li> |
| 33 | </ol> |
| 34 | </li> |
| 35 | <li><a href="#whitelisting-cases">Acceptable Use Cases for Whitelisting</a></li> |
| 36 | </ol> |
| 37 | </div> |
| 38 | </div> |
| 39 | |
| 40 | <p> |
| 41 | Starting from Android 6.0 (API level 23), Android introduces two |
| 42 | power-saving features that extend battery life for users by managing how apps behave when a |
| 43 | device is not connected to a power source. <em>Doze</em> reduces battery consumption by deferring |
| 44 | background CPU and network activity for apps when the device is unused for long periods |
| 45 | of time. <em>App Standby</em> defers background network activity for apps |
| 46 | with which the user has not recently interacted. |
| 47 | </p> |
| 48 | |
| 49 | <p> |
| 50 | Doze and App Standby manage the behavior of all apps running on Android 6.0 |
| 51 | or higher, regardless whether they are specifically targeting API level 23. |
| 52 | To ensure the best experience for users, test your app in Doze and App |
| 53 | Standby modes and make any necessary adjustments to your code. The sections |
| 54 | below provide details. |
| 55 | </p> |
| 56 | |
| 57 | |
| 58 | <h2 id="understand_doze">Understanding Doze</h2> |
| 59 | <p> |
| 60 | If a user leaves a device unplugged and stationary for a period of time, with |
| 61 | the screen off, the device enters Doze mode. In Doze mode, the system |
| 62 | attempts to conserve battery by restricting apps' access to network and |
| 63 | CPU-intensive services. It also prevents apps from accessing the network and |
| 64 | defers their jobs, syncs, and standard alarms. |
| 65 | </p> |
| 66 | |
| 67 | <p> |
| 68 | Periodically, the system exits Doze for a brief time to let apps complete |
| 69 | their deferred activities. During this <em>maintenance window</em>, the |
| 70 | system runs all pending syncs, jobs, and alarms, and lets apps access the |
| 71 | network. |
| 72 | </p> |
| 73 | |
| 74 | <div style="margin:1em 0em;"> |
| 75 | <img src="{@docRoot}images/training/doze.png"> |
| 76 | <p class="img-caption" style="text-align:center;"> |
| 77 | <strong>Figure 1.</strong> Doze provides a recurring maintenance window for apps to use the |
| 78 | network and handle pending activities. |
| 79 | </p> |
| 80 | </div> |
| 81 | |
| 82 | <p> |
| 83 | At the conclusion of each maintenance window, the system again enters Doze, |
| 84 | suspending network access and deferring jobs, syncs, and alarms. Over time, |
| 85 | the system schedules maintenance windows less and less frequently, helping to |
| 86 | reduce battery consumption in cases of longer-term inactivity when the device is not |
| 87 | connected to a charger. |
| 88 | </p> |
| 89 | |
| 90 | |
| 91 | <p> |
| 92 | As soon as the user wakes the device by moving it, turning on the screen, or |
| 93 | connecting a charger, the system exits Doze and all apps return to normal |
| 94 | activity. |
| 95 | </p> |
| 96 | |
| 97 | |
| 98 | <h3 id="restrictions">Doze restrictions</h3> |
| 99 | |
| 100 | <p> |
| 101 | The following restrictions apply to your apps while in Doze: |
| 102 | </p> |
| 103 | |
| 104 | <ul> |
| 105 | <li>Network access is suspended. |
| 106 | </li> |
| 107 | |
| 108 | <li>The system ignores <a href="{@docRoot}reference/android/os/PowerManager.WakeLock.html"> |
| 109 | wake locks</a>. |
| 110 | </li> |
| 111 | |
| 112 | <li>Standard {@link android.app.AlarmManager} alarms (including {@link |
| 113 | android.app.AlarmManager#setExact(int, long, android.app.PendingIntent) setExact()} and |
| 114 | {@link android.app.AlarmManager#setWindow(int, long, long, |
| 115 | android.app.PendingIntent) setWindow()}) are deferred to the next maintenance window. |
| 116 | </li> |
| 117 | |
| 118 | <li style="list-style: none; display: inline"> |
| 119 | <ul> |
| 120 | <li>If you need to set alarms that fire while in Doze, use {@link |
| 121 | android.app.AlarmManager#setAndAllowWhileIdle(int,long,android.app.PendingIntent) |
| 122 | setAndAllowWhileIdle()} |
| 123 | or {@link android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, |
| 124 | android.app.PendingIntent) setExactAndAllowWhileIdle()}. |
| 125 | </li> |
| 126 | |
| 127 | <li>Alarms set with {@link |
| 128 | android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo, |
| 129 | android.app.PendingIntent) setAlarmClock()} continue to fire normally — the system |
| 130 | exits Doze shortly before those alarms fire. |
| 131 | </li> |
| 132 | </ul> |
| 133 | </li> |
| 134 | |
| 135 | <li>The system does not perform Wi-Fi scans. |
| 136 | </li> |
| 137 | |
| 138 | <li>The system does not allow |
| 139 | <a href="{@docRoot}reference/android/content/AbstractThreadedSyncAdapter.html">sync adapters</a> |
| 140 | to run. |
| 141 | </li> |
| 142 | |
| 143 | <li>The system does not allow {@link android.app.job.JobScheduler} to run. |
| 144 | </li> |
| 145 | </ul> |
| 146 | |
| 147 | |
| 148 | <div id="qv-wrapper"> |
| 149 | <div id="qv" style="width:300px"> |
| 150 | <h2>Doze checklist</h2> |
| 151 | <ol> |
| 152 | <ul> |
| 153 | <li>If possible, use GCM for <a href= |
| 154 | "https://developers.google.com/cloud-messaging/downstream">downstream |
| 155 | messaging</a>. |
| 156 | </li> |
| 157 | |
| 158 | <li>If your users must see a notification right away, make sure to use a <a href= |
| 159 | "https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message">GCM |
| 160 | high priority message</a>. |
| 161 | </li> |
| 162 | |
| 163 | <li>Provide sufficient information within the initial <a href= |
| 164 | "https://developers.google.com/cloud-messaging/concept-options#payload">message |
| 165 | payload</a>, so subsequent network access is unnecessary. |
| 166 | </li> |
| 167 | |
| 168 | <li>Set critical alarms with {@link |
| 169 | android.app.AlarmManager#setAndAllowWhileIdle(int, long, |
| 170 | android.app.PendingIntent) setAndAllowWhileIdle()} and {@link |
| 171 | android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, |
| 172 | android.app.PendingIntent) setExactAndAllowWhileIdle()}. |
| 173 | </li> |
| 174 | |
| 175 | <li> |
| 176 | <a href="#testing_doze">Test your app in Doze.</a> |
| 177 | </li> |
| 178 | </ul> |
| 179 | </ol> |
| 180 | </div> |
| 181 | </div> |
| 182 | |
| 183 | <h3 id="assessing_your_app">Adapting your app to Doze</h3> |
| 184 | |
| 185 | <p> |
| 186 | Doze can affect apps differently, depending on the capabilities they offer |
| 187 | and the services they use. Many apps function normally across Doze |
| 188 | cycles without modification. In some cases, you must optimize the way |
| 189 | that your app manages network, alarms, jobs, and syncs. Apps should be able |
| 190 | to efficiently manage activities during each maintenance window. |
| 191 | </p> |
| 192 | <p> |
| 193 | Doze is particularly likely to affect activities that {@link android.app.AlarmManager} alarms and |
| 194 | timers manage, because alarms in Android 5.1 (API level 22) or lower do not fire when the system |
| 195 | is in Doze. |
| 196 | </p> |
| 197 | |
| 198 | <p> |
| 199 | To help with scheduling alarms, Android 6.0 (API level 23) introduces two new |
| 200 | {@link android.app.AlarmManager} methods: {@link |
| 201 | android.app.AlarmManager#setAndAllowWhileIdle(int, long, |
| 202 | android.app.PendingIntent) setAndAllowWhileIdle()} and {@link |
| 203 | android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, |
| 204 | android.app.PendingIntent) setExactAndAllowWhileIdle()}. With these methods, |
| 205 | you can set alarms that will fire even if the device is in Doze. |
| 206 | </p> |
| 207 | |
| 208 | <p class="note"><strong>Note:</strong> Neither |
| 209 | {@link |
| 210 | android.app.AlarmManager#setAndAllowWhileIdle(int, long, |
| 211 | android.app.PendingIntent) setAndAllowWhileIdle()} nor {@link |
| 212 | android.app.AlarmManager#setExactAndAllowWhileIdle(int, long, |
| 213 | android.app.PendingIntent) setExactAndAllowWhileIdle()} can fire alarms more than once per 15 |
| 214 | minutes per app.</p> |
| 215 | |
| 216 | <p> |
| 217 | The Doze restriction on network access is also likely to affect your app, |
| 218 | especially if the app relies on real-time messages such as tickles or |
| 219 | notifications. If your app requires a persistent connection to the network to |
| 220 | receive messages, you should use <a href="#using_gcm">Google Cloud Messaging (GCM)</a> |
| 221 | if possible. |
| 222 | </p> |
| 223 | |
| 224 | <p> |
| 225 | To confirm that your app behaves as expected with Doze, you can use adb commands to force the |
| 226 | system to enter and exit Doze and observe your app’s behavior. For details, see |
| 227 | <a href="#testing_doze_and_app_standby">Testing with Doze and App Standby</a>. |
| 228 | </p> |
| 229 | |
| 230 | <h2 id="understand_app_standby">Understanding App Standby</h2> |
| 231 | |
| 232 | <p> |
| 233 | App Standby allows the system to determine that an app is idle when the user |
| 234 | is not actively using it. The system makes this determination when the user |
| 235 | does not touch the app for a certain period of time and none of the following |
| 236 | conditions applies: |
| 237 | </p> |
| 238 | |
| 239 | <ul> |
| 240 | <li>The user explicitly launches the app. |
| 241 | </li> |
| 242 | |
| 243 | <li>The app has a process currently in the foreground (either as an activity |
| 244 | or foreground service, or in use by another activity or foreground service). |
| 245 | </li> |
| 246 | |
| 247 | <li>The app generates a notification that users see on the lock screen or in |
| 248 | the notification tray. |
| 249 | </li> |
| 250 | </ul> |
| 251 | |
| 252 | <p> |
| 253 | When the user plugs the device into a power supply, the system releases apps |
| 254 | from the standby state, allowing them to freely access the network and to |
| 255 | execute any pending jobs and syncs. If the device is idle for long periods of |
| 256 | time, the system allows idle apps network access around once a day. |
| 257 | </p> |
| 258 | |
| 259 | <h2 id="using_gcm">Using GCM to Interact with Your App While the Device is Idle</h2> |
| 260 | |
| 261 | <p> |
| 262 | <a href="https://developers.google.com/cloud-messaging/">Google Cloud |
| 263 | Messaging (GCM)</a> is a cloud-to-device service that lets you support |
| 264 | real-time downstream messaging between backend services and apps on |
| 265 | Android devices. GCM provides a single, persistent connection to the cloud; all apps needing |
| 266 | real-time messaging can share this connection. This shared |
| 267 | connection significantly optimizes battery consumption by making it unnecessary for |
| 268 | multiple apps to maintain their own, separate persistent connections, which can |
| 269 | deplete the battery rapidly. For this reason, if your app requires messaging integration with a |
| 270 | backend service, we strongly recommend that you <strong>use GCM if possible</strong>, rather than |
| 271 | maintaining your own persistent network connection. |
| 272 | </p> |
| 273 | |
| 274 | <p> |
| 275 | GCM is optimized to work with Doze and App Standby idle modes by means of |
| 276 | <a href="https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message"> |
| 277 | high-priority GCM messages</a>. GCM high-priority messages let you reliably wake your app to |
| 278 | access the network, even if the user’s device is in Doze or the app is in App Standby mode. |
| 279 | In Doze or App Standby mode, the system delivers the message and gives the |
| 280 | app temporary access to network services and partial wakelocks, then returns the device or app |
| 281 | to idle state. |
| 282 | </p> |
| 283 | |
| 284 | <p> |
| 285 | High-priority GCM messages do not otherwise affect Doze mode, and they don’t |
| 286 | affect the state of any other app. This means that your app can use them to communicate |
| 287 | efficiently while minimizing battery impacts across the system and device. |
| 288 | </p> |
| 289 | |
| 290 | <p> |
| 291 | As a general best practice, if your app requires downstream messaging, it |
| 292 | should use GCM. If your server and client already uses GCM, make sure that your service uses |
| 293 | high-priority messages for critical messages, since this will reliably |
| 294 | wake apps even when the device is in Doze. |
| 295 | </p> |
| 296 | |
| 297 | <h2 id="support_for_other_use_cases">Support for Other Use Cases</h2> |
| 298 | |
| 299 | <p> |
| 300 | Almost all apps should be able to support Doze by managing network connectivity, alarms, |
| 301 | jobs, and syncs properly, and using GCM high-priority messages. For a narrow |
| 302 | set of use cases, this might not be sufficient. For such cases, the system |
| 303 | provides a configurable whitelist of apps that are <strong>partially |
| 304 | exempt</strong> from Doze and App Standby optimizations. |
| 305 | </p> |
| 306 | |
| 307 | <p> |
| 308 | An app that is whitelisted can use the network and hold |
| 309 | |
| 310 | <a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK"> |
| 311 | partial wake locks</a> during Doze and |
| 312 | App Standby. However, <strong>other restrictions still apply</strong> to the |
| 313 | whitelisted app, just as they do to other apps. For example, the whitelisted |
| 314 | app’s jobs and syncs are deferred, and its regular {@link android.app.AlarmManager} alarms do not |
| 315 | fire. An app can check whether it is currently on the exemption whitelist by |
| 316 | calling {@link |
| 317 | android.os.PowerManager#isIgnoringBatteryOptimizations(java.lang.String) |
| 318 | isIgnoringBatteryOptimizations()}. |
| 319 | </li> |
| 320 | </p> |
| 321 | |
| 322 | <p> |
| 323 | Users can manually configure the whitelist in <strong>Settings > Battery |
| 324 | > Battery Optimization.</strong> Alternatively, the system provides |
| 325 | ways for apps to ask users to whitelist them. |
| 326 | |
| 327 | </p> |
| 328 | |
| 329 | <ul> |
| 330 | <li>An app can fire the {@link |
| 331 | android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS} intent |
| 332 | to take the user directly to the <strong>Battery Optimization</strong>, where they can |
| 333 | add the app. |
| 334 | </li> |
| 335 | |
| 336 | <li>An app holding the {@link |
| 337 | android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} permission |
| 338 | can trigger a system dialog to let the user add the app to the whitelist |
| 339 | directly, without going to settings. The app fires a {@link |
| 340 | android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} Intent |
| 341 | to trigger the dialog. |
| 342 | </li> |
| 343 | |
| 344 | <li>The user can manually remove apps from the whitelist as needed. |
| 345 | </li> |
| 346 | </ul> |
| 347 | |
| 348 | <p>Before asking the user to add your app to the whitelist, make sure the app |
| 349 | |
| 350 | matches the <a href="#whitelisting-cases">acceptable use cases</a> for whitelisting.</p> |
| 351 | |
| 352 | |
| 353 | <p class="caution"> |
| 354 | <strong>Note:</strong> Google Play policies prohibit apps from requesting |
| 355 | direct exemption from Power Management features in Android 6.0+ (Doze and App |
| 356 | Standby) unless the core function of the app is adversely affected. |
| 357 | </p> |
| 358 | |
| 359 | <h2 id="testing_doze_and_app_standby">Testing with Doze and App Standby</h2> |
| 360 | |
| 361 | <p> |
| 362 | To ensure a great experience for your users, you should test your app fully |
| 363 | in Doze and App Standby. |
| 364 | </p> |
| 365 | |
| 366 | <h3 id="testing_doze">Testing your app with Doze</h4> |
| 367 | |
| 368 | <p>You can test Doze mode by following these steps:</p> |
| 369 | <ol> |
| 370 | <li>Configure a hardware device or virtual device with an Android 6.0 (API |
| 371 | level 23) or higher system image. |
| 372 | </li> |
| 373 | |
| 374 | <li>Connect the device to your development machine and install your app. |
| 375 | </li> |
| 376 | |
| 377 | <li>Run your app and leave it active. |
| 378 | </li> |
| 379 | |
| 380 | <li>Shut off the device screen. (The app remains active.) |
| 381 | </li> |
| 382 | |
| 383 | <li>Force the system to cycle through Doze modes by running the following |
| 384 | commands: |
| 385 | |
| 386 | <pre class="no-pretty-print"> |
| 387 | $ adb shell dumpsys battery unplug |
| 388 | $ adb shell dumpsys deviceidle step</pre> |
| 389 | |
| 390 | <p>You may need to run the second command more than once. Repeat it until |
| 391 | the device state changes to idle.</p> |
| 392 | </li> |
| 393 | |
| 394 | <li> Observe the behavior of your app after you reactivate the device. Make |
| 395 | sure the app recovers gracefully when the device exits Doze. |
| 396 | </li> |
| 397 | </ol> |
| 398 | |
| 399 | <h3 id="testing_your_app_with_app_standby">Testing your app with App Standby</h4> |
| 400 | |
| 401 | <p>To test the App Standby mode with your app:</p> |
| 402 | |
| 403 | <ol> |
| 404 | <li> Configure a hardware device or virtual device with an Android 6.0 (API level |
| 405 | 23) or higher system image. |
| 406 | </li> |
| 407 | <li> Connect the device to your development machine and install your app.</li> |
| 408 | <li> Run your app and leave it active.</li> |
| 409 | <li> Force the app into App Standby mode by running the following commands: |
| 410 | |
| 411 | <pre class="no-pretty-print">$ adb shell dumpsys battery unplug |
| 412 | $ adb shell am set-inactive <packageName> true</pre> |
| 413 | <li>Simulate waking your app using the following commands: |
| 414 | |
| 415 | <pre class="no-pretty-print">$ adb shell am set-inactive <packageName> false |
| 416 | $ adb shell am get-inactive <packageName></pre> |
| 417 | </li> |
| 418 | <li>Observe the behavior of your app after waking it. Make sure the app recovers gracefully |
| 419 | from standby mode. In particular, you should check if your app's Notifications and background |
| 420 | jobs continue to function as expected. |
| 421 | </li> |
| 422 | </ol> |
| 423 | |
| 424 | |
| 425 | <h2 id="whitelisting-cases">Acceptable Use Cases for Whitelisting</h2> |
| 426 | |
| 427 | <p>The table below highlights the acceptable use cases for requesting or being on |
| 428 | the Battery Optimizations exceptions whitelist. In general, your app should not be on the |
| 429 | whitelist unless Doze or App Standby break the core function of the app or there is a |
| 430 | technical reason why your app cannot use GCM high-priority messages.</p> |
| 431 | |
| 432 | <p>For more information, see <a href="#support_for_other_use_cases">Support for Other Use Cases |
| 433 | </a>.</p> |
| 434 | |
| 435 | <table> |
| 436 | <tr> |
| 437 | <th>Type</td> |
| 438 | <th>Use-case</td> |
| 439 | <th>Can use GCM?</td> |
| 440 | <th>Whitelisting acceptable?</td> |
| 441 | <th>Notes</td> |
| 442 | </tr> |
| 443 | |
| 444 | <tr> |
| 445 | <td rowspan="2">Instant messaging, chat, or calling app. </td> |
| 446 | <td rowspan="3">Requires delivery of real-time messages to users while device is in Doze or app |
| 447 | is in App Standby.</td> |
| 448 | <td>Yes, using GCM</td> |
| 449 | <td rowspan="2" style="color:red">Not Acceptable</td> |
| 450 | <td rowspan="2">Should use GCM high-priority messages to wake the app and access the network.</td> |
| 451 | </tr> |
| 452 | |
| 453 | <tr> |
| 454 | <td>Yes, but is not using GCM high-priority messages.</td> |
| 455 | </tr> |
| 456 | |
| 457 | <tr> |
| 458 | <td rowspan="1">Instant messaging, chat, or calling app; |
| 459 | enterprise VOIP apps.</td> |
| 460 | <td>No, can not use GCM because of technical dependency on another messaging |
| 461 | service or Doze and App Standby break the core function of the app.</td> |
| 462 | <td style="color:green">Acceptable</td> |
| 463 | <td></td> |
| 464 | </tr> |
| 465 | |
| 466 | <tr> |
| 467 | <td rowspan="1">Task automation app</td> |
| 468 | <td>App's core function is scheduling automated actions, such as for instant |
| 469 | messaging, voice calling, new photo management, or location actions.</td> |
| 470 | <td>If applicable.</td> |
| 471 | <td style="color:green">Acceptable</td> |
| 472 | <td></td> |
| 473 | </tr> |
| 474 | |
| 475 | <tr> |
| 476 | <td rowspan="2">Peripheral device companion app</td> |
| 477 | <td>App's core function is maintaining a persistent connection with the peripheral |
| 478 | device for the purpose of providing the peripheral device internet access.</td> |
| 479 | <td >If applicable.</td> |
| 480 | <td style="color:green">Acceptable</td> |
| 481 | <td rowspan="2"></td> |
| 482 | </tr> |
| 483 | |
| 484 | <tr> |
| 485 | <td>App only needs to connect to a peripheral device periodically to sync, or only |
| 486 | needs to connect to devices, such as wireless headphones, connected via standard |
| 487 | Bluetooth profiles.</td> |
| 488 | <td >If applicable.</td> |
| 489 | <td style="color:red">Not Acceptable</td> |
| 490 | </tr> |
| 491 | </table> |
| 492 | |
| 493 | |