diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index f3632f08880dd..f085e290222f0 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -840,7 +840,10 @@ public class BatteryStatsHelper { if (sipper.shouldHide) { if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED && sipper.drainType != BatterySipper.DrainType.SCREEN - && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED) { + && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED + && sipper.drainType != BatterySipper.DrainType.BLUETOOTH + && sipper.drainType != BatterySipper.DrainType.WIFI + && sipper.drainType != BatterySipper.DrainType.IDLE) { // Don't add it if it is overcounted, unaccounted or screen proportionalSmearPowerMah += sipper.totalPowerMah; } @@ -861,19 +864,19 @@ public class BatteryStatsHelper { * time. */ public void smearScreenBatterySipper(List sippers, BatterySipper screenSipper) { - final long rawRealtimeMs = SystemClock.elapsedRealtime(); long totalActivityTimeMs = 0; final SparseLongArray activityTimeArray = new SparseLongArray(); for (int i = 0, size = sippers.size(); i < size; i++) { final BatteryStats.Uid uid = sippers.get(i).uidObj; if (uid != null) { - final long timeMs = getForegroundActivityTotalTimeMs(uid, rawRealtimeMs); + final long timeMs = getProcessForegroundTimeMs(uid, + BatteryStats.STATS_SINCE_CHARGED); activityTimeArray.put(uid.getUid(), timeMs); totalActivityTimeMs += timeMs; } } - if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) { + if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) { final double screenPowerMah = screenSipper.totalPowerMah; for (int i = 0, size = sippers.size(); i < size; i++) { final BatterySipper sipper = sippers.get(i); @@ -936,16 +939,41 @@ public class BatteryStatsHelper { return false; } + public long convertUsToMs(long timeUs) { + return timeUs / 1000; + } + + public long convertMsToUs(long timeMs) { + return timeMs * 1000; + } + @VisibleForTesting - public long getForegroundActivityTotalTimeMs(BatteryStats.Uid uid, long rawRealtimeMs) { + public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) { final BatteryStats.Timer timer = uid.getForegroundActivityTimer(); if (timer != null) { - return timer.getTotalTimeLocked(rawRealtimeMs, BatteryStats.STATS_SINCE_CHARGED); + return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); } return 0; } + @VisibleForTesting + public long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) { + final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime()); + final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP}; + + long timeUs = 0; + for (int type : foregroundTypes) { + final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which); + timeUs += localTime; + } + + // Return the min value of STATE_TOP time and foreground activity time, since both of these + // time have some errors. + return convertUsToMs( + Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs))); + } + @VisibleForTesting public void setPackageManager(PackageManager packageManager) { mPackageManager = packageManager; diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java index f01c33f7ed2e6..e81f6789185e3 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java @@ -18,9 +18,12 @@ package com.android.internal.os; +import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -54,11 +57,16 @@ import java.util.List; @SmallTest public class BatteryStatsHelperTest extends TestCase { private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0; - private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS; + private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS * 1000; + private static final long TIME_STATE_FOREGROUND_MS = 10 * DateUtils.MINUTE_IN_MILLIS; + private static final long TIME_STATE_FOREGROUND_US = TIME_STATE_FOREGROUND_MS * 1000; private static final int UID = 123456; private static final double BATTERY_SCREEN_USAGE = 300; private static final double BATTERY_SYSTEM_USAGE = 600; + private static final double BATTERY_WIFI_USAGE = 200; + private static final double BATTERY_IDLE_USAGE = 600; + private static final double BATTERY_BLUETOOTH_USAGE = 300; private static final double BATTERY_OVERACCOUNTED_USAGE = 500; private static final double BATTERY_UNACCOUNTED_USAGE = 700; private static final double BATTERY_APP_USAGE = 100; @@ -68,6 +76,12 @@ public class BatteryStatsHelperTest extends TestCase { @Mock private BatteryStats.Uid mUid; @Mock + private BatterySipper mWifiBatterySipper; + @Mock + private BatterySipper mBluetoothBatterySipper; + @Mock + private BatterySipper mIdleBatterySipper; + @Mock private BatterySipper mNormalBatterySipper; @Mock private BatterySipper mScreenBatterySipper; @@ -109,6 +123,15 @@ public class BatteryStatsHelperTest extends TestCase { mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED; mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE; + mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI; + mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE; + + mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH; + mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE; + + mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE; + mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE; + mContext = InstrumentationRegistry.getContext(); mBatteryStatsHelper = spy(new BatteryStatsHelper(mContext)); mBatteryStatsHelper.setPackageManager(mPackageManager); @@ -165,6 +188,9 @@ public class BatteryStatsHelperTest extends TestCase { sippers.add(mSystemBatterySipper); sippers.add(mOvercountedBatterySipper); sippers.add(mUnaccountedBatterySipper); + sippers.add(mWifiBatterySipper); + sippers.add(mBluetoothBatterySipper); + sippers.add(mIdleBatterySipper); doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper); doNothing().when(mBatteryStatsHelper).smearScreenBatterySipper(any(), any()); @@ -219,6 +245,19 @@ public class BatteryStatsHelperTest extends TestCase { assertThat(mBatteryStatsHelper.isTypeService(mNormalBatterySipper)).isTrue(); } + @Test + public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() { + doReturn(TIME_STATE_FOREGROUND_US + 500).when(mBatteryStatsHelper) + .getForegroundActivityTotalTimeUs(eq(mUid), anyLong()); + doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP), + anyLong(), anyInt()); + + final long time = mBatteryStatsHelper.getProcessForegroundTimeMs(mUid, + BatteryStats.STATS_SINCE_CHARGED); + + assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS); + } + private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah, int uidCode, boolean isUidNull) { final BatterySipper sipper = mock(BatterySipper.class); @@ -227,8 +266,8 @@ public class BatteryStatsHelperTest extends TestCase { doReturn(uidCode).when(sipper).getUid(); if (!isUidNull) { final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS); - doReturn(activityTime).when(mBatteryStatsHelper).getForegroundActivityTotalTimeMs( - eq(uid), anyLong()); + doReturn(activityTime).when(mBatteryStatsHelper).getProcessForegroundTimeMs(eq(uid), + anyInt()); doReturn(uidCode).when(uid).getUid(); sipper.uidObj = uid; } @@ -236,5 +275,4 @@ public class BatteryStatsHelperTest extends TestCase { return sipper; } - }