Merge "ScreenPowerCalculator is responsible for smearing" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-01-28 20:39:30 +00:00
committed by Android (Google) Code Review
3 changed files with 76 additions and 78 deletions

View File

@@ -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;
@@ -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);
@@ -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}
@@ -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);
@@ -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.
*/
@@ -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;

View File

@@ -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;
@@ -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.
}
/**
@@ -73,6 +79,8 @@ public class ScreenPowerCalculator extends PowerCalculator {
bs.usageTimeMs = durationMs;
bs.sumPower();
sippers.add(bs);
smearScreenBatterySipper(sippers, bs);
}
}
@@ -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);
}
}

View File

@@ -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;
@@ -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);
@@ -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);
@@ -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);
}
@@ -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;
}