先日からの、Wi-Fiに接続できる環境でもモバイルデータが使われる問題への対処の続きのまとめを書いていたら、新しいアイデアが浮かんで、それがうまく行ったので書く。前半はそのアイデアが浮かぶ前に書いていたものを加筆・修正したもので、後半がそのアイデアと結果である(前半を飛ばしたい場合はここ)。
ディープスリープ回避による同期間隔の改善
当初は、Automagicで定期的にカレンダーなどの特定アプリの同期を行うようにし、その時にWi-Fiが切れていたら再接続するようにしていた。ただ、システムがディープスリープする(Dozeモードになる)のか、アイドル時間が長くなると、Automagicでの同期間隔が(設定は30分なのに)3時間前後に伸びる傾向にあった。それは消費電力の削減には効くので諦めようとした。とは言え、やっぱり、できれば同期間隔が伸び過ぎないようにしたくなった。ただ、前回も書いたように、消費電力削減と定期的な同期間隔とモバイルデータ量の削減は相反するので、うまく共存させる必要がある。
それまでに分かった問題点は、
- ディープスリープ(Dozeモード)のために同期間隔が伸びる。
- 要求した同期の実行が遅れることがある。(同期の実行遅れ)
なので、それらを解消(軽減)できればいいと考えた。
それで、同期間隔が長くなり過ぎることを改善するためのポイントは、スマフォを「寝させ過ぎない」(ディープスリープさせ過ぎない)ことだろうと考えた。ディープスリープし過ぎると同期間隔が伸び、更に、Wi-Fiが切れる(offになる)可能性も高くなって、モバイルデータ量も増えてしまう。一方で、全然ディープスリープしなかったら消費電力が増えてしまう。だから、Androidを「適度に突っついて」、目を覚まさせればうまく行きそうな気がした。
いろいろ試したのだが、前回気付いた「ディープスリープを回避する方法」をヒントにしたら、結構うまく行った感じだ。そのアイデアは以下である。
Periodic Timer(オプション= "Like alarm clock")をセットすると、ディープスリープにならなくなるが、セットしたままだと消費電力が増えてしまう。そこで、短時間だけPeriodic Timerをセットして解除すれば、消費電力はそれほど増えないのではないか。
これにより、上記の2つの問題が改善できることを期待した。1番は、定期的にディープスリープにならない状態を作ることで、ほとんどの同期間隔を支配しているPeriodic Timer Inexactの精度が向上することを(この間にPeriodic Timer Inexactが「動き出す」ことを期待する)、2番は、ディープスリープにならない状態を作ることでAndroid内部に溜まっている同期要求が実行(flush)されることを、それぞれ期待した。それで、以下のようなPeriodic Timerの設定で試してみた。
- Periodic Timerの周期(= ディープスリープにしない時間): 2分
- Periodic Timerを解除するまでの待ち時間: 30秒
理論的には、Periodic Timerのイベントが起こったらすぐに解除してもいいはずだが、解除する前に何かの処理を入れたほうがいいかと考えて、少し待ち時間を入れた(後で分かったが、待ち時間は要るようだ)。
すると、1番(同期間隔)については効果があったが、意外なことに、2番(同期の実行遅れ)にはほとんど効果がなかった。ディープスリープにしない時間が短かかったのかも知れないし、他の要因があるのかも知れないと思っていたのだが、その後、要求を溜めているのは、OSでなく同期アプリ自体なのかも知れない(同期アプリがスリープしていたら、要求を受けても実行できないのだろう)と考え、同期アプリがスリープしないように、「電池の最適化」をoffにして試したら、同期の実行遅れもなくなった。
基本的な処理の流れは以下である。
- 同期の契機となるイベント(例: Periodic Timer Inexact)を待つ。
- 同期する時期(例: 前回の同期から30分以上経過)だったら以下を行う。
- ディープスリープ回避処理を有効にする(= Periodic Timerを起動する)。 → ディープスリープの回避が始まり、Periodic Timerの周期の経過後に解除される。
- 同期処理を行う(基本的には前回書いたのと同じ内容)。
本当は本体のプログラム中でPeriodic Timerの作成や起動をしたかったのだが、Automagicに適当な機能はなかったので(アラームやタイマーなどは可能だが、本当にアラームが設定されて音が鳴ったりするので、実用には向かない)、別のプログラムにした。もしかしたら、ディープスリープ回避処理で行っているスリープ(オプション= "Keep device awake")をするだけでもいいのかも知れないが、確かではない(Periodic Timerには"Like alarm clock"オプションが必要なので、たぶん駄目だと思う)。
ディープスリープ回避処理は以下である。
- Periodic Timer(周期= 1分, オプション= "Like alarm clock")のイベントを待つ。
- 以下を並行して行う。
- 一定時間(30秒間)Sleepする(オプション= "Wake up from idle/doze": Doze(ディープスリープ)状態から復帰させる)。
- 一定時間(35秒間)Sleepする(オプション= "Keep device awake": この間はディープスリープさせない)。
- 自分を無効にする(= Periodic Timerを無効にする)。
2種類のSleepは、Sleepの2種類のオプションのうちどちらがディープスリープの回避に効果的なのか分からなかったので、念のため両方入れた(Periodic Timerによってディープスリープは既に回避されているのだから、おそらく後者だけで充分だと思うし、なくてもいいかも知れない)。
上記の仕組みを実装し、試してみたところ、管理しているアプリが同期する時にWi-Fiが切れていても確実に接続できるようになり、なかなか良い結果が得られた。要するに、僕の要求のほとんどを満たし、期待以上の効果が得られた。ただ、このプログラムとサーバのログやモバイルデータ通信の状態や使い勝手をチェックしていたら、以下の問題が見付かった。
Wi-Fiが切れている間にこの仕組みが管理していないアプリ(= 外部から同期開始できないもの。例: AquaMailやGoogle Play)やOSの通信が始まった場合は、モバイルが使われてしまう。
特に、AquaMail(メールアプリ)はデータ量が多いうえに外部から同期を開始させられないのでモバイルデータ量が増える要因なので、外部からの同期が可能なBlueMail(= TypeApp)に換えたのだが、使い勝手や好みではAquaMailの方が良い。
Wi-Fi接続のモニタリングと自動(強制)再接続
それで思い付いたのは、同期する仕組みの中の、「Wi-Fiが切れていたら再接続する」処理だけを定期的に実行することである。本来、Wi-Fiの再接続はOSが自動的に行うから自分でする必要はないのだが、ディープスリープ中はそれが結構長く遅れることがあり、その間に通信が発生するとモバイルが使われるので、それを回避するため、切断後なるべく速やかに再接続したい。AutomagicはWi-Fiの切断イベント(WiFi Disconnected)を受けられるので、それを契機にすれば切断後即座に接続できそうだ。また、何らかの理由(例: 帰宅時、ディープスリープ中)でWiFi Disconnectedがない・受け損ねた場合に備えて、定期的なチェックも行う。
基本的な処理の流れは以下である。
- 契機となるイベント(例: WiFi Disconnected, Periodic Timer Inexact)を待つ。
- 再接続処理を行う時期(例: 前回の処理から30分以上経過)だったら、以下を行う。
- Wi-Fiを使用する設定になっていて、Wi-Fiが切れていて(WiFi Connectedが偽)、
- 指定のAP(= 家のルータ)が利用可能(WiFi Available)なら、再接続(WiFi Reassociate)を行う。
- イベントがWi-Fiの切断(WiFi Disconnected)で、指定のAPが利用可能でないなら、Wi-Fi APのスキャン(WiFi Scan)を行う。
- イベントがWi-Fi APのスキャン結果(WiFi Scan Results Available)で、結果(AP一覧)が空の場合には、再接続(WiFi Reassociate)を行う※。
- ディープスリープ回避を行う時期(例: 前回の回避から30分以上経過)だったら、以下を行う。
- ディープスリープ回避プログラムを起動する(実際にはプログラムを「有効」にすることでPeriodic Timerが起動され、ディープスリープの回避が始まる)。
※ 下にも書いたが、Wi-Fi APがあるにも関わらずWiFi Scanの結果が空の場合があり、その時に切断されたままの状態が長引いてしまうため、スキャン結果が空の場合にも再接続してみるようにした。ただ、画面を点灯すると自動的にスキャンが行われるようなので、外出時に無駄に再接続しようとして消費電力を増やす可能性はある。
実装後、さまざまな調整を行い、最終的には以下のような設定(動作条件)にした。
- 処理の契機とするイベント
- Periodic Timer Inexact, WiFi Disconnected, WiFi Scan Results Available, WiFi State Enabled, Automagic Startup
- 再接続処理を行う最小間隔: 10分 (Periodic Timer InexactとAutomagic Startupのみ。それ以外は無条件に実行する)
- Periodic Timer Inexactの周期: 15分
- ディープスリープを回避する間隔: 30分
- ディープスリープの回避
- Periodic Timerの周期(= ディープスリープにしない時間): 1分
- Periodic Timerを解除するまでの待ち時間(Sleep(Keep device awake)): 35秒
Periodic Timer Inexactの周期やディープスリープ回避の間隔を長くすると消費電力が減るが、切断時(Wi-Fiの鍵の期限切れなどで起こる)や帰宅時に再接続するまでの時間が長くなる可能性が高い。また、Periodic Timerを解除するまでの待ち時間は必要で、ないとディープスリープしてWi-Fiが切れてしまう。
当初は、基地局(セル)への接続イベント(Phone Cell GSM: Connected to CIDs)を使って帰宅の判定をしようとしたのだが、基地局の範囲は広いために家から離れたところ(Wi-Fiは繋がらない)で「帰宅」と判定してしまうのと、基地局の変化(増減)を常にフォローすることはできないから、いつまで今の判定条件が有効なのか分からないので止めた。
それから、画面を点灯させるとWi-Fiのスキャンが行われてWiFi Scan Results Availableイベントが発生するから、その時はPeriodic Timer Inexactの周期を待たずに素早く再接続できる(実際には、この場合はOSも再接続すると思われる)。
なお、同期間隔が伸びるのを防ぐために無効にしていた、カレンダー同期アプリの「電池の最適化」は有効に戻した。ディープスリープ回避の効果のようだ。
最終的な性能(特性)は以下のようになり、概ね要求を満たせたように思う。
Wi-Fiが利用可能な場所(家)で、約7時間(2/25 21:13 - 2/26 4:17)のアイドル時の性能:
- 消費電力率: 0.6%/h (2/26 1:50までは0.4%/h)
- モバイルデータの使用量(← Wi-Fiの再接続が遅れた期間): 約60KB (Wi-Fiの使用量: 約3MB)
- Wi-Fiの再接続が遅れた回数: 3回 (再接続回数: 4回)
- カレンダーの平均同期間隔: 約32分 (13回/7時間)
ディープスリープ回避処理により、Wi-Fiが長時間停まることはなくなったようだが、Wi-Fiの鍵の期限切れの時の再接続が数十秒遅れることがあるために※、モバイルデータが使われるのを完全には防げてはいない。ただ、OSを含むすべてのアプリからの通信をほぼWi-Fiにすることができたので、前回よりはモバイルデータ量が減ったはずだ。消費電力は以前より大きくなっているが*、低い期間もあるので他の要因が関係しているのではないかと思う。この点はもう少し様子を見たい。また、同期間隔は申し分ない。
※ Wi-Fiの再接続が遅れることがある問題の詳細な原因は不明なのだが、その時はWi-Fi APのスキャン(WiFi Scan)を行ってもAP一覧が空になっているので、スマフォ(AQUOS sense lite)の仕様(作り)に起因するものではないかと思っている。OSはWi-Fiデバイスは使える状態(「生きている」)だと思って使おうとするのだが、実際にはスマフォが停めていて、使われる時に陰で起動させるのだが、その立ち上がりに時間が掛かるために、最初のスキャンで結果が得られないのではないかと推測している。あるいは、Wi-Fiデバイスの立ち上がりが遅く、OSはそれを待ちきれなくて、モバイルが使われるのかも知れない。
* 消費電力増加の影響を考えてみる。: アイドル状態を継続(使わずに放置)できる時間を考えると、今回の消費電力率(0.6%/h)では前回(最小で0.3%/h)より約7日短くなる。が、実際にはそういう状況はなく、毎日使って充電しているので、その値は余り意味がない。それで、1日当たりの消費電力の差を求めると7.2%程度となる。そして、当然ながら、使っている時の消費電力はそれよりずっと大きい(数十%)ので、この処理による消費電力の増加はそれほど問題ではなさそうだ(と思ったが、通常は1日で20%くらいしか減らないから、7.2%の増加は大きいかも知れない)。
この作業はなかなか根気が要り、動作確認すると不具合が見付かって調整し、再度確認するという手順を何度も繰り返していた。動作確認は深夜などの長時間使わない時に放置することでしかできないので、なかなか時間が掛かり、3週間くらい掛かったが、ようやく終わったようだ(消費電力と再接続の遅れに我慢すればね・・・w)。
わずかなモバイルデータ使用量や電池使用量を減らすだけの、重箱の隅をつつくような改良ではあるのだが、Androidのいろいろなことが分かって(大体は想像)おもしろかった。それから、Automagicを使えば(いくつか不満はあるものの)ものすごくいろいろなことができるので、感心した。結構昔に買ったのだが、全く損はない。
↓
(3/1 6:51) 月が変わったので、モバイルデータ使用量削減処理の効果を調べてみた。削減処理の作成を始めたのは大体2月からなので、1月と2月のモバイルデータ量を比較すれば分かりそうだ。
- 1月: 134MB → 4.3MB/日
- 2月: 81.8MB → 2.9MB/日
-
-
1月のモバイルデータ量
-
-
2月のモバイルデータ量
見かけ上は1日約1.4MBの節約となった。ただし、1月には設定誤りによるカレンダーの再取得や地図アプリ比較のための利用があったので、その分が多くなっているはずだから、過去のログからそれらのデータ量(カレンダー: 約16MB、地図: 11.8(1月分)-2.7(2月分)= 9.1MB)を引くと、以下のようになる。
- 1月: 109MB → 3.5MB/日
- 2月: 81.8MB → 2.9MB/日
1日600KB(27MB/月)の節約と、効果はかなり微妙(気分の問題??)だ。ただ、データ量削減処理は2月の半ば頃から動き出したし、処理の作成や修正による増分もありそうなので、今月の分を見てみないと本当の効果は分からない。ただ、劇的に減ることはなさそうだ。
それでも、現在のモバイルデータの残量は1GB(契約は500MB)になっているので、まあ、全体としては目論見どおりである(良く考えると、繰り越しできるのは前月分だけだと思っていたが、そうではない? それならなおありがたいが・・・)。
PS. この作業中に他の問題も見付かったので、書いておく。
○同期アプリごとの問題
- 同期が不安定なもの: Androidの再起動後にカレンダーの予定がほとんどなくなって、同期がうまく行かなくなった。
- 同期のデータ量が多いもの: 同期は調子いいのだが、常に数十KB(上の約10倍)のデータを取得する。取得するデータの選択がインテリジェントでない?
不安定なのは良くないのだが、最初だけ何とかすればあとはうまく動くから、データ量を減らしたいので、1番を使うことにした。
○Wi-Fi matic(位置に基づいて自動的にW-Fiを有効・無効にするアプリ)の問題
なぜか、Wi-Fiを有効にする場所なのに無効にされてしまうことがある。有効・無効はモバイルの基地局(セル)で判定しているのだが、家に居ても基地局がたまに変わる(3つくらいあった)のに、1つしか記憶しないために無効にしてしまうようだ。元々なのか、設定を変えてしまったせいだろうか? しかも、このアプリはGoogle Playからなくなってしまっているので、使い続けるのは好ましくない。Wi-Fi maticは家以外に居る時(外出時)の消費電力を減らすために使っているのだが、とりあえず、使うのを止めることにした。
それから、複数の基地局に対応したWi-Fi maticの代わりを作ろうとしたのだが、難しかったので止めて、常にWi-Fiを有効にしたままにすることにした。問題になるのは、外出時に無駄にWi-Fiが有効であるために消費電力が増えることだが、外出時は操作やモバイルデータの消費電力の方が大きいので、大きな問題ではなさそうだ。
PS2. この、Wi-Fiが途切れる(勝手にoffになる、再接続が遅れる)現象は僕のスマフォ・環境(ルータとの相性)だけで起こるのか、それともAndroidなら他でも起こるのか気になるところだ。何となく前者の気はするが、実は後者だけど、細かい話だから誰も気にしていないのかも知れない。
PS3. モバイルのデータ残量を見たら、月末だというのに690MB(→ 先月の繰り越し分が190MB余った)も余っている。繰り越しできるのは1か月だろうから、節約し過ぎても意味がないのかも知れない。であれば、多少の接続遅延を許して(= Wi-Fi時でも少しモバイルが使われる)省電力に振る方が得策なのか? 「そんなのどっちでもいい」というのが真実のような気はするがw、まあ、ちょっと考えてみよう。
という具合に、"Never ending story"になる。。。 (2/27 18:58)