Skip to content
This repository has been archived by the owner on Apr 12, 2023. It is now read-only.

[Android] Force-stop Handlingの適用(ExposureNotification SDKアップデート) #136

Closed
keiji opened this issue Apr 30, 2021 · 10 comments
Assignees
Labels
enhancement 新しい機能や改善のリクエスト released リリースが完了したもの

Comments

@keiji
Copy link
Collaborator

keiji commented Apr 30, 2021

その機能リクエストは何らかの問題に関連しますか / Is your feature request related to a problem?

#123 の検討過程で提案をもらったもの。

#123 (comment)

一部端末でバックグラウンドタスクが実行されない。実行されてもキャンセルされる場合がある現象が確認されている。

通常アプリはユーザーやシステムから強制停止されると、次回起動するまでバックグラウンドタスクの実行が制限される(スケジュールされない)。一部の端末ではバッテリー消費を低減する目的で、自動的にアプリを強制停止している可能性がある。

解決策についてお書きください / Describe the solution you'd like

「Force-stop Handling」はExposure Notification APIのバージョン1.5から追加された機能。

Google Play ServicesがEN APIを使っているアプリのプロセスを再起動することで、強制停止の状態から復帰させる。

Force-stop handlingについて、具体的な適用方法についてGoogleから回答を得ている。

  • SDK v1.5 以降へのアップデートが必要
  • SDKのアップデートで利用可能になる

とのことで、まずXamarin.GooglePlayServices.Nearby.ExposureNotificationをアップデートすることになる(現在は18.0.2-eap.6)。


バージョンアップについては以前Pull Request( #22 )をもらっています。現時点で一気に更新してしまうのは避けて、ライブラリをそれぞれアップデートしていきたいので、こちらで巻き取らせてくださいと調整済です。


Internal Tracking ID: NFR 2262

@keiji keiji added the enhancement 新しい機能や改善のリクエスト label Apr 30, 2021
@keiji keiji changed the title Force-stop Handlingの適用(ExposureNotification SDKアップデート) [Android] Force-stop Handlingの適用(ExposureNotification SDKアップデート) Apr 30, 2021
@keiji
Copy link
Collaborator Author

keiji commented May 1, 2021

Xamarin.GooglePlayServices.Nearby.ExposureNotificationについては現在、手に入る最新のバージョンは19.7.1-eap.1となっている。

https://www.nuget.org/packages/Xamarin.GooglePlayServices.Nearby.ExposureNotification/

19.7.1-eap.1が使っているSDKはplay-services-nearby-exposurenotification-1.7.1-eap.aarなので、これでForce-stop Handlingは有効になる。

https://github.com/xamarin/XamarinComponents/blob/f39add7ad854c3a8d8ad6a9284220a3d1073e055/Android/ExposureNotification/build.cake#L3-L4


個人的には、最新のplay-services-nearby-exposurenotification-1.8.3-eap.aarを参照したバージョンを作ってあるので、こちらが使えないかなとも思います。

xamarin/XamarinComponents#1133

こちらはPreAuthorizeにも対応しています(COCOAでは利用していませんが)。

PRは提出済みです(Support PreAuthorization)。Microsoftの人、マージしてくれないかなぁ…

@keiji keiji self-assigned this May 2, 2021
@keiji keiji added the ready-for-release マージが済み、リリース準備が完了しているもの label May 16, 2021
@tmurakami
Copy link

tmurakami commented May 17, 2021

ご無沙汰しております。

#123 (comment) でおっしゃっていた

COCOAの場合はApplicationのonCreateでWorkerを登録する

対応は不要という回答を Google から頂いたということでしょうか?
私も @keiji さんと同じようにApplication#onCreateで WorkRequest を enqueue する必要があると考えていたので、ちょっと意外です。

EDIT

私が理解(推測)している内容を追記しておきます。

play-services-nearby-exposurenotificationの aar には以下のような WakeUpService (com.google.android.gms.nearby.exposurenotification.WakeUpService) が含まれています。
https://github.com/google/exposure-notifications-internals/blob/aa75f5c834aacdcad2aa29d899ba882295b31d16/exposurenotification/src/main/java/com/google/samples/exposurenotification/nearby/WakeUpService.java

この Service は 6時間毎に Play Service から bind されます。
EN アプリのプロセスが無い場合はそのタイミングでApplication#onCreateが呼ばれるので、そこで Worker のスケジュールを行って下さい、ということなのだと思っています。

@keiji
Copy link
Collaborator Author

keiji commented May 18, 2021

Application.onCreateでのWorker登録については質問に含めていますが、ライブラリのアップデートのみとのことでした(後述するテストで動作確認が取れたので、本当に要らないのかと再質問はしていません)。

ぼくの手元でも、つぎのPull RequestでビルドしたAPKをインストールしてテストをしてみました。
#141

  1. COCOAをインストールして利用を開始する
  2. adb shell dumpsys jobscheduler でJobSchedulerの登録状態を確認する
  3. adb shell am force-stop [APP_PACKAGE_NAME] でアプリを強制停止する
  4. adb shell dumpsys jobscheduler でJobSchedulerの登録状態を確認して、アプリのJobがない(消えている)ことを確認する
  5. 6時間程度待つ(Force-stop handlingでアプリの再有効化)
  6. adb shell dumpsys jobscheduler でJobSchedulerの登録状態を確認して、アプリのJobがある(復帰している)ことを確認する

この手順で、アプリのJobが復帰していることを確認しています。なお、アプリの設定画面から「強制停止」を選択するとJobは復帰しなかったので、adb shell am force-stop とは意味合いが異なる様子です。

バックグラウンドでの動作安定化については取り組みを続けていく予定です。ApplicationでのWorker登録に切り替える選択肢も持っておきたいと考えています。

@tmurakami
Copy link

@keiji お返事ありがとうございます。

この手順で、アプリのJobが復帰していることを確認しています。

#141 に書いていましたね。失礼致しました。

@keiji
Copy link
Collaborator Author

keiji commented May 18, 2021

それにしてもドキドキしますよね。
ExistingPeriodicWorkPolicy もKEEPになっているのでWorker登録自体をApplication側に移動してもいいかもしれません。

@tmurakami
Copy link

tmurakami commented May 22, 2021

FYI です。

force-stop された場合は WorkManager 初期化時に Job を復元するようです。
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java

PendingIntent が force-stop でクリアされることを利用して force-stop かどうか判別しているようです。
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java#L146-L167

そこのコメントに書いてありますが、いくつかの OEM (コミットメッセージによるとsome popular devices) では AlarmManager のバグにより SecurityException が発生するらしいので

のどちらか (もしくは両方) の対応を合わせて実施したほうが安全かもしれません。

@keiji
Copy link
Collaborator Author

keiji commented May 24, 2021

WorkManagerのバージョンアップについてはしない理由がないので、あとは施策として追加でApplication#onCreateで再スケジュールするように変更するかどうかですね。

AlarmManagerでSecurityExceptionについては、現在COCOAがターゲットにしているバージョンで動作するWorkManagerは、バックエンドにAlarmManagerを使わない(JobSchedulerを使う)と理解しているのですが、ぼくもWorkManagerのすべての実装を見たわけではありませんし、リスクを低減する意味でもApplication#onCreate移動は検討したいです(その場合にiOS側のスケジューラーに影響があるかも念のため確認します)。

@tmurakami
Copy link

バックエンドにAlarmManagerを使わない(JobSchedulerを使う)と理解している

言葉足らずで申し訳ありません。
ForceStopRunnable は API レベル (使用される Job ディスパッチサービス) に関係なく force-stop 判別の為に AlarmManager を利用しているようです。

当該クラスは「force-stop されていたら Job を再スケジュールする」というものです。
これは WorkManagerImpl が生成されるときにWorkManagerImpl#internalInitから呼び出されます。
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java#L764

ForceStopRunnable では「isForceStoppedtrueであれば Job を再スケジュールする」という処理を行っています。
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java#L180-L182
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java#L675-L694

isForceStoppedでは「AlarmManager は force-stop でキャンセルされる」という仕様を利用して PendingIntent の存在有無で force-stop を判別しています。
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java#L153

このアラームの予定時刻は 10 年後ですので
https://github.com/androidx/androidx/blob/9b770633fafed35c5185f1cc2b52612a451ccdb9/work/workmanager/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java#L300
ForceStopRunnable ではアラームを実行させる為ではなく、force-stop を判別する為だけに AlarmManager を利用しているように見えます。

あと、追加でお伝えしたいことがあります。
先に私が述べた

AlarmManager のバグにより SecurityException が発生するらしい

の対応
androidx/androidx@9b77063
について WorkManager 2.5.0 のソース (work-runtime-2.5.0-sources.jar) を確認しましたが、残念ながら当該修正コードは含まれていませんでした。
ですので、現時点で ForceStopRunnable のコミットメッセージにあった some popular devices をケアする為には、Application#onCreateでの再スケジュールを行う他ないかもしれません。

ご参考まで。

@keiji
Copy link
Collaborator Author

keiji commented May 24, 2021

ありがとうございます。そうか、状態判別でAlarmManagerを使っているところでSecurityException出すんですね。
"some popular devices"という記述も不安なので、これは「WorkManagerをApplication#onCreateで再スケジュールする」と言うIssueにした方が良さそうです。

@keiji keiji added released リリースが完了したもの and removed ready-for-release マージが済み、リリース準備が完了しているもの labels Jun 7, 2021
@keiji keiji closed this as completed Jun 10, 2021
@b-wind
Copy link

b-wind commented Jun 12, 2021

たまたま見かけた改善事例があったので貼っておきます(このIssue が適切かどうかは不明ですが)

https://twitter.com/hatano/status/1402783405599719426?s=20

ghost pushed a commit that referenced this issue Jun 30, 2022
ghost pushed a commit that referenced this issue Jul 4, 2022
ghost pushed a commit that referenced this issue Jul 4, 2022
ghost pushed a commit that referenced this issue Jul 4, 2022
ghost pushed a commit that referenced this issue Jul 4, 2022
ghost pushed a commit that referenced this issue Jul 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement 新しい機能や改善のリクエスト released リリースが完了したもの
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants