Loading core/java/com/android/internal/os/BatteryStatsHelper.java +2 −65 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; Loading Loading @@ -379,6 +378,7 @@ public class BatteryStatsHelper { mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; // Create list of (almost all) sippers, calculate their usage, and put them in mUsageList. processAppUsage(asUsers); Collections.sort(mUsageList); Loading Loading @@ -556,8 +556,7 @@ public class BatteryStatsHelper { } /** * Mark the {@link BatterySipper} that we should hide and smear the screen usage based on * foreground activity time. * Mark the {@link BatterySipper} that we should hide. * * @param sippers sipper list that need to check and remove * @return the total power of the hidden items of {@link BatterySipper} Loading @@ -565,7 +564,6 @@ public class BatteryStatsHelper { */ public double removeHiddenBatterySippers(List<BatterySipper> sippers) { double proportionalSmearPowerMah = 0; BatterySipper screenSipper = null; for (int i = sippers.size() - 1; i >= 0; i--) { final BatterySipper sipper = sippers.get(i); sipper.shouldHide = shouldHideSipper(sipper); Loading @@ -581,44 +579,10 @@ public class BatteryStatsHelper { proportionalSmearPowerMah += sipper.totalPowerMah; } } if (sipper.drainType == BatterySipper.DrainType.SCREEN) { screenSipper = sipper; } } smearScreenBatterySipper(sippers, screenSipper); return proportionalSmearPowerMah; } /** * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity * time. */ public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) { 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 = getProcessForegroundTimeMs(uid, BatteryStats.STATS_SINCE_CHARGED); activityTimeArray.put(uid.getUid(), timeMs); totalActivityTimeMs += timeMs; } } 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); sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0) / totalActivityTimeMs; } } } /** * Check whether we should hide the battery sipper. */ Loading Loading @@ -681,33 +645,6 @@ public class BatteryStatsHelper { return timeMs * 1000; } @VisibleForTesting public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) { final BatteryStats.Timer timer = uid.getForegroundActivityTimer(); if (timer != null) { 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; Loading core/java/com/android/internal/os/ScreenPowerCalculator.java +64 −0 Original line number Diff line number Diff line Loading @@ -21,9 +21,14 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.SystemBatteryConsumer; import android.os.SystemClock; import android.os.UserHandle; import android.text.format.DateUtils; import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import java.util.List; Loading Loading @@ -57,6 +62,7 @@ public class ScreenPowerCalculator extends PowerCalculator { .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); } // TODO(b/178140704): Attribute screen usage similar to smearScreenBatterySipper. } /** Loading @@ -73,6 +79,8 @@ public class ScreenPowerCalculator extends PowerCalculator { bs.usageTimeMs = durationMs; bs.sumPower(); sippers.add(bs); smearScreenBatterySipper(sippers, bs); } } Loading @@ -96,4 +104,60 @@ public class ScreenPowerCalculator extends PowerCalculator { } return power; } /** * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity * time, and store this in the {@link BatterySipper#screenPowerMah} field. */ @VisibleForTesting public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) { long totalActivityTimeMs = 0; final SparseLongArray activityTimeArray = new SparseLongArray(); for (int i = sippers.size() - 1; i >= 0; i--) { final BatteryStats.Uid uid = sippers.get(i).uidObj; if (uid != null) { final long timeMs = getProcessForegroundTimeMs(uid); activityTimeArray.put(uid.getUid(), timeMs); totalActivityTimeMs += timeMs; } } if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) { final double screenPowerMah = screenSipper.totalPowerMah; for (int i = sippers.size() - 1; i >= 0; i--) { final BatterySipper sipper = sippers.get(i); sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0) / totalActivityTimeMs; } } } /** Get the minimum of the uid's ForegroundActivity time and its TOP time. */ @VisibleForTesting public long getProcessForegroundTimeMs(BatteryStats.Uid uid) { final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000; final int[] foregroundTypes = {BatteryStats.Uid.PROCESS_STATE_TOP}; long timeUs = 0; for (int type : foregroundTypes) { final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, BatteryStats.STATS_SINCE_CHARGED); timeUs += localTime; } // Return the min value of STATE_TOP time and foreground activity time, since both of these // time have some errors. return Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)) / 1000; } /** Get the ForegroundActivity time of the given uid. */ @VisibleForTesting public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) { final BatteryStats.Timer timer = uid.getForegroundActivityTimer(); if (timer == null) { return 0; } return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); } } core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java +10 −13 Original line number Diff line number Diff line Loading @@ -21,12 +21,10 @@ 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; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; Loading Loading @@ -194,7 +192,6 @@ public class BatteryStatsHelperTest extends TestCase { sippers.add(mBluetoothBatterySipper); sippers.add(mIdleBatterySipper); doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper); doNothing().when(mBatteryStatsHelper).smearScreenBatterySipper(any(), any()); final double totalUsage = mBatteryStatsHelper.removeHiddenBatterySippers(sippers); Loading @@ -208,19 +205,20 @@ public class BatteryStatsHelperTest extends TestCase { @Test public void testSmearScreenBatterySipper() { final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class); final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO, BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */); BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */, spc); final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO, BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */); BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */, spc); final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY, BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */); BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */, spc); final List<BatterySipper> sippers = new ArrayList<>(); sippers.add(sipperNull); sippers.add(sipperBg); sippers.add(sipperFg); mBatteryStatsHelper.smearScreenBatterySipper(sippers, mScreenBatterySipper); spc.smearScreenBatterySipper(sippers, mScreenBatterySipper); assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0); assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0); Loading Loading @@ -249,13 +247,13 @@ public class BatteryStatsHelperTest extends TestCase { @Test public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() { doReturn(TIME_STATE_FOREGROUND_US + 500).when(mBatteryStatsHelper) final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class); doReturn(TIME_STATE_FOREGROUND_US + 500).when(spc) .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); final long time = spc.getProcessForegroundTimeMs(mUid); assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS); } Loading Loading @@ -291,15 +289,14 @@ public class BatteryStatsHelperTest extends TestCase { } private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah, int uidCode, boolean isUidNull) { int uidCode, boolean isUidNull, ScreenPowerCalculator spc) { final BatterySipper sipper = mock(BatterySipper.class); sipper.drainType = BatterySipper.DrainType.APP; sipper.totalPowerMah = totalPowerMah; doReturn(uidCode).when(sipper).getUid(); if (!isUidNull) { final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS); doReturn(activityTime).when(mBatteryStatsHelper).getProcessForegroundTimeMs(eq(uid), anyInt()); doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid)); doReturn(uidCode).when(uid).getUid(); sipper.uidObj = uid; } Loading Loading
core/java/com/android/internal/os/BatteryStatsHelper.java +2 −65 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; Loading Loading @@ -379,6 +378,7 @@ public class BatteryStatsHelper { mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge() * mPowerProfile.getBatteryCapacity()) / 100; // Create list of (almost all) sippers, calculate their usage, and put them in mUsageList. processAppUsage(asUsers); Collections.sort(mUsageList); Loading Loading @@ -556,8 +556,7 @@ public class BatteryStatsHelper { } /** * Mark the {@link BatterySipper} that we should hide and smear the screen usage based on * foreground activity time. * Mark the {@link BatterySipper} that we should hide. * * @param sippers sipper list that need to check and remove * @return the total power of the hidden items of {@link BatterySipper} Loading @@ -565,7 +564,6 @@ public class BatteryStatsHelper { */ public double removeHiddenBatterySippers(List<BatterySipper> sippers) { double proportionalSmearPowerMah = 0; BatterySipper screenSipper = null; for (int i = sippers.size() - 1; i >= 0; i--) { final BatterySipper sipper = sippers.get(i); sipper.shouldHide = shouldHideSipper(sipper); Loading @@ -581,44 +579,10 @@ public class BatteryStatsHelper { proportionalSmearPowerMah += sipper.totalPowerMah; } } if (sipper.drainType == BatterySipper.DrainType.SCREEN) { screenSipper = sipper; } } smearScreenBatterySipper(sippers, screenSipper); return proportionalSmearPowerMah; } /** * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity * time. */ public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) { 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 = getProcessForegroundTimeMs(uid, BatteryStats.STATS_SINCE_CHARGED); activityTimeArray.put(uid.getUid(), timeMs); totalActivityTimeMs += timeMs; } } 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); sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0) / totalActivityTimeMs; } } } /** * Check whether we should hide the battery sipper. */ Loading Loading @@ -681,33 +645,6 @@ public class BatteryStatsHelper { return timeMs * 1000; } @VisibleForTesting public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) { final BatteryStats.Timer timer = uid.getForegroundActivityTimer(); if (timer != null) { 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; Loading
core/java/com/android/internal/os/ScreenPowerCalculator.java +64 −0 Original line number Diff line number Diff line Loading @@ -21,9 +21,14 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.SystemBatteryConsumer; import android.os.SystemClock; import android.os.UserHandle; import android.text.format.DateUtils; import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; import java.util.List; Loading Loading @@ -57,6 +62,7 @@ public class ScreenPowerCalculator extends PowerCalculator { .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); } // TODO(b/178140704): Attribute screen usage similar to smearScreenBatterySipper. } /** Loading @@ -73,6 +79,8 @@ public class ScreenPowerCalculator extends PowerCalculator { bs.usageTimeMs = durationMs; bs.sumPower(); sippers.add(bs); smearScreenBatterySipper(sippers, bs); } } Loading @@ -96,4 +104,60 @@ public class ScreenPowerCalculator extends PowerCalculator { } return power; } /** * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity * time, and store this in the {@link BatterySipper#screenPowerMah} field. */ @VisibleForTesting public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) { long totalActivityTimeMs = 0; final SparseLongArray activityTimeArray = new SparseLongArray(); for (int i = sippers.size() - 1; i >= 0; i--) { final BatteryStats.Uid uid = sippers.get(i).uidObj; if (uid != null) { final long timeMs = getProcessForegroundTimeMs(uid); activityTimeArray.put(uid.getUid(), timeMs); totalActivityTimeMs += timeMs; } } if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) { final double screenPowerMah = screenSipper.totalPowerMah; for (int i = sippers.size() - 1; i >= 0; i--) { final BatterySipper sipper = sippers.get(i); sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0) / totalActivityTimeMs; } } } /** Get the minimum of the uid's ForegroundActivity time and its TOP time. */ @VisibleForTesting public long getProcessForegroundTimeMs(BatteryStats.Uid uid) { final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000; final int[] foregroundTypes = {BatteryStats.Uid.PROCESS_STATE_TOP}; long timeUs = 0; for (int type : foregroundTypes) { final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, BatteryStats.STATS_SINCE_CHARGED); timeUs += localTime; } // Return the min value of STATE_TOP time and foreground activity time, since both of these // time have some errors. return Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)) / 1000; } /** Get the ForegroundActivity time of the given uid. */ @VisibleForTesting public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) { final BatteryStats.Timer timer = uid.getForegroundActivityTimer(); if (timer == null) { return 0; } return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); } }
core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java +10 −13 Original line number Diff line number Diff line Loading @@ -21,12 +21,10 @@ 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; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; Loading Loading @@ -194,7 +192,6 @@ public class BatteryStatsHelperTest extends TestCase { sippers.add(mBluetoothBatterySipper); sippers.add(mIdleBatterySipper); doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper); doNothing().when(mBatteryStatsHelper).smearScreenBatterySipper(any(), any()); final double totalUsage = mBatteryStatsHelper.removeHiddenBatterySippers(sippers); Loading @@ -208,19 +205,20 @@ public class BatteryStatsHelperTest extends TestCase { @Test public void testSmearScreenBatterySipper() { final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class); final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO, BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */); BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */, spc); final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO, BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */); BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */, spc); final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY, BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */); BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */, spc); final List<BatterySipper> sippers = new ArrayList<>(); sippers.add(sipperNull); sippers.add(sipperBg); sippers.add(sipperFg); mBatteryStatsHelper.smearScreenBatterySipper(sippers, mScreenBatterySipper); spc.smearScreenBatterySipper(sippers, mScreenBatterySipper); assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0); assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0); Loading Loading @@ -249,13 +247,13 @@ public class BatteryStatsHelperTest extends TestCase { @Test public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() { doReturn(TIME_STATE_FOREGROUND_US + 500).when(mBatteryStatsHelper) final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class); doReturn(TIME_STATE_FOREGROUND_US + 500).when(spc) .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); final long time = spc.getProcessForegroundTimeMs(mUid); assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS); } Loading Loading @@ -291,15 +289,14 @@ public class BatteryStatsHelperTest extends TestCase { } private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah, int uidCode, boolean isUidNull) { int uidCode, boolean isUidNull, ScreenPowerCalculator spc) { final BatterySipper sipper = mock(BatterySipper.class); sipper.drainType = BatterySipper.DrainType.APP; sipper.totalPowerMah = totalPowerMah; doReturn(uidCode).when(sipper).getUid(); if (!isUidNull) { final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS); doReturn(activityTime).when(mBatteryStatsHelper).getProcessForegroundTimeMs(eq(uid), anyInt()); doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid)); doReturn(uidCode).when(uid).getUid(); sipper.uidObj = uid; } Loading