Open30
[Google I/O 2022 メモ]Best practices for running background work on Android
Managing background work on Android
- アプリがバックグラウンドでタスクを実行する方法とタイミングにいくつかの変更を加えた
- 変更した理由、開発者がバックグラウンドを効率的に利用するためのベストプラクティスを紹介する
- バッテリー寿命はユーザーにとって最大の懸念事項の1つ
- 私達は皆、エンドユーザーに最高の体験を提供する上で果たすべき役割を担っている
- 開発者はユーザーにリーチし、価値を提供する
- AndroidOSは開発者とユーザーをつなぐプラットフォームとして機能する
- システムは各アプリが使用するリソースを測定/管理し、悪用を防止する
- ユーザーがデバイスを制御できるようにする必要がある
- 開発者に一貫性のある文書化されたAPI動作を提供する
- APIの制約と、特定のAPIをいつ使用するか/しないかを明確にする必要がある
- 開発者に効率的で信頼性の高いツールを提供する必要がある
- ユーザーは信頼性を損なうことなく、お気に入りのアプリを使用するときに予測可能なバッテリー寿命を期待する
What Android is doing
- ビジョンを追求するためにパズルのいろいろな部分に取り組んできた。各ピースは連携して機能する
- デバイス間の一貫性を改善
- 特定の動作に対するユーザーコントロールの強化
- FCMポリシーの大幅な変更
- JobSchedulerの動作と機能の改善
Improving consistency across devices
- Fragmentationは難しい
- アプリ開発者はAndroidデバイスメーカーのカスタマイズに対応するため苦労している
- デバイスメーカーの主要な動機の1つに良いバッテリー寿命提供がある
- その実現のために制限を導入するが、文書化されていないことが多い
- そのためForegroundServiceが期待通りに動くデバイスと、予期せず殺されるデバイスがある
- デバイスメーカーの動機もわかるが、アプリ開発者からのフラストレーションも感じている
- この問題を解決するため、制限をいくつかのレベルに標準化することを検討している
- これによってアプリ自身でどのようなレベル、制限に直面する可能性があるかを知ることができる
App Restriction Levels
- レベルはUnrestrictedで始まり、移動するにつれて、より制限的になる
- 一部は自動遷移するが、他のレベルはユーザーが選択する必要がある
Unrestricted
- 制限なし
- ユーザーはアプリ設定のバッテリー設定から"Unrestricted"を選択できる
- 制限を受けないので、バッテリー寿命に悪影響を与える可能性がある
- そのため、ユーザーのみが選択できるレベル
Optimized
- ほとんどのアプリでのデフォルト設定
- アプリのバッテリー設定で選択可能
- Optimizedは、Android9で導入された4つのapp standby bucket、Active/Working Set/Frequent/Rare、で構成されている
- 各Bucketは、Job、Alarm、その他リソースに対して異なる割当てになっている
- システムはアプリの使用履歴に従って、これらのBucket間でアプリを移動させる
- アプリ利用頻度が高いほど、システムがアプリに割り当てるリソースが多くなる
Restricted Bucket
- 制限付きapp standby bucketをAndroid12でリリースし、Android13の新しいRestrictedレベルに拡張した
- Restricted Bucketは非常に限れらたJobとAlermしか受け取れないので、実行できるバックグラウンドworkの量は限られる
Background Restricted
- フォアグラウンドサービスを利用したり、バックグラウンドで他の作業を行ったりすることはできない
- targetSdkがAndroid13以上のアプリでも、Broadcastの遅延がある?(字幕読み取れず)
- Background restrictedはユーザーがアプリ設定から選択した場合のみアクティブになる
- このレベルではアプリが正しく機能しない場合がある
- Android13では、フォアグラウンド、バックグラウンド、フォアグラウンドサービスに渡って、ここのアプリのバッテリー使用量を追跡するためのサポートが追加されている
JobScheduler Improvements
Prefetch Jobs
- PrefetchとしてマークされたJobの処理方法を改善
- ユーザーにとって最も役立つときにデータ読み込むよう延期、早すぎたり実行しすぎたりすることなく、読み込み時間を短縮できる
JobScheduler Priority
- 実行準備ができているJobが複数ある場合、Priority APIはsortするのに役立つ
- Priority APIはアプリ間のJobをsortすることはできない
- JobSchedulerはこのPriorityを、リソース不足時にどのJobを最初に止めると適切か、にも使う
- デバイスの状態と連携し、デバイスヘルスを改善する。例えばデバイスが熱くなりすぎるのを防ぐために、Jobを早期に停止するなど。
- なぜすべてのJobをHighest Priorityにしないのかと思うかもしれない
- 3つの答えがある
- 1 : それは良いエチケットではない
- 2 : 優先度の高いJobは、デフォルトの優先度の低いJobよりタイムアウトが短くなる
- 間違った状況でのHighPriority選択を躊躇させる
- 3 : すべてのJobを同じPriorityにしてもメリットがない
- 優先度の区別ができないので、長期的にはJobのパフォーマンス低下につながる
Network Transfer Jobs
- 同じデータを繰り返しネットワーク転送するのは無駄
- JobSchedulerは、Jobがすべてのデータ転送をできると確信している場合、Job実行をスマートにしようとする
- ネットワークトラフィックのpause/resumeをサポートしているアプリと、そうでないアプリがある
- コードでJobSchedulerに転送できるデータの最小量を通知し、pause/resumeのサポートを示すことができる
- このAPIによってJobSchedulerがいつ開始するかをより適切に判断させることができる
Expedited Job Improvements
- Expedited Jobの改善をした。特にアプリがトップで動作しているとき。
- ForegroundServiceからExpeditedJobの切り替えが容易になった
Job Scheduler Changes Summary
User Control
- 通知権限が導入される
- この権限が許可されていないすべてのアプリは通知を投稿できなくなる
- ForegroundServiceは以前と同じ用に実行できるが、ForegroundServiceに紐付いた通知は表示されなくなる
- 今までと同じ用に、ForegroundServiceを開始するときには、通知を含める必要がある
Dismissible FGS Notifications
- ForegroundServiceに関連付けられた通知の可視性に影響を与えるもう1つの機能で、ユーザーがスワイプでこの通知を消せるようになった
Notification Visibility
- ForegroundServiceに関連づいた通知は、作業がバックグラウンドで行われていることをユーザーに認識させるのに役立つ
- 通知権限の導入により、ForegroundServiceが実行される可能性が高くなり、ユーザーが忘れやすくなる。= ForegroundServiceは悪用に対してより脆弱になってしまう
FGS Task Manager
- この問題に対処するために、Android13ではtargetSdkに関わらず、ユーザーが通知シェードからForegroundServiceを停止できる機能が導入されている
- この機能をForegroundService(FGS) Task Managerと呼ぶ
- ここからForegroundServiceをいつでも停止できる
- ForceStopとは異なり、アプリのJobやAlarmは保持されるので、アプリのビジネス影響を最小限に抑える
User Control Summary
High Priority Firebase Cloud Messages
- Android13では、アプリのStandby bucketによる、High Priority FCMの割当てにも変更がある
- 長年のガイダンスでは、タイムクリティカルなユーザーに表示されるメッセージにHigh Priority FCMを使用すること、だった
- 以前のバージョンのAndroidでは、High Priority FCMの割当は、Standby bucketと直接関連していた
- そのためHigh Priority FCMはユーザーインタラクションの少ないアプリには適していなかった
- High Priority FCMを送信する機能を向上させるため、Android13ではHigh Priority FCMの割当を、Standby bucketから切り離した
- High Priority FCMを送信する開発者は、Standby bucketに関係なく、メッセージ配信に基づいてタイムラインが改善される
- High Priority FCMに応答して、通知を正常に投稿しないアプリは、High Priority FCMの一部が通常のPriorityにダウングレードされる場合がある
- ダウングレードされたかどうかはコードで取得することができる
High Priority FCM Summary
What can Developers Do?
- エチケットの意味
- 友人に招待され、他数人の友人とプロジェクトを助けると想像してください
- 到着するとエナジーバーがいくつかあります
- プロジェクトに取り組んでる間、活動するためにエナジーバーをいくつか食べても良いと言っています
- バーには限りがあるので、食べた分、他の人が食べれる数が減ります
- 礼儀正しいやり方は、いくつかを取り、他の人のために残すことです
- 同様に、ユーザーはあなたや他のアプリを自分のデバイスに招待して物事を成し遂げます
- 各アプリには異なるタスクがあり、必要なエネルギー量も違います
- エチケットは、タスクを完了するために必要最小限のエネルギーを消費すること
Best Practicies
Use WorkManager
- WorkManagerには多くの機能と利点があるが、今回は電力にのみ焦点をあてる
- バッテリー節約に関して、WorkManagerは、タスクに定義されたパラメータに基づいてバックグラウンド作業を行うための最も効率的な方法を、インテリジェントに使用する
- WorkManagerとForegroundServiceを直接使用する場合、特に顕著
- ForegroundServiceは非常に強力。効率ではなくパフォーマンスに合わせて調整されている
- 代替としてWorkManagerを検討することをおすすめする
- タイムクリティカルなユースケースの場合は、WorkManager setExpedited APIを使用する
- 効率を高める方法がいくつかある
- 1: クリーンアップ処理をonStoppedのタイミングで行うこと
- 2: 1つの大きなworkリクエストを作るのではなく、リソースごとにグルーピングされた、とても小さなworkリクエストを作ること
- 1: クリーンアップ処理をonStoppedのタイミングで行うこと
Using High Priority FCMs
- 開発者は、実際に優先度が高い時にだけ、優先度の高いFCMを使用することに注意を払う必要がある
- FCMが通知でユーザーに割り込むのに適切かどうかを自問すること。ユーザーが待つことができるのであれば、通常のFCMを使うべき
- High Priority FCMはデバイスがDozeのときでもアプリをWakeupし、CPUを低電力モードから解除できる
- これは電力を管理するシステムをかなり混乱させる可能性がある
- そのためHigh Priority FCMを使用するのはユーザーがすぐ知る必要のあるときだけ、であることが非常に重要
Refreshing Data
- Webサーバーからデータ取得、IoTデバイスからデータ取得、Wearableから統計を取得、など外部システムと連携することは多い
- これらの作業をバックグラウンドで行う場合、アプリがデータを頻繁に更新しないことが重要
- サーバーに対して毎秒getクエリを実行するのは適切?
- 5秒ごとにIoTセンサーを読み取るのは役立つ?
- バックグラウンドでデータを更新する頻度を検討することをおすすめする
- 効率とは、少なくともデフォルトでは、ユーザーが実行できる最も遅い周期を見つけることを指す。ユーザーが変更についてなにか行うより早くデータを更新することはリソースの効率的な使用ではない
Using Bluetooth Efficiently
- Bluetoothを利用する時はスキャンモードに注意することが重要
- ユースケースが許せれば、SCAN_MODE_LOW_LATENCYではなく、LOW_POWERもしくはBALANCEDの使用を検討する
- バックグラウンドでスキャンを実行する場合に特に重要
- LOW_LATENCYを使う場合、バッテリー影響を減らすためにできることがある
- スキャンの頻度と期間を検討する
- アプリがフォアグラウンドでアクティブなときだけスキャンする
Efficiency while in use
- ユーザーがアプリを積極的に使っている時の効率化
Heat & Power
- デバイスが多くの電力を消費している時は、デバイスが熱くなりやすい
- Androidには温度上昇の結果、CPUやGPUのリソースがより制限されるメカニズムが組み込まれている
- これをThrottlingと呼ぶ
- ユーザーに与える影響が大きくなるので、システムが提供するシグナルをアプリが吸収することをおすすめする。
- 例えば、アプリがユーザーに動画をレンダリングするとする
- デバイスがCPUやGPUのThrottlingを開始すると、動画のsttutterやjankの可能性が高くなる
- ThermalStatusListnerで温度上昇に反応して、アプリで解像度を下げることも選択できる
Use CameraX
- オンデバイスカメラを利用する場合、CameraXを使用することを強くおすすめする
- CameraXもバッテリー効率が良い
- CameraXはCamera2上に構築されており、Camera1よりはるかに効率的
- まだCamera1APIを使用している場合、CameraXに移行すると、アプリに多くの機能が提供されるだけでなく、バッテリーパフォーマンスも向上する
Display Refresh Rate
- 最新のデバイスは、60/90/120Hzのリフレッシュレートを表示できる
- はるかに高速に更新されるディスプレイで30/60フレームでしかレンダリングできないゲームやアプリは、judder、junkなどの視覚的な問題を起こす可能性がある
- アプリ/ゲームのリフレッシュレートとディスプレイのリフレッシュレートが一致するように設定することで防げる
- surface.setFrameRate APIでディスプレイのリフレッシュレートを設定し、アプリ/ゲームのリフレッシュレートと一致させると、アニメーションの品質が向上するだけでなく、バッテリー寿命も向上する
Looking to the future
- バッテリーが消耗すると、ユーザーが再充電するまで、ユーザーを含む誰もがバッテリーを使用できなくなる
- リソースが限られていることを認識し、ポリシーを調整し続ける
- 可能な限り効率的に正しいことを行うのに役立つ、多くのAPIとツールを提供する