Android バックグラウンドで位置情報が取れない場合に、バッテリーセーブの状態を調べる 

Androidで位置情報アプリを開発しておりますと、位置情報が取れないということにしばしば遭遇します。

ここでは、

・基本的なパーミッションの設定
・サービスで動作させる場合は、ForegroundServiceを使う

などの基本的なことはやっているのに、位置情報が取れないよ~ ぴえん という場合に、バッテリーセーブのことを調べると、役に立つ場合があるというのをご紹介します。

PowerManagerに

 getLocationPowerSaveMode()

という関数があります。
https://developer.android.com/reference/android/os/PowerManager#getLocationPowerSaveMode()

次のように利用します。

        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            int power_save_mode = powerManager.getLocationPowerSaveMode();
            Log.d("sample", "Power Save Mode:" + power_save_mode);
        }

すると、

2

とか

0

とかの数字が戻ってきます。

私の私物スマホはバッテリーセーブを基本的にONにしていると、2になっていて、2の意味は

LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF

All location providers should be disabled when battery saver is on and
 the device is non-interactive.

Constant Value: 2 (0x00000002)

です。位置情報のプロバイダは、バッテリーセーバーがONの場合とデバイスがインタラクティブではないときにオフられるようです。

0は

LOCATION_MODE_NO_CHANGE

Either the location providers shouldn't be affected by battery saver,
 or battery saver is off.

Constant Value: 0 (0x00000000)

だそうです。この場合は、バッテリーセーバーがONでもOFFでも位置情報プロバイダがオフられないようです。


詳しくは、下記のPowerManagerの定数一覧を見てみてください。

https://developer.android.com/reference/android/os/PowerManager#LOCATION_MODE_NO_CHANGE


Android QUICK_DOZE_DELAY とは

前回

で紹介しました、Android のDozeモードを調べる過程で、

C:\as_component\platform-tools>adb shell dumpsys deviceidle force-idle
Unable to go deep idle; stopped at QUICK_DOZE_DELAY

となることがありました。

どうやら、アラームが設定されていると、こうなるみたいですね。普通のアラームではなく、

AlarmManager.setAlarmClock()

などで設定されているアラームです。

で、これも特にリファレンスがなく、ググってヒットするのは、Androidのソースコードだけですね…。(泣)

DeviceIdleController.java ということで、前にも紹介したこのサイトに出てきました、アイドル状態をコントロールするクラスです。

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android10-c2f2-release/services/core/java/com/android/server/DeviceIdleController.java

ささっと見たところ、次のようなコメントがついてましたね。

 
/**

* Device is inactive and should go straight into idle (foregoing motion and location

* monitoring), but allow some time for current work to complete first.

*/

@VisibleForTesting

static final int STATE_QUICK_DOZE_DELAY = 7;

やらなければいけない仕事もあるけれのでIDLEにならないけれども、IDLEの一歩手前の状態ということでしょうか。

Android dozeモードについてADBを使って調べる

Android dozeモード。

憎いですね。

バッテリーセーブのためにAndroid Mから導入されましたが、最近の端末(Android Xとか以降)になって、非常に幅を利かせている気がします。

バックグラウンドでアプリを動作させたいアプリ開発者にとっては、もう、本当にやめて頂きたい機能です。

さて、先だって、次の記事を読みました。これ、非常に勉強になりましたね。内部的に、どのようにシステムがDoze(Idle)状態になるのか、ということを説明してくださっています。All英語ですが、読む価値あります。(`・ω・´)

https://www.protechtraining.com/blog/post/diving-into-android-m-doze-875

で、ここでも紹介されている

$ adb shell dumpsys deviceidle

が非常にいろいろなことがわかります。

adb shell dumpsys deviceidle やってみる

さて、上記で出力されている内容を解説します。(公式ドキュメントとかないので推測なんですけど。あったら教えて!)

最初のあたりですが

Settings:
light_after_inactive_to=+3m0s0ms
light_pre_idle_to=+3m0s0ms
light_idle_to=+5m0s0ms
light_idle_factor=2.0
light_max_idle_to=+15m0s0ms
light_idle_maintenance_min_budget=+1m0s0ms
light_idle_maintenance_max_budget=+5m0s0ms
min_light_maintenance_time=+5s0ms
min_deep_maintenance_time=+30s0ms
inactive_to=+30m0s0ms… 以下続く

となっていて、おそらく、いつアイドル状態になるのか、という設定が表示されています。モニターの電源をいつ切るかともあるみたいですね。

この端末では、30m にinactive_to なので、30分後にインアクティブという状態になります。

あと、これも役立つ!Idling history というのもあります。

Idling history:         
deep-idle: -5h33m20s697ms
normal: -5h15m8s32ms (alarm)
deep-idle: -5h0m2s802ms
deep-maint: -4h0m10s231ms
deep-idle: -3h59m40s8ms
normal: -3h23m45s722ms (notification interaction)
deep-idle: -24m29s944ms
normal: -23m37s96ms (alarm)

いや、これすごくないですか?ここしばらくの、端末がアイドル状態だったのか、Dozeのメンテナンス枠だったのか、などがわかります。

そして、ホワイトリストにあるアプリがなんなのかが続きます。この辺りは、ほかのサイトさんでも詳しいので割愛します。

Whitelist (except idle) system apps:
jp.co.nttdocomo.lcsapp
com.nttdocomo.android.wipe
com.lge.sizechangable.weather.platform
com.nttdocomo.android.anmane2
com.android.providers.calendar
com.android.providers.downloads

最後に、今の端末の状態(たぶん)があります。

mLightEnabled=true  mDeepEnabled=true
mForceIdle=false
mUseMotionSensor=true mMotionSensor={Sensor name="LGE Significant Motion Detector Sensor", vendor="qualcomm", version=1, type=17, maxRange=1.0, resolution=1.0, power=0.025, minDelay=-1}
mScreenOn=false
mScreenLocked=true
mNetworkConnected=true
mCharging=true
mMotionActive=false
mNotMoving=true
mLocating=false mHasGps=true mHasNetwork=false mLocated=true
mLastGpsLocation=Location[gps 35.142360,139.631290 hAcc=0 et=+2d4h20m18s373ms alt=0.0 vel=13.89 bear=0.0 vAcc=??? sAcc=??? bAcc=??? mock]
mState=ACTIVE mLightState=ACTIVE
mInactiveTimeout=+30m0s0ms

この時点で、端末の状態はACTIVEということになってますね。端末がスリープになってなくて、画面がONで動作させてます。

強制的にDozeモードにするコマンドは

adb shell dumpsys deviceidle force-idle

ですが、これをやると、さっきの最後のmStateが

mState=IDLE

になります。

開発が、少しはかどりますね!

Android Studio Android SDKの場所

Android Studio 4.2

Android SDKがインストールされている場所が知りたいことがあると思います。

そんな時は、SDK Managerを立ち上げましょう。

(File→Settings→Appearance &Bahavior→System Settings→Android SDKでも行けます)

表示されるSDK Platformsの上のほうに、書いてあります。

Android SDKの場所

Xdebug3 var_dumpもきれいに表示したいしデバッグもしたいし、というときの設定

Xdebugがバージョン3になってました。

https://xdebug.org/

環境は、Windows+PHPStorm+PHP7.4(Xampp)です。

PHP7.2→PHP7.4 にしたくて、Xamppを新しくし、Xdebugを設定しなおして気づきました。

まず、PHPStormでデバッグできず、ちょっとはまりました。

注意点は

①PHPStormのバージョンが2020.3以降じゃないとXdebug3に対応していない
②ポート番号がデフォルト9003になっている

です。

さて、表題の話なんですが、まず、デバッグしたいために最初は次のようにphp.iniを設定していました。

zend_extension = D:\xampp2\php\ext\php_xdebug-3.0.1-7.4-vc15-x86_64.dll
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9001
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1
xdebug.var_display_max_depth=-1
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9001
xdebug.mode = debug

最後のxdebug.modeがポイントです。

xdebug.mode = debug

にしないとPHPStormでデバッグできません。(ほかのIDEで試してないのでほかのIDEでどうかわかりません。)

しかし、このままにしておくと、PHPerは必ず使うであろう、var_dump関数の実行結果が美しく表示されません。

きれいに表示されないvar_dumpの結果
きれいに表示されないvar_dumpの結果

こんなん見てられないし、辛いですよね~(>_<)


xdebug.mode = develop

にすると、美しく整形されて表示されます。developがデフォルトだそうです。

美しく出力されたvar_dumpの結果。これならだれでもわかるね!⊂(^-^)⊃

しかし、このままではデバッグできません。

一体どうして…。

と、ぼんやりXdebugの作者のDerickさんのTwitterを見ていたら

Xdebug3のModeについて説明動画があるじゃないですか!!!

Xdebugを作ってくれているだけでもありがたいのに、動画まで…。その優しさに涙が溢れますね…。(>_<)

というわけで、上記を見ると、modeが二つ平行で設定できることがわかります。

xdebug.mode = develop,debug

上記のように設定すると、var_dumpも美しく出力され、デバッグもできました!⊂(^-^)⊃

ちな、Xdebug関係のphp.iniの設定を下記に書いておきます。(私はデバッグのポートを9001で運用しています。)

[xdebug]
zend_extension = D:\xampp2\php\ext\php_xdebug-3.0.1-7.4-vc15-x86_64.dll
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9001
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1
xdebug.var_display_max_depth=-1
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9001
xdebug.mode = develop,debug

php.iniを変更した後は、Webサーバーの再起動を忘れないように!

ありがとう、Derickさん!ロンドンいろいろ大変そうですが、がんばってください。