diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index e5aeb4b2139dc..8d73544602baa 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -39,6 +39,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; import android.view.Display; + import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -181,6 +182,8 @@ public abstract class BatteryStats implements Parcelable { * * New in version 19: * - Wakelock data (wl) gets current and max times. + * New in version 20: + * - Sensor gets a background counter. */ static final String CHECKIN_VERSION = "20"; @@ -600,10 +603,13 @@ public abstract class BatteryStats implements Parcelable { */ // Magic sensor number for the GPS. public static final int GPS = -10000; - + public abstract int getHandle(); - + public abstract Timer getSensorTime(); + + /** Returns a counter for usage count when in the background. */ + public abstract Counter getSensorBgCount(); } public class Pid { @@ -3318,13 +3324,16 @@ public abstract class BatteryStats implements Parcelable { final Uid.Sensor se = sensors.valueAt(ise); final int sensorNumber = sensors.keyAt(ise); final Timer timer = se.getSensorTime(); + final Counter bgCounter = se.getSensorBgCount(); if (timer != null) { // Convert from microseconds to milliseconds with rounding final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000; final int count = timer.getCountLocked(which); + final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0; if (totalTime != 0) { - dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); + dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count, + bgCount); } } } @@ -4493,17 +4502,25 @@ public abstract class BatteryStats implements Parcelable { sb.append(": "); final Timer timer = se.getSensorTime(); + final Counter bgCounter = se.getSensorBgCount(); if (timer != null) { // Convert from microseconds to milliseconds with rounding final long totalTime = (timer.getTotalTimeLocked( rawRealtime, which) + 500) / 1000; final int count = timer.getCountLocked(which); + final int bgCount = bgCounter != null ? bgCounter.getCountLocked(which) : 0; //timer.logState(); if (totalTime != 0) { formatTimeMs(sb, totalTime); sb.append("realtime ("); sb.append(count); - sb.append(" times)"); + sb.append(" times"); + if (bgCount > 0) { + sb.append(", "); + sb.append(bgCount); + sb.append(" bg"); + } + sb.append(")"); } else { sb.append("(not used)"); } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 6a5bbccb48f04..5d49d12554e35 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -6912,6 +6912,8 @@ public class BatteryStatsImpl extends BatteryStats { final int mHandle; StopwatchTimer mTimer; + Counter mBgCounter; + public Sensor(BatteryStatsImpl bsi, Uid uid, int handle) { mBsi = bsi; mUid = uid; @@ -6931,7 +6933,17 @@ public class BatteryStatsImpl extends BatteryStats { return new StopwatchTimer(mBsi.mClocks, mUid, 0, pool, timeBase, in); } + private Counter readCounterFromParcel(TimeBase timeBase, Parcel in) { + if (in.readInt() == 0) { + return null; + } + return new Counter(timeBase, in); + } + boolean reset() { + if (mBgCounter != null) { + mBgCounter.reset(true); + } if (mTimer.reset(true)) { mTimer = null; return true; @@ -6941,10 +6953,12 @@ public class BatteryStatsImpl extends BatteryStats { void readFromParcelLocked(TimeBase timeBase, Parcel in) { mTimer = readTimerFromParcel(timeBase, in); + mBgCounter = readCounterFromParcel(timeBase, in); } void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) { Timer.writeTimerToParcel(out, mTimer, elapsedRealtimeUs); + Counter.writeCounterToParcel(out, mBgCounter); } @Override @@ -6952,6 +6966,11 @@ public class BatteryStatsImpl extends BatteryStats { return mTimer; } + @Override + public Counter getSensorBgCount() { + return mBgCounter; + } + @Override public int getHandle() { return mHandle; @@ -7795,6 +7814,22 @@ public class BatteryStatsImpl extends BatteryStats { return t; } + public Counter getSensorBgCounterLocked(int sensor, boolean create) { + Sensor se = mSensorStats.get(sensor); + if (se == null) { + if (!create) { + return null; + } + se = new Sensor(mBsi, this, sensor); + mSensorStats.put(sensor, se); + } + Counter c = se.mBgCounter; + if (c != null) return c; + c = new Counter(mBsi.mOnBatteryTimeBase); + se.mBgCounter = c; + return c; + } + public void noteStartSyncLocked(String name, long elapsedRealtimeMs) { StopwatchTimer t = mSyncStats.startObject(name); if (t != null) { @@ -7871,6 +7906,10 @@ public class BatteryStatsImpl extends BatteryStats { if (t != null) { t.startRunningLocked(elapsedRealtimeMs); } + Counter c = getSensorBgCounterLocked(sensor, true); + if (c != null && mProcessState >= PROCESS_STATE_BACKGROUND) { + c.stepAtomic(); + } } public void noteStopSensor(int sensor, long elapsedRealtimeMs) { @@ -7886,6 +7925,10 @@ public class BatteryStatsImpl extends BatteryStats { if (t != null) { t.startRunningLocked(elapsedRealtimeMs); } + Counter c = getSensorBgCounterLocked(Sensor.GPS, true); + if (c != null && mProcessState >= PROCESS_STATE_BACKGROUND) { + c.stepAtomic(); + } } public void noteStopGps(long elapsedRealtimeMs) { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java new file mode 100644 index 0000000000000..0bdf7caa8903f --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.internal.os; + +import android.app.ActivityManager; +import android.os.BatteryStats; +import android.os.Debug; +import android.support.test.filters.SmallTest; +import android.util.Log; + +import junit.framework.TestCase; + +/** + * Test BatteryStatsImpl Sensor Timers. + */ +public class BatteryStatsSensorTest extends TestCase { + + private static final int UID = 10500; + private static final int SENSOR_ID = -10000; + + @SmallTest + public void testSensorStartStop() throws Exception { + final MockClocks clocks = new MockClocks(); + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + bi.mForceOnBattery = true; + clocks.realtime = 100; + clocks.uptime = 100; + bi.getOnBatteryTimeBase().setRunning(true, 100, 100); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); + bi.noteStartSensorLocked(UID, SENSOR_ID); + clocks.realtime = 200; + clocks.uptime = 200; + bi.noteStopSensorLocked(UID, SENSOR_ID); + + bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER); + bi.noteStartSensorLocked(UID, SENSOR_ID); + clocks.realtime = 400; + clocks.uptime = 400; + bi.noteStopSensorLocked(UID, SENSOR_ID); + + BatteryStats.Timer sensorTimer = bi.getUidStats().get(UID).getSensorStats() + .get(SENSOR_ID).getSensorTime(); + BatteryStats.Counter sensorBgCounter = bi.getUidStats().get(UID).getSensorStats() + .get(SENSOR_ID).getSensorBgCount(); + + assertEquals(2, sensorTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); + assertEquals(300000, + sensorTimer.getTotalTimeLocked(clocks.realtime, BatteryStats.STATS_SINCE_CHARGED)); + + assertEquals(1, sensorBgCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED)); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java index 9518219f8c6fa..c7cd0ee710e12 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -11,6 +11,7 @@ import org.junit.runners.Suite; BatteryStatsTimeBaseTest.class, BatteryStatsTimerTest.class, BatteryStatsUidTest.class, + BatteryStatsSensorTest.class, }) public class BatteryStatsTests { } diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index 3924489762296..10541060398ae 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -16,36 +16,28 @@ package com.android.internal.os; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; - -import android.os.BatteryStats; -import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import com.android.internal.os.BatteryStatsImpl; - -import org.mockito.Mockito; - /** * Mocks a BatteryStatsImpl object. */ public class MockBatteryStatsImpl extends BatteryStatsImpl { public BatteryStatsImpl.Clocks clocks; + public boolean mForceOnBattery; + + MockBatteryStatsImpl(Clocks clocks) { + super(clocks); + this.clocks = mClocks; + } MockBatteryStatsImpl() { - super(new MockClocks()); - this.clocks = mClocks; + this(new MockClocks()); } public TimeBase getOnBatteryTimeBase() { return mOnBatteryTimeBase; } + public boolean isOnBattery() { + return mForceOnBattery ? true : super.isOnBattery(); + } }