Android CPUの動作をモニターする

時に、Androidの開発でCPUがどれぐらい使われてるかな~

とかモニタリングしたい時があります。

CPUやネットワークを使う動きは、バッテリーを消耗するからモニタリングしたいとか、CPUを動作させるようなプログラムがちゃんと意図したとおりに定期的に動作しているか、などを確認することができます。

やり方はとってもカンタン!です。

1.AndroidStudioの下にある「Profiler」というタブをクリックするか、[View] > [Tool Windows] > [Profiler] を選択でProfilerを開きます。

2.動作を確認したいアプリをRunします。

そんだけ。

Profilerの画面に、下記のようにCPUとかメモリとか、ネットワーク利用とか、バッテリ使用量が出てきます。便利!

停止するときは、赤い■ボタンを押します。

CPUの行をクリックすると、CPUがどのように使われているかが一覧の画面より詳しくわかります。

どのスレッドがいつ発生しているかとかもわかりますね。

ライブラリを組み込んでいるときは、ライブラリのスレッドの動作も出てきます。

画面をタップして違う画面に遷移したりしていろいろ計測できますので、やってみてください!

公式は下記です。

https://developer.android.com/studio/profile/cpu-profiler?hl=ja

Android wakelockがちゃんと動作しているかADBを使って調べる

AndroidでCPUを動作させ続けるために、wakelockというものが使えます。

https://developer.android.com/training/scheduling/wakelock?hl=ja

次のように起動します。

        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        PowerManager.WakeLock mWl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "MyApp::MyWakelockTag");
        mWl.acquire();

//後でこれを呼び出さないとだめ
       
        if (mWl != null && mWl.isHeld()) {
              mWl.release();
        }

しかし、仕込んだところで、これがちゃんと動作しているのか…?

調べたい時がありますよね。

そんな時は、ADB

adb shell dumpsys power

とやります。

ちょっとですね、出てくる情報が多すぎなんですが

Wake Locksという部分がありまして、ここにしかけられているWaleLockが出てきます。

wakelockがrelease されていると、ここに出てきません。

ちなみに、

adb shell dumpsys power

でwakelock関連で使えるところがもう一個ありまして、Wake Lock Log という、Wakelockを使ったおそらくログなのだろう… というのを見ることができます。

出力が多すぎて萎えますが、上述の

        PowerManager.WakeLock mWl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "MyApp::MyWakelockTag");

としました、この ”MyApp::MyWakelockTag” という引数が役に立ちます!

ありますね~ ちゃんと17:49:06 に動作していたということがわかります(泣)

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

になります。

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