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

[Android] 電池の最適化の対象外とする(ホワイトリスト登録)導線を作るかを検討する #123

Closed
keiji opened this issue Apr 22, 2021 · 9 comments
Labels
confirmed 開発内部管理用 enhancement 新しい機能や改善のリクエスト wontfix 今のところ対応予定がないもの

Comments

@keiji
Copy link
Collaborator

keiji commented Apr 22, 2021

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

COCOAで接触確認を行うバックグラウンドタスクはWorkManagerを通じて実行している。
WorkManagerは端末の省電力機能(バッテリーセーバーなど)の影響を強く受け、電池残量やユーザーの設定によってはバックグラウンドタスクの起動が制限されて、接触確認が定期的に行われないことがある。

現在は、省電力機能が有効化されていることによって接触確認が定期的に行われないことがある旨、厚生労働省のウェブサイトで広報している。

https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/kenkou_iryou/covid19_qa_kanrenkigyou_00009.html#Q3-6

多くのAndroid搭載端末では、OSのバージョンや機種により、電池消耗やデータ通信量の削減等を目的としてバックグラウンドでのアプリの稼働を停止する様々な機能が備えられており、省電力モード等により、アプリのバックグラウンドでの動作が制限されると、本アプリに限らずアプリ全般で通知を受け取るのが遅れる、または受け取ることができない場合があります。Android搭載端末で本アプリをご利用の方は、端末設定をご確認ください。

電池の最適化の対象外にする設定は設定メニューの奥にあり、ユーザーによっては操作で混乱する可能性がある。また、端末の機種によって少しずつ操作や各画面の内容が異なるので一律の案内が難しい面がある。

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

アプリから電池の最適化の対象外とするように要求する(ユーザーに促す)APIが用意されている。

Doze とアプリ スタンバイ用に最適化する - その他のユースケースのサポート
https://developer.android.com/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases

これを使って電池の最適化の対象外とすることで、ユーザーは複雑な操作をすることなくCOCOAを省電力機能(バッテリーセーバーなど)の対象外にできる。

あなたが考える代替案についてご説明ください / Describe alternatives you've considered

そもそも、電池の最適化の対象外とすることが正しいのか検討の必要がある(ユーザーが省電力を望むのであれば、その意思を尊重すべきと言う考え方)。

ホワイトリスト登録には適用適格な条件があり、COCOAがそれに該当しなければ「ホワイトリスト登録導線は作らない」という選択も当然考慮すべきと考える。

ホワイトリスト登録が可能なユースケース
https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases

その他 / Additional context

本Issueの目的は検討であり、ホワイトリスト登録について広く意見を募るためにある。

作るか・作らないかを決定した時点で、結果を報告してクローズとする。作ると決まった場合、実装については別Issueにて行う予定。

Internal IDs:

  • Prepare Item 2950
@keiji keiji added enhancement 新しい機能や改善のリクエスト discussion 議論が目的、または議論中の Issue labels Apr 22, 2021
@tmurakami
Copy link

個人の見解です。

残念ながら

アプリから電池の最適化の対象外とするように要求する(ユーザーに促す)APIが用意されている。

Doze とアプリ スタンバイ用に最適化する - その他のユースケースのサポート
https://developer.android.com/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases

これを使って電池の最適化の対象外とすることで、ユーザーは複雑な操作をすることなくCOCOAを省電力機能(バッテリーセーバーなど)の対象外にできる。

この試みはあまりうまくいかないのではないかと思います。

例えば、
corona-warn-app/cwa-app-android@22fc49e
kontalk/androidclient#1037
https://stackoverflow.com/a/50840603
などを見れば、いくつかのデバイスではそれがまともに動かないだろうことが想像できます。

v1.2.3 ではSetRequiresDeviceIdle(true)を外しており、まともな Android 端末であれば端末に触れたときや充電開始時に遅延したジョブが動くはずなので特に問題にはならないのではないかと思います。
問題なのは https://dontkillmyapp.com/ で指摘されているような、省電力モードと称してプロセスをキルする(=スケジュールされたジョブをキャンセルする)メーカーの端末です。

私が考える最良の方法は、Google のガイド
https://developers.google.com/android/exposure-notifications/implementation-guide#workmanager
https://developers.google.com/android/exposure-notifications/exposure-notifications-api#force-stop
に従って Force-stop handling の対応を行うことです。

@keiji
Copy link
Collaborator Author

keiji commented Apr 24, 2021

私が考える最良の方法は、Google のガイド
https://developers.google.com/android/exposure-notifications/implementation-guide#workmanager
https://developers.google.com/android/exposure-notifications/exposure-notifications-api#force-stop
に従って Force-stop handling の対応を行うことです。

ありがとうございます。

Force-stop handlingとホワイトリスト登録と、どちらもやる方向で検討していきましょう。
「Force-stop handling」については別Issueで検討していきたいと思います。

@keiji
Copy link
Collaborator Author

keiji commented Apr 24, 2021

Oppoについては、搭載されている省電力機能「スマート電力消費保護」が1つの要因である可能性がある。

#123 (comment)

説明を読む限りではForegroundService化していれば制限を受けなさそう。ホワイトリストへの登録が効くかは不明。

Force-stop handlingは効きそう。プロセスが立ち上がる度にKillされる可能性はある?(Google Play Servicesのプロセス内で立ち上がるから大丈夫?) このあたりは別Issueの中で要検討。

EzjLWjWVIAY8YnS

https://twitter.com/it00h/status/1385080547597193216 より)

Ezsn5-YUYAA-aCJ

Ezsn6TjXMAA0IYo

https://twitter.com/it00h/status/1385745195526881281 より)

@tmurakami
Copy link

いち利用者の立場から言えば、積極的なホワイトリスト登録はちょっと拒否反応が出てしまいます。

  1. 正しく接触チェックが行なわれているか確認を促す
  2. 問題があったらホワイトリスト登録を試してもらう

という流れだと嬉しいです。

「よくある質問」問③-6 を充実させるだけでも良いのかもしれませんが、「よくある質問」は大分肥大化していて、ただの説明と利用者さんに行動を促すものとが混在していて正直少し見づらいな、と感じています。
ですので、家電とかの説明書によくある「故障かな?と思ったら」みたいな専用の Web ページを別途用意したほうが良いのかな、と思っています。

Web ページにすることで、アプリリリースに縛られることなく修正・追記ができるようになります。
FAQ フォーマットに縛られずに、操作マニュアルのようなページにすることも可能かもしれません。
厚労省サポートさんも、問い合わせの内容次第では専用ページへ誘導するだけで解決できるものもあるかもしれませんし、そもそも問い合わせを減らすことができるかもしれません。
SNS 等で啓蒙活動されている方なんかも少しは楽になるかもしれません。

アプリからの動線ですが、多くの利用者さんに見て頂きたいのであればメイン画面にボタンを配置しても良いでしょうし、サポートさんへ問い合わせる前に確認頂きたいのであれば「よくある質問」と「メールで問い合わせ」の間にボタンを設けても良いかもしれません。
もちろん両方あっても良いかな、と思います。

取るに足らない意見ですが...

@keiji
Copy link
Collaborator Author

keiji commented Apr 26, 2021

@tmurakami
そうですね。たとえば「起動直後にホワイトリスト登録を求める」のは、乱暴だとぼくも思います。

#106 でも触れられていますが、

  1. まずは、通常画面から接触チェックが行われた時刻を確認できるようにする
  2. 次に、一定期間、接触チェックが行われていない場合にユーザーに通知できるようにする
  3. 接触チェックが正しく行われておらず、ユーザーが解決を求める場合に限定してホワイトリスト登録の導線を表示する

くらいの扱いでしょうか。

設定画面に置いてもいいかもしれません(同じコードなのでiOSとの兼ね合いが悩ましいところではありますが)。

ホワイトリスト登録を求めたときにユーザーが一度拒否して、後からやっぱりホワイトリスト登録したくなった場合にアプリからの導線が失われていることは避けたいので、しっかりと整理していく必要がありそうですね。

@keiji
Copy link
Collaborator Author

keiji commented Apr 26, 2021

参考情報です。

Oppoについて、前述に掲載したTwitterアカウントの方から「スマート電力消費保護」が有効になっていて、かつバックグラウンドでの接触確認が行われていなかった期間のログをもらって確認しました。結果、該当期間のログは一切、出力されていませんでした。

これは、そもそもバックグラウンドタスクが起動していない(Workerが起動されていない)ことを意味すると理解しています(実行途中でキャンセルされたなら最低限、初期化時のログくらいは出るはずという認識)。

この事例だとForce-stop handlingは効かず、ホワイトリスト登録が解決策として有効になりそうです。

@tmurakami
Copy link

この事例だとForce-stop handlingは効かず

ごめんなさい。
(本 issue から逸れた話かもしれませんが) Force-stop handling について認識合わせをさせて下さい。

まず、アプリを Force-stop するとアプリが設定していたジョブのスケジュールはキャンセルされます。
これは例えば以下の Application と Worker を含む

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        val req = PeriodicWorkRequestBuilder<MyWorker>(
            PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
            TimeUnit.MILLISECONDS
        ).build()
        WorkManager.getInstance(this)
            .enqueueUniquePeriodicWork("myWorker", ExistingPeriodicWorkPolicy.KEEP, req)
    }
}

class MyWorker(appContext: Context, params: WorkerParameters) :
    CoroutineWorker(appContext, params) {
    override suspend fun doWork(): Result = Result.success()
}

適当なプロジェクトを作成してエミュレータにインストールすることで確認することができます。

上記コードを追加したアプリを Pixel 4 (API 30) のエミュレータで動かして、途中でadb shell am force-stop PACKAGE_NAMEした後 22:00 過ぎまで放置してみました。
その際の logcat は以下のとおりです。
(WorkManager はandroidx.work:work-runtime-ktx:2.5.0を使用しました)

$ adb logcat -s WM-WorkerWrapper:* ActivityManager:* -e forcestoptest
--------- beginning of main
--------- beginning of crash
04-26 20:30:09.422  4171  4194 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=70191183-9898-4996-8a3c-14668628fb66, tags={ com.example.forcestoptest.MyWorker } ]
--------- beginning of system
04-26 20:45:09.551  4171  4212 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=70191183-9898-4996-8a3c-14668628fb66, tags={ com.example.forcestoptest.MyWorker } ]
04-26 21:00:09.622  4171  4212 I WM-WorkerWrapper: Worker result SUCCESS for Work [ id=70191183-9898-4996-8a3c-14668628fb66, tags={ com.example.forcestoptest.MyWorker } ]
04-26 21:07:17.597   506   574 I ActivityManager: Force stopping com.example.forcestoptest appid=10154 user=0: from pid 9160
04-26 21:07:17.598   506   574 I ActivityManager: Killing 4171:com.example.forcestoptest/u0a154 (adj 0): stop com.example.forcestoptest due to from pid 9160

20:30、20:45、21:00 と 15 分毎に Worker が起動していますが、21:07 に Force-stop した後は Worker が起動しませんでした。

Force-stop でジョブのスケジュールがキャンセルされること自体は、違和感はありません。
私が問題だと思っているのはアプリを Force-stop することで省電力を実現している端末がそれなりにある(らしい)ことで、それに対処するために用意されたのが「ジョブを再スケジュールできるように Force-stop された EN アプリのプロセスを立ちあげる」という Force-stop handling の仕組みなのだと認識しています。

ドイツの CWA はかなり初期のバージョンでホワイトリスト登録の導線を作っていたようなのですが、corona-warn-app/cwa-app-android#933 をさっと眺めた限りではホワイトリスト登録では対処できなかったようで、それで SAP と Google が協力して Force-stop handling の仕組みを作ったのかな?と推測しています。
とはいえ https://www.coronawarn.app/en/faq/#no_risk_update を見る限り、Force-stop handling だけでもダメなのかもしれません。

Force-stop handling については私の理解不足も多々あると思いますので、可能ならば Force-stop handling の導入意図や実装上の注意点などを Google に問い合わせたほうが良いかと思います。

@keiji
Copy link
Collaborator Author

keiji commented Apr 27, 2021

ありがとうございます。Force-stop handlingについてぼくが勘違いしていました。確かに、Oppoについても強制停止の状態になっている可能性がありますね。

ぼくがIssueをまだ立てていないのは、Force-stop handlingの正体をぼく自身がつかみ切れていないことがあります。経緯を含めて解説いただいて少し理解できた気がします。

次のURLを見る限りでは、COCOAの場合はApplicationのonCreateでWorkerを登録するように変更すれば、Google Play Service Layerがプロセスを起動したタイミングでWorkerも復帰するだろうと考えています。

https://developers.google.com/android/exposure-notifications/implementation-guide#workmanager
https://developers.google.com/android/exposure-notifications/exposure-notifications-api#force-stop

あとは使われているExposureNotification関係のNuGetが古いので、そちらも更新が必要かもしれません。

ともあれ、開発チームを通じてGoogleへの問い合わせも行っていきます。問い合わせとしては2つ、Force-stop handlingの導入経緯(可能であれば)と、どのようにして導入するかの確認です。

後ほど別Issueを立てます。

@keiji
Copy link
Collaborator Author

keiji commented Nov 23, 2021

あれからずいぶん時間がたってしまいましたが、教えていただいたForce-stop handlingの導入以降、バックグラウンドでの接触確認は問題なく動作しているようです。

したがって、電池の最適化の対象外(ホワイトリスト登録)の導線は作らない。として、今週末を目処に本Issueをクローズする予定です。

@keiji keiji added wontfix 今のところ対応予定がないもの and removed discussion 議論が目的、または議論中の Issue labels Nov 23, 2021
@keiji keiji closed this as completed Nov 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
confirmed 開発内部管理用 enhancement 新しい機能や改善のリクエスト wontfix 今のところ対応予定がないもの
Projects
None yet
Development

No branches or pull requests

3 participants