Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Doze とアプリ スタンバイ用に最適化する

Android 6.0(API レベル 23)以降には、デバイスが電源に接続していない場合のアプリの動作を管理することでバッテリーの寿命を延ばす 2 種類の省電力機能が導入されています。「Doze」は、デバイスが長い間使用されていない場合にアプリのバックグラウンド CPU とネットワーク アクティビティを保留することで電力消費を抑えます。「アプリ スタンバイ」は、ユーザーがしばらくの間操作していないアプリのバックグラウンド ネットワーク アクティビティを保留します。

デバイスが「Doze」状態になっている間、電池の消費量が多いリソースへのアプリのアクセスはメンテナンスの時間まで保留となります。電源管理に関する制限に特定の制限事項が記載されています。

Doze とアプリ スタンバイは、API レベル 23 を明示的にターゲットとしているかどうかに関係なく、Android 6.0 以降で実行されるすべてのアプリの動作を管理します。最適なユーザー エクスペリエンスを実現するため、アプリを Doze モードとアプリ スタンバイ モードでテストし、コードを必要に応じて調整します。以下、詳細を説明します。

Doze を理解する

ユーザーがデバイスを電源と接続せずに静止状態にして、画面がオフのまま一定時間が過ぎると、デバイスは Doze モードになります。Doze モードでは、ネットワークや CPU に高負荷をかけるサービスへのアプリのアクセスをシステムで制限することによりバッテリーを節約しようとします。さらに、ネットワークへのアプリのアクセスが切断され、ジョブ、同期、標準アラームが保留になります。

システムは定期的に Doze モードを一時停止して、アプリが保留アクティビティを完了できるようにします。この「メンテナンスの時間枠」中に、システムはすべての保留中の同期、ジョブ、アラームを実行し、アプリがネットワークにアクセスできるようにします。

図 1. Doze モードではメンテナンスの時間枠を繰り返し設けることで、アプリがネットワークを使用して保留中のアクティビティを処理できるようにします。

メンテナンスの時間が終了するたびにシステムは再び Doze モードに入り、ネットワークへのアクセスを切断し、ジョブ、同期、アラームを保留にします。デバイスが充電中ではなく長期間使用されていない場合、システムはメンテナンスの発生頻度を徐々に減らしていき、バッテリーの消費量を抑えます。

放置していたデバイスを動かしたり、画面をオンにしたり、充電器に接続したりするなどの動作によってデバイスをアクティブにすると、Doze モードは解除され、すべてのアプリが通常のアクティビティに戻ります。

Doze の制限事項

Doze 中は、アプリに次の制限が適用されます。

  • ネットワークへのアクセスが切断されます。
  • システムが wake locks を無視します。
  • 標準 AlarmManager アラーム(setExact()setWindow() など)が次のメンテナンスの時間まで保留となります。
    • Doze 中にアラームが発生するように設定する必要がある場合は、setAndAllowWhileIdle() または setExactAndAllowWhileIdle() を使用します。
    • setAlarmClock() に設定されたアラームは引き続き通常どおり発生します。これらが発生する直前にシステムは Doze モードを停止します。
  • システムが Wi-Fi スキャンを実行しません。
  • システムがアダプタの同期の実行を許可しません。
  • システムが JobScheduler の実行を許可しません。

Doze チェックリスト

Doze 向けにアプリを調整する

Doze は、アプリの機能や使用するサービスに応じてアプリに異なる影響を及ぼす可能性があります。多くのアプリは、修正しなくても Doze サイクル全体で正常に機能します。ただし、場合によってはネットワーク、アラーム、ジョブ、同期をアプリが管理する方法を最適化する必要があります。アプリがメンテナンスごとにアクティビティを効率的に管理できるようにする必要があります。

Android 5.1(API レベル 22)以前では Doze モード中にアラームが発生しないため、Doze は AlarmManager アラームとタイマーが管理するアクティビティに特に影響を及ぼす可能性があります。

アラームのスケジュール設定をサポートするため、Android 6.0(API レベル 23)では setAndAllowWhileIdle()setExactAndAllowWhileIdle() という 2 つの新しい AlarmManager メソッドが導入されています。このメソッドを使用すると、デバイスが Doze モードになっていてもアラームが発生するように設定できます。

注: setAndAllowWhileIdle()setExactAndAllowWhileIdle() のどちらのメソッドを使用しても、各アプリに対して 9 分に 1 回以上アラームを発生させることができません。

Doze のネットワーク アクセス制限は、通知などのリアルタイム メッセージに依存しているアプリに特に影響を及ぼす可能性があります。メッセージ受信にネットワークへの継続的な接続を必要とするアプリでは、できるだけ Firebase Cloud Messaging(FCM)を使用してください。

Doze モード中にアプリが期待どおりに動作するかを確認するには、adb コマンドでシステムを強制的に Doze モードにしてからモードを解除してアプリの動作を監視します。詳しくは、Doze モードとアプリ スタンバイ モードでテストするを参照してください。

アプリ スタンバイを理解する

アプリ スタンバイにより、ユーザーがアプリをアクティブに使用していない場合に、システムはアプリがアイドル状態であると判断します。システムがこのように判断するのは、ユーザーが一定時間アプリをタップしておらず、次のどの条件にも該当しないときです。

  • ユーザーがアプリを明示的に起動している。
  • アプリのプロセスが現在フォアグラウンドにある(アクティビティかフォアグラウンド サービスとして、または他のアクティビティかフォアグラウンド サービスによって使用されている)。

    注: フォアグラウンド サービスは、システムが即座に実行するタスク、または実行し続ける必要があるタスクに対してのみ使用します。たとえば、ソーシャル メディアに写真をアップロードしたり、音楽プレーヤー アプリがフォアグラウンドで実行していないときに音楽を再生したりする場合です。アプリがアイドル状態にならないようにする目的で、フォアグラウンド サービスを開始しないでください。

  • アプリがロック画面や通知トレイに表示される通知を生成する。
  • アプリが有効なデバイス管理アプリ(デバイス ポリシー コントローラなど)である場合。通常はアプリはバックグラウンドで実行されますが、デバイス管理アプリは、サーバーからいつでもポリシーを受信できるように常に使用可能な状態である必要があるため、スタンバイ状態にはなりません。

デバイスを電源に接続すると、アプリはスタンバイ状態から抜けてネットワークに自由にアクセスできるようになり、保留中のジョブと同期をすべて実行できます。デバイスが長時間アイドル状態の場合、システムによってアイドル中のアプリは 1 日 1 回程度ネットワーク アクセスを許可されます。

デバイスがアイドル状態の間に FCM でアプリにデータを送信する

Firebase Cloud Messaging(FCM)はクラウドからデバイスへのサービスで、Android デバイスでのバックエンド サービスとアプリ間のリアルタイム ダウンストリーム メッセージングをサポートします。FCM はクラウドへの単一かつ継続的な接続を提供します。リアルタイム メッセージングを必要とするすべてのアプリはこの接続を共有できます。この共有接続により、バッテリーを著しく消費する可能性がある継続的な接続を複数のアプリが個別に保持する必要がなくなるため、バッテリーの消費が大幅に最適化されます。このため、バックエンド サービスとのメッセージ統合が必要なアプリでは、継続的なネットワーク接続を個別で保持するよりも、できるだけ FCM を使用することをおすすめします。

FCM は、優先度の高い FCM メッセージにより、Doze とアプリ スタンバイのアイドルモードに対応するように最適化されています。優先度の高い FCM メッセージを使用すると、ユーザーのデバイスが Doze モードでも、アプリがスタンバイ モードでも、アプリを確実に起動してネットワークにアクセスできます。Doze モードまたはアプリ スタンバイ モードの場合、システムからメッセージが配信され、アプリはネットワーク サービスに一時的にアクセス可能となり一部のウェイクロックが実現します。その後、デバイスまたはアプリがアイドル状態に戻ります。

上記の動作以外では、優先度の高い FCM メッセージは Doze モードには影響せず、他のどのアプリの状態にも影響を及ぼしません。つまり、アプリが FCM を使用すれば、システムとデバイス全体へのバッテリーの影響を最小限に抑えながら効率的に通信できることになります。

サーバーとクライアントがすでに FCM を利用している場合は、重要なメッセージに対してサービスで優先度の高いメッセージを利用するようにしてください。これにより、デバイスが Doze モードになっていても確実にアプリをアクティブにすることができます。

その他のユースケースのサポート

ネットワーク接続、アラーム、ジョブ、同期を適切に管理し、FCM の優先度の高いメッセージを使用することで、大半のアプリで Doze をサポートすることができます。ただし、これだけでは不十分なユースケースも一部存在します。このような例に対応するため、Doze 最適化とアプリ スタンバイ最適化の対象から一部除外されるアプリを設定できるホワイトリストがシステムで提供されています。

このホワイトリストに含まれるアプリは、Doze モード中やアプリ スタンバイ中でもネットワークの使用が可能で、部分的な wake locks を保持することができます。ただし、ホワイトリストに含まれるアプリにも、他のアプリと同様に他の制限は適用されます。たとえば、ホワイトリストに含まれるアプリのジョブと同期は(API レベル 23 以下で)保留され、アプリの定期 AlarmManager アラームは発生しません。アプリが対象外ホワイトリストに現在含まれているかどうかを確認するには、isIgnoringBatteryOptimizations() を呼び出します。

ユーザーは、[設定] > [電池] > [電池の最適化] でホワイトリストを手動で設定できます。 また、システムでもアプリをホワイトリストに登録する方法が提供されています。

  • アプリで ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS インテントを発行し、ユーザーがアプリを追加できる [電池の最適化] を直接開くこともできます。
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS パーミッションを持つアプリはシステム ダイアログを起動できるため、ユーザーは設定に移動せずに直接ホワイトリストにアプリを追加できます。アプリは ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS インテントを発行してダイアログを表示します。
  • ユーザーは必要に応じてホワイトリストからアプリを手動で削除できます。

アプリをホワイトリストに追加するかどうかユーザーに確認する前に、そのアプリがホワイトリスト登録が可能なユースケースに適合しているか確認する必要があります。

注: Google Play ポリシーでは、アプリの主要機能が悪影響を受けるのでない限り、直接 Android 6.0 以降の電力管理機能(Doze とアプリ スタンバイ)の対象外とするようアプリが要求することを禁止しています。

Doze モードとアプリ スタンバイ モードでテストする

優れたユーザー エクスペリエンスを実現するため、Doze モードとアプリ スタンバイ モードでアプリを十分にテストする必要があります。

アプリで Doze をテストする

次の手順を実行して Doze モードをテストします。

  1. Android 6.0(API レベル 23)以降のシステム イメージ搭載のハードウェア デバイスまたは仮想デバイスを設定します。
  2. デバイスを開発用 PC に接続してアプリをインストールします。
  3. アプリを実行してアクティブ状態のままにします。
  4. 次のコマンドを実行して、システムを強制的にアイドルモードにします。
        $ adb shell dumpsys deviceidle force-idle
        
  5. 準備ができたら、次のコマンドを実行してアイドルモードを終了します。
        $ adb shell dumpsys deviceidle unforce
        
  6. 次のコマンドを実行して、デバイスを再度アクティブにします。
        $ adb shell dumpsys battery reset
          
  7. デバイスを再びアクティブ状態にした後のアプリの動作を監視します。デバイスが Doze モードから抜けるときに、アプリがスムーズに復帰することを確認してください。

アプリでアプリ スタンバイをテストする

アプリでアプリ スタンバイ モードをテストするには:

  1. Android 6.0(API レベル 23)以降のシステム イメージ搭載のハードウェア デバイスまたは仮想デバイスを設定します。
  2. デバイスを開発用 PC に接続してアプリをインストールします。
  3. アプリを実行してアクティブ状態のままにします。
  4. 次のコマンドを実行して、アプリを強制的にスタンバイ モードにします。
    $ adb shell dumpsys battery unplug
        $ adb shell am set-inactive <packageName> true
  5. 次のコマンドを実行して、アプリの復帰をシミュレートします。
    $ adb shell am set-inactive <packageName> false
        $ adb shell am get-inactive <packageName>
  6. 復帰後のアプリの動作を監視します。アプリがスタンバイ モードからスムーズに復帰することを確認してください。特に、アプリの通知とバックグラウンド ジョブが想定どおりの動作を続けているかを確認する必要があります。

ホワイトリスト登録が可能なユースケース

以下の表に、バッテリー最適化の対象外ホワイトリストへの登録、または登録要求が可能なユースケースをまとめています。Doze やアプリ スタンバイがアプリの主要機能に悪影響を及ぼす場合、またはアプリが技術的な理由から FCM の優先度の高いメッセージを使用できない場合を除き、通常はアプリをホワイトリストに載せるべきではありません。

詳しくは、他のユースケースのサポートをご覧ください。

ユースケース FCM 使用の可否 ホワイトリスト登録の可否 備考
インスタント メッセージ、チャット、通話アプリ デバイスが Doze モードになっている、またはアプリがスタンバイ状態の間、リアルタイム メッセージをユーザーに配信する必要がある。 FCM を使用できます。 登録不可 アプリを復帰させ、ネットワークにアクセスするために、FCM の優先度の高いメッセージを使用する必要があります。
可能ですが、現在 FCM の優先度の高いメッセージを使用していません。
インスタント メッセージ、チャット、通話アプリ、エンタープライズ VoIP アプリ FCM を使用できません。別のメッセージ サービスへの技術的な依存関係、または Doze とアプリ スタンバイがアプリの主要な機能に悪影響を生じさせるためです。 登録可
タスク自動化アプリ アプリの主要機能がインスタント メッセージ、音声通話、新しい写真の管理、ロケーション操作などの自動化操作をスケジュールしている。 該当する場合のみ。 登録可
周辺機器コンパニオン アプリ アプリの主要機能が周辺機器のインターネット アクセスを可能にするために周辺機器との継続的な接続を維持している。 該当する場合のみ。 登録可
アプリに定期的な同期のための周辺機器接続、標準 Bluetooth プロフィールを経由のワイヤレス ヘッドホンなどの機器への接続のみが必要。 該当する場合のみ。 登録不可