The Android Developer Challenge is back! Submit your idea before December 2.

バックグラウンド実行制限

アプリは、バックグラウンドで実行されているときは必ず端末のリソースの一部(RAM など)を消費します。 これにより、ユーザー エクスペリエンスが悪化する場合があります。特にゲームをプレイしたり動画を視聴したりするなど、多くのリソースを消費するアプリを使用している場合、この傾向が強くなります。 Android 8.0(API レベル 26)では、ユーザー エクスペリエンスを向上させるために、アプリがバックグラウンドで実行されているときの動作を制限しています。 このドキュメントでは、オペレーティング システムへの変更点を説明し、新しい制限下でアプリを良好に動作させるためのアップデート方法を説明します。

概要

多くの Android アプリやサービスは同時に実行することができます。 たとえば、あるウィンドウでゲームをプレイしながら別のウィンドウでウェブをブラウジングしているときに、別のアプリで音楽を再生できます。 同時に実行するアプリが多いほど、システムに大きな負荷がかかります。 さらに多くのアプリやサービスがバックグラウンドで実行されると、システムにかかる負荷が増えて、音楽アプリが突然シャットダウンするなど、ユーザー エクスペリエンスが低下します。

Android 8.0 では、このような問題の発生頻度を抑えるため、ユーザーがアプリを直接操作していないときにアプリで実行できる動作を制限しています。 アプリの動作は次の 2 つの方法で制限されます。

  • バックグラウンド サービスの制限事項: アプリがアイドル状態にある場合、バックグラウンド サービスの使用を制限します。 これは、ユーザーが認識しやすいフォアグラウンド サービスには適用されません。

  • ブロードキャストの制限事項: 限定的な例外を除き、アプリはマニフェストを使用して暗黙的なブロードキャストを登録できません。 ただし、アプリは実行時にこれらのブロードキャストを登録でき、アプリを明確に対象とする明示的なブロードキャストについては、マニフェストを使って登録できます。

多くの場合、アプリは JobScheduler ジョブを使用してこれらの制限を回避できます。 このアプローチでは、アプリがアクティブに実行されていないときに動作を実行するように調整できますが、アプリがユーザー エクスペリエンスに影響しないようにこれらのジョブをスケジュールすることも可能です。 Android 8.0 では、JobScheduler にいくつかの改善が追加されており、サービスとブロードキャスト レシーバーをスケジュールされたジョブに簡単に置き替えることができます。詳細については、JobScheduler の改善をご覧ください。

バックグラウンド サービスの制限事項

バックグラウンドで実行されているサービスが端末のリソースを消費して、ユーザー エクスペリエンスに悪影響を及ぼす可能性があります。 システムでは、この問題を軽減するために、サービスに対して多くの制限を適用しています。

システムでは、フォアグラウンドとバックグラウンドのアプリが区別されます (サービス制限の目的におけるバックグラウンドの定義は、メモリ管理で使用される定義とは異なります。アプリはメモリ管理に関連してバックグラウンドに存在することがありますが、フォアグラウンドに存在する場合は、サービスを起動する機能に関連します)。アプリは、以下のいずれかに該当する場合にフォアグラウンドにあると見なされます。

  • 可視アクティビティがある(アクティビティが開始されているか一時停止されているかに関係なく)。
  • フォアグラウンド サービスを使用している。
  • 別のフォアグラウンド アプリが、該当アプリのいずれかのサービスにバインドされるか、該当アプリのいずれかのコンテンツ プロバイダを使用することで、該当アプリに接続している。 たとえば、別のアプリが次のいずれかのサービスにバインドされると、アプリがフォアグラウンドになります。
    • IME
    • 壁紙サービス
    • 通知リスナー
    • 音声またはテキスト サービス

これらのいずれの条件にも該当しない場合、アプリはバックグラウンドにあると見なされます。

注: これらのルールは バインドされたサービスには一切影響を与えません。 アプリでバインドされたサービスを定義している場合、アプリがフォアグラウンドにあるかどうかに関係なく、別のコンポーネントをそのサービスにバインドできます。

アプリがフォアグラウンドにある場合、そのアプリはフォアグラウンド サービスとバックグラウンド サービスの両方を制限なく作成して実行できます。 アプリがバックグラウンドに移行すると、そのアプリには数分間ほど、サービスを作成して使用できる猶予が与えられます。 その猶予期間の終了時に、アプリはアイドル状態であると見なされます。 システムはこの時点で、アプリがサービスの Service.stopSelf() メソッドを呼び出したかのように、アプリのバックグラウンド サービスを停止します。

特定の状況下では、バックグラウンド アプリは一時的なホワイトリストに数分間入れられます。 アプリは、このホワイトリストに入っている間、制限なくサービスを起動でき、バックグラウンド サービスの実行を許可されます。 アプリがホワイトリストに入れられるのは、ユーザーに表示される次のようなタスクを処理しているときです。

  • 高い優先度の Firebase Cloud Messaging(FCM)メッセージの処理。
  • SMS/MMS メッセージなどのブロードキャストの受信。
  • 通知からの PendingIntent の実行。
  • VPN アプリが自身をフォアグラウンドにプロモートする前の VpnService の開始。

注: IntentService はサービスであるため、バックグラウンド サービスに対する新しい制限事項の対象になります。 そのため、IntentService に依存する多くのアプリは、Android 8.0 以降を対象にすると正常に動作しません。 こうした理由から、Android Support Library 26.0.0 に新しいJobIntentService クラスが導入されました。このクラスは IntentService と同じ機能を提供しますが、Android 8.0 以降で実行されるときにサービスではなくジョブを使用します。

多くの場合、アプリではバックグラウンド サービスを JobScheduler ジョブに置き換えることができます。 たとえば、CoolPhotoApp はこのアプリがフォアグラウンドで実行されていない場合でも、ユーザーが友人から共有写真を受信したかどうかを確認する必要があります。 このアプリでは以前、アプリのクラウド ストレージをチェックするバックグラウンド サービスを使っていました。 Android 8.0(API レベル 26)に移行するには、バックグラウンド サービスをスケジュールされたジョブに置き換えます。スケジュールされたジョブは、定期的に起動され、サーバーに対してクエリを実行してから終了します。

Android 8.0 よりも前のバージョンでは、フォアグラウンド サービスを作成する通常の方法として、バックグラウンド サービスを作成してから、そのサービスをフォアグラウンドにプロモートしていました。 Android 8.0 では、追加機能があります。システムは、バックグラウンド アプリによるバッグラウンド サービスの作成を許可しません。 そのため、Android 8.0 では、フォアグラウンドで新しいサービスを開始する startForegroundService() メソッドが新たに導入されています。 システムによってサービスが作成されると、アプリは、サービスの startForeground() メソッドを 5 秒以内に呼び出して、その新しいサービスの通知をユーザーに表示します。 アプリが startForeground() を制限時間内に呼び出さない場合、システムによってサービスが停止され、アプリが ANR になります。

ブロードキャストの制限事項

アプリがブロードキャストを受信するように登録されている場合、ブロードキャストが送信されるたびにアプリのレシーバーがリソースを消費します。 そのため、システム イベントに基づくブロードキャストの受信を登録しているアプリが多すぎると、ブロードキャストをトリガーするシステム イベントによって、これらのすべてのアプリが続けざまにリソースを消費し、ユーザー エクスペリエンスに悪影響を与え、問題が発生する可能性があります。 Android 7.0(API レベル 24)では、この問題を軽減するために、バックグラウンド処理の最適化で説明しているように、ブロードキャストに制限を課しています。 Android 8.0(API レベル 26)では、これらの制限を強化しています。

  • Android 8.0 以降を対象にしているアプリは、暗黙的なブロードキャストに対するブロードキャスト レシーバーをマニフェストで登録できなくなりました。 暗黙的なブロードキャストとは、ターゲットにするアプリを明確に指定しないブロードキャストです。 たとえば、登録されたすべてのリスナーに、端末上のパッケージが置き換えられたことを通知するために送信される ACTION_PACKAGE_REPLACED は、暗黙的なブロードキャストです。 一方、他にリスナー登録しているアプリがあっても、パッケージが置き換えられたアプリ以外には送信されない ACTION_MY_PACKAGE_REPLACED は暗黙的なブロードキャストではありません。
  • アプリは引き続き明示的なブロードキャストをマニフェスト内で登録できます。
  • アプリは実行時に Context.registerReceiver() を使って、暗黙的、明示的を問わず任意のブロードキャストに対するレシーバーを登録できます。
  • 署名パーミッションが必要なブロードキャストは、端末上のすべてのアプリではなく、同じ証明書で署名されたアプリのみに送信されるため、これらのブロードキャストにはこの制限は適用されません。

多くの場合、以前に暗黙的なブロードキャストに対して登録していたアプリは、JobScheduler ジョブを使用して同様の機能を得ることができます。 たとえば、ソーシャル フォト アプリでは、そのデータを適宜クリーンアップする必要があり、多くの場合、クリーンアップ操作は端末の充電中に行われます。 以前は、アプリは ACTION_POWER_CONNECTED に対するレシーバーをマニフェスト内で登録しており、ブロードキャストを受信すると、クリーンアップが必要かどうかをチェックしていました。 Android 8.0 以降に移行するために、アプリのマニフェストからこのレシーバーが削除されました。 その代わり、アプリでは端末がアイドル状態かつ充電中である場合に実行するクリーンアップ ジョブがスケジュールされます。

移行ガイド

デフォルトでは、これらの変更は Android 8.0(API レベル 26)以降を対象とするアプリにのみ影響があります。 ただし、アプリが API レベル 26 未満を対象としている場合でも、ユーザーは [Settings] 画面でアプリに対してこれらの制限を有効にすることができます。 新しい制限に準拠するために、アプリをアップデートする必要がある場合があります。

アプリがサービスをどのように使用しているかを確認してください。 アプリがアイドル状態のときにバックグラウンドで実行されるサービスに、アプリが依存している場合、これらのサービスを置き換える必要があります。 考えられる解決策は次のとおりです。

  • アプリが、バックグラウンドにあるときにフォアグラウンド サービスを作成する必要がある場合は、startForegroundService() メソッドを startService() の代わりに使用します。
  • ユーザーに表示されるサービスは、フォアグラウンド サービスにします。 たとえば、音声を再生するサービスは常にフォアグラウンド サービスである必要があります。 このようなサービスを作成するには、startForegroundService() メソッドを startService() の代わりに使用します。
  • スケジュールされたジョブを使ってサービスの機能を複製する方法を検討します。 一般的には、ユーザーが直ちに認識できる動作を行っていないサービスの代わりとして、スケジュールされたジョブを使うことができます。
  • バックグラウンドでポーリングを行うのではなく、FCM を使って、ネットワーク イベントが発生したときにアプリを選択的に起動します。
  • アプリが自然にフォアグラウンドになるまでバックグラウンドの動作を保留します。

アプリのマニフェストで定義されているブロードキャスト レシーバーを確認します。 マニフェストで暗黙的なブロードキャストに対してレシーバーを宣言している場合、それを置き換える必要があります。 考えられる解決策は次のとおりです。

  • マニフェストでレシーバーを宣言するのではなく、Context.registerReceiver() を呼び出して実行時にレシーバーを作成します。
  • スケジュールされたジョブを使って、暗黙的なブロードキャストがトリガーされた状況があったかどうかを確認します。