2022/09/11

[android] ブート後に intent を受け取る

AlarmManager の章にデバイスの再起動後にアラームを開始したい場合について書かれている。

デバイスの再起動時にアラームを開始する
https://developer.android.com/training/scheduling/alarms#boot

デバイスの再起動をアプリは検知することは通常できないので、 intent を受け取るようにするようにしておくのだ。
つまり、アラームとは関係が無いのだが、アラームを設定したアプリを起動していたのに、いつの間にか再起動されてアラームが動作しなかったということがあるからここで説明しているのだろう。

 

書いてあるとおりに実装した。
一度アプリを起動しておけば、再起動すると notification が表示される。

https://github.com/hirokuma/AndroidAlarmTest/compare/20488ad5377f82a2d529b2654dbb6262a50985e6..4f69554d7f177e051d3f57b33e59c7701986507d

(関係ないけど、Windows で作っていたからか AndroidManifest.xml だけ CR/LF になっていた。 Android Studio の設定だけでは足りないのか?)

 

また、このブート時に受け取るような設定は永続的なものではないようだ。
このアプリを「アプリ情報」から強制停止してからデバイスを再起動すると notification が出てこなかったからだ。一度設定しておけば良いものでも無く、アプリがブート前に立ち上がって設定しておくだけで良いものでも無く、アプリがまったく死んでいない状態にしておかなければならないようだ。

 

では、ブート時の notification が表示されただけで setComponentEnabledSettings() を実行していない状態で再起動したらどうなるだろうか?
これはブート時に notification が表示された。 AlarmTest アプリは Activity の onCreate() で setComponentEnabledSettings() を呼び出しているのでおそらく呼ばれていないだろう。3分間隔の notification も出ないのでそのはずだ。
プロセスとしては立ち上がっているけれども、 onCreate() から始まる経路は使われていないということかな。

[android] アラームの復習

さて、少し期間が空いてしまったため Android の Alarm についてかなり忘れてしまった。
ほんの少し・・・それですら命取りになるのが加齢よ。。。


前回は AlarmManager を使って通知を出すようなしくみを考えていたが、Android というシステムからするとデバイスの起動状態を管理するという分野になるそうだ。宇宙の成り立ちみたいな広い話ですな。

デバイスの起動状態を管理する  |  Android デベロッパー  |  Android Developers
https://developer.android.com/training/scheduling

定期的に intent を発行する、というだけでなく、もっとデバイスの中で限られたリソースをうまいこと使いたいとなると電源やネットワークの状態によってアプリの動作を制限するというのも理解できる。
アプリを作っている人たちはみんな「私のアプリを使って!」と思っているので、1つしかデバイスがないのであれば優先順位を付けるしかないのだ。

そう考えると、アクションゲーム?のように前面にアプリが起動していないと意味が無いようなアプリの場合はあまり考えなくて良いだろう。バックグラウンドで動作できるアプリが複数あるのに対して、フォアグラウンドで動作できるアプリは1つしかないからだ。画面を分割することもできたと思うが、それでも入力のフォーカスを持っているのは 1アプリだけだろう。

そう考えると、定期的にアプリを起動したいのはフォアグラウンドにはいないアプリが主になるはずだ。
Android 10 からはバックグラウンドアプリから Activity を表に出すことに制限がかかった。調べ切れていないが OS のバージョンが上がってできなくなったことが増えていてもおかしくない。

こういった実装やバージョンの事情がいろいろと複雑にしているのだと思う。
developer のドキュメントはよくできていると思うのだが、Google で検索しても本家の情報が出てこないのであれば実装する人が混乱するのも仕方ないと思う。


AlarmManager 以外にも WorkManager がある。
最近は WorkManager を使うよう勧めているように思うが、得意とする分野が少し異なる。

他の API との関係性
https://developer.android.com/topic/libraries/architecture/workmanager?hl=ja#other-APIs

Dozeモードを解除できるのが AlarmManager らしい。

プラットフォームの電源管理  |  Android オープンソース プロジェクト  |  Android Open Source Project
https://source.android.com/docs/core/power/platform_mgmt

Doze とアプリ スタンバイ用に最適化する  |  Android デベロッパー  |  Android Developers
https://developer.android.com/training/monitoring-device-state/doze-standby?hl=ja

検索していると Dozeモードが搭載された Android 6.0 のときの話が良く出てくるが、Android 7.0 でさらに拡張されたのか。
上のリンクは AOSP なので OS そのものの話になっている。今回はアプリを作る方の立場なので下のリンクの方がわかりやすい。

  • 電源と接続していない
  • 静止状態にしている(センサーで見ているのだろう)
  • 画面オフのまま一定時間過ぎる

これで Dozeモードになるそうだ。それ以降は「メンテナンス枠」ということでときどき Dozeモードを解除して、また戻る。ということは、アプリが Dozeモードになるのではなく本体が Dozeモードになるということか。
時間経過のグラフを見るとメンテナンス枠になるタイミングがどんどん延びているので、放置状態が長くなるほど働かなくなるようにすることで電池の減りをなくそうということだろう。

AlarmManager はこの Dozeモードを無視して動くことができるというのが強みなのだろう。ただそこからすぐに Dozeモードに再突入するかもしれんが、そこはアプリ次第なのか。その API も追加されたもので、なおかつ 9分に 2回以上はアラームが発生しない(ということは 9分に 1回までということか)。

 

もう1つの「アプリスタンバイ」はアプリ単位。いくつか条件が整わないといけないので、アプリスタンバイにならないように作るのは難しくないかもしれない。ただ、アプリスタンバイでなくてもリソースを使いすぎだと判断されたら OS から止められるしくみはあったと思うので、結局は実験して確認するのがよいのか? でも対策していない要因でアプリが止められたら結局調べるしかないだろうし、知識を補充するのが先か・・・。

 

アプリが途中で動かなくなることについての YES/NO シートとか、logcat にこのメッセージが出たらこの状態、みたいなものがあるとよいのだが。