Make ScreenPowerCalculator use measured energy with BatteryUsageStats
Test: atest FrameworksCoreTests:com.android.internal.os.ScreenPowerCalculatorTest Bug: 158137862 Bug: 178140704 Change-Id: I8066e0712db88a8825dc973d9efa45fdf70a2ef5
This commit is contained in:
@@ -47,6 +47,7 @@ public abstract class BatteryConsumer {
|
||||
POWER_COMPONENT_SYSTEM_SERVICES,
|
||||
POWER_COMPONENT_SENSORS,
|
||||
POWER_COMPONENT_GNSS,
|
||||
POWER_COMPONENT_SCREEN,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public static @interface PowerComponent {
|
||||
@@ -63,8 +64,9 @@ public abstract class BatteryConsumer {
|
||||
public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
|
||||
public static final int POWER_COMPONENT_SENSORS = 9;
|
||||
public static final int POWER_COMPONENT_GNSS = 10;
|
||||
public static final int POWER_COMPONENT_SCREEN = 13;
|
||||
|
||||
public static final int POWER_COMPONENT_COUNT = 11;
|
||||
public static final int POWER_COMPONENT_COUNT = 14;
|
||||
|
||||
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
|
||||
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
|
||||
@@ -85,6 +87,7 @@ public abstract class BatteryConsumer {
|
||||
TIME_COMPONENT_MOBILE_RADIO,
|
||||
TIME_COMPONENT_SENSORS,
|
||||
TIME_COMPONENT_GNSS,
|
||||
TIME_COMPONENT_SCREEN,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public static @interface TimeComponent {
|
||||
@@ -101,8 +104,9 @@ public abstract class BatteryConsumer {
|
||||
public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
|
||||
public static final int TIME_COMPONENT_SENSORS = 9;
|
||||
public static final int TIME_COMPONENT_GNSS = 10;
|
||||
public static final int TIME_COMPONENT_SCREEN = 13;
|
||||
|
||||
public static final int TIME_COMPONENT_COUNT = 11;
|
||||
public static final int TIME_COMPONENT_COUNT = 14;
|
||||
|
||||
public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
|
||||
public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
|
||||
|
||||
@@ -99,12 +99,13 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela
|
||||
private boolean mExcludeFromBatteryUsageStats;
|
||||
|
||||
public Builder(int customPowerComponentCount, int customTimeComponentCount,
|
||||
BatteryStats.Uid batteryStatsUid) {
|
||||
@NonNull BatteryStats.Uid batteryStatsUid) {
|
||||
super(customPowerComponentCount, customTimeComponentCount);
|
||||
mBatteryStatsUid = batteryStatsUid;
|
||||
mUid = batteryStatsUid.getUid();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public BatteryStats.Uid getBatteryStatsUid() {
|
||||
return mBatteryStatsUid;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
|
||||
|
||||
private double getMeasuredOrEstimatedPower(long measuredEnergyUJ, long durationMs) {
|
||||
if (measuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
|
||||
return mAhToUJ(measuredEnergyUJ);
|
||||
return uJtoMah(measuredEnergyUJ);
|
||||
} else {
|
||||
return mPowerEstimator.calculatePower(durationMs);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,11 @@ public abstract class PowerCalculator {
|
||||
return String.format(Locale.ENGLISH, format, power);
|
||||
}
|
||||
|
||||
static double mAhToUJ(long energyUJ) {
|
||||
static double uJtoMah(long energyUJ) {
|
||||
if (energyUJ == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(b/173765509): Convert properly. This is mJ / V * (h/3600s) = mAh with V = 3.7 fixed.
|
||||
// Leaving for later since desired units of energy have yet to be decided
|
||||
return energyUJ / 1000.0 / 3.7 / 3600;
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.os.BatteryStats;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Slog;
|
||||
@@ -39,9 +39,17 @@ public class ScreenPowerCalculator extends PowerCalculator {
|
||||
private static final String TAG = "ScreenPowerCalculator";
|
||||
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
|
||||
|
||||
// Minimum amount of time the screen should be on to start smearing drain to apps
|
||||
public static final long MIN_ACTIVE_TIME_FOR_SMEARING = 10 * DateUtils.MINUTE_IN_MILLIS;
|
||||
|
||||
private final UsageBasedPowerEstimator mScreenOnPowerEstimator;
|
||||
private final UsageBasedPowerEstimator mScreenFullPowerEstimator;
|
||||
|
||||
private static class PowerAndDuration {
|
||||
public long durationMs;
|
||||
public double powerMah;
|
||||
}
|
||||
|
||||
public ScreenPowerCalculator(PowerProfile powerProfile) {
|
||||
mScreenOnPowerEstimator = new UsageBasedPowerEstimator(
|
||||
powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON));
|
||||
@@ -52,17 +60,40 @@ public class ScreenPowerCalculator extends PowerCalculator {
|
||||
@Override
|
||||
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
|
||||
final long durationMs = computeDuration(batteryStats, rawRealtimeUs,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
final double powerMah = computePower(batteryStats, rawRealtimeUs,
|
||||
BatteryStats.STATS_SINCE_CHARGED, durationMs);
|
||||
if (powerMah != 0) {
|
||||
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
|
||||
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
|
||||
final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
|
||||
final boolean forceUsePowerProfileModel = (query.getFlags()
|
||||
& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL) != 0;
|
||||
|
||||
final boolean useEnergyData = calculateTotalDurationAndPower(totalPowerAndDuration,
|
||||
batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
|
||||
forceUsePowerProfileModel);
|
||||
|
||||
builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN)
|
||||
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE,
|
||||
totalPowerAndDuration.durationMs)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE,
|
||||
totalPowerAndDuration.powerMah);
|
||||
|
||||
// Now deal with each app's UidBatteryConsumer. The results are stored in the
|
||||
// BatteryConsumer.POWER_COMPONENT_SCREEN power component, which is considered smeared,
|
||||
// but the method depends on the data source.
|
||||
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
|
||||
builder.getUidBatteryConsumerBuilders();
|
||||
if (useEnergyData) {
|
||||
final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
|
||||
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
|
||||
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
|
||||
calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.getBatteryStatsUid(),
|
||||
rawRealtimeUs);
|
||||
app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN,
|
||||
appPowerAndDuration.durationMs)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN,
|
||||
appPowerAndDuration.powerMah);
|
||||
}
|
||||
} else {
|
||||
smearScreenBatteryDrain(uidBatteryConsumerBuilders, totalPowerAndDuration,
|
||||
rawRealtimeUs);
|
||||
}
|
||||
// TODO(b/178140704): Attribute *measured* total usage for BatteryUsageStats.
|
||||
// TODO(b/178140704): Attribute (measured/smeared) usage *per app* for BatteryUsageStats.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,51 +102,79 @@ public class ScreenPowerCalculator extends PowerCalculator {
|
||||
@Override
|
||||
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
|
||||
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
|
||||
|
||||
final long energyUJ = batteryStats.getScreenOnEnergy();
|
||||
final boolean isMeasuredDataAvailable = energyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE;
|
||||
|
||||
final long durationMs = computeDuration(batteryStats, rawRealtimeUs, statsType);
|
||||
final double powerMah = getMeasuredOrComputedPower(
|
||||
energyUJ, batteryStats, rawRealtimeUs, statsType, durationMs);
|
||||
if (powerMah == 0) {
|
||||
final PowerAndDuration totalPowerAndDuration = new PowerAndDuration();
|
||||
final boolean useEnergyData = calculateTotalDurationAndPower(totalPowerAndDuration,
|
||||
batteryStats, rawRealtimeUs, statsType, false);
|
||||
if (totalPowerAndDuration.powerMah == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First deal with the SCREEN BatterySipper (since we need this for smearing over apps).
|
||||
final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0);
|
||||
bs.usagePowerMah = powerMah;
|
||||
bs.usageTimeMs = durationMs;
|
||||
bs.usagePowerMah = totalPowerAndDuration.powerMah;
|
||||
bs.usageTimeMs = totalPowerAndDuration.durationMs;
|
||||
bs.sumPower();
|
||||
sippers.add(bs);
|
||||
|
||||
// Now deal with each app's BatterySipper. The results are stored in the screenPowerMah
|
||||
// field, which is considered smeared, but the method depends on the data source.
|
||||
if (isMeasuredDataAvailable) {
|
||||
super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
|
||||
if (useEnergyData) {
|
||||
final PowerAndDuration appPowerAndDuration = new PowerAndDuration();
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper app = sippers.get(i);
|
||||
if (app.drainType == BatterySipper.DrainType.APP) {
|
||||
calculateAppUsingMeasuredEnergy(appPowerAndDuration, app.uidObj, rawRealtimeUs);
|
||||
app.screenPowerMah = appPowerAndDuration.powerMah;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
smearScreenBatterySipper(sippers, bs);
|
||||
smearScreenBatterySipper(sippers, bs, rawRealtimeUs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
|
||||
long rawUptimeUs, int statsType) {
|
||||
/**
|
||||
* Stores duration and power information in totalPowerAndDuration and returns true if measured
|
||||
* energy data is available and should be used by the model.
|
||||
*/
|
||||
private boolean calculateTotalDurationAndPower(PowerAndDuration totalPowerAndDuration,
|
||||
BatteryStats batteryStats, long rawRealtimeUs, int statsType,
|
||||
boolean forceUsePowerProfileModel) {
|
||||
totalPowerAndDuration.durationMs = calculateDuration(batteryStats, rawRealtimeUs,
|
||||
statsType);
|
||||
|
||||
if (!forceUsePowerProfileModel) {
|
||||
final long energyUJ = batteryStats.getScreenOnEnergy();
|
||||
if (energyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
|
||||
totalPowerAndDuration.powerMah = uJtoMah(energyUJ);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats,
|
||||
rawRealtimeUs, statsType, totalPowerAndDuration.durationMs);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void calculateAppUsingMeasuredEnergy(PowerAndDuration appPowerAndDuration,
|
||||
BatteryStats.Uid u, long rawRealtimeUs) {
|
||||
appPowerAndDuration.durationMs = getProcessForegroundTimeMs(u, rawRealtimeUs);
|
||||
|
||||
final long energyUJ = u.getScreenOnEnergy();
|
||||
if (energyUJ < 0) {
|
||||
Slog.wtf(TAG, "Screen energy not supported, so calculateApp shouldn't de called");
|
||||
appPowerAndDuration.powerMah = 0;
|
||||
return;
|
||||
}
|
||||
if (energyUJ == 0) return;
|
||||
app.screenPowerMah = mAhToUJ(u.getScreenOnEnergy());
|
||||
|
||||
appPowerAndDuration.powerMah = uJtoMah(energyUJ);
|
||||
}
|
||||
|
||||
private long computeDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
|
||||
private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) {
|
||||
return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000;
|
||||
}
|
||||
|
||||
private double computePower(BatteryStats batteryStats, long rawRealtimeUs, int statsType,
|
||||
long durationMs) {
|
||||
private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, long rawRealtimeUs,
|
||||
int statsType, long durationMs) {
|
||||
double power = mScreenOnPowerEstimator.calculatePower(durationMs);
|
||||
for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
|
||||
final long brightnessTime =
|
||||
@@ -131,35 +190,25 @@ public class ScreenPowerCalculator extends PowerCalculator {
|
||||
return power;
|
||||
}
|
||||
|
||||
private double getMeasuredOrComputedPower(long measuredEnergyUJ,
|
||||
BatteryStats batteryStats, long rawRealtimeUs, int statsType, long durationMs) {
|
||||
|
||||
if (measuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
|
||||
return mAhToUJ(measuredEnergyUJ);
|
||||
} else {
|
||||
return computePower(batteryStats, rawRealtimeUs, statsType, durationMs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper,
|
||||
long rawRealtimeUs) {
|
||||
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);
|
||||
final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
|
||||
activityTimeArray.put(uid.getUid(), timeMs);
|
||||
totalActivityTimeMs += timeMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
|
||||
if (screenSipper != null && totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
|
||||
final double totalScreenPowerMah = screenSipper.totalPowerMah;
|
||||
for (int i = sippers.size() - 1; i >= 0; i--) {
|
||||
final BatterySipper sipper = sippers.get(i);
|
||||
@@ -170,10 +219,37 @@ public class ScreenPowerCalculator extends PowerCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private void smearScreenBatteryDrain(
|
||||
SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders,
|
||||
PowerAndDuration totalPowerAndDuration, long rawRealtimeUs) {
|
||||
long totalActivityTimeMs = 0;
|
||||
final SparseLongArray activityTimeArray = new SparseLongArray();
|
||||
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
|
||||
final BatteryStats.Uid uid = uidBatteryConsumerBuilders.valueAt(i).getBatteryStatsUid();
|
||||
final long timeMs = getProcessForegroundTimeMs(uid, rawRealtimeUs);
|
||||
activityTimeArray.put(uid.getUid(), timeMs);
|
||||
totalActivityTimeMs += timeMs;
|
||||
}
|
||||
|
||||
if (totalActivityTimeMs >= MIN_ACTIVE_TIME_FOR_SMEARING) {
|
||||
final double totalScreenPowerMah = totalPowerAndDuration.powerMah;
|
||||
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
|
||||
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
|
||||
final long durationMs = activityTimeArray.get(app.getUid(), 0);
|
||||
final double powerMah = totalScreenPowerMah * durationMs / totalActivityTimeMs;
|
||||
app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN, durationMs)
|
||||
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN, powerMah);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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;
|
||||
public long getProcessForegroundTimeMs(BatteryStats.Uid uid, long rawRealTimeUs) {
|
||||
final int[] foregroundTypes = {BatteryStats.Uid.PROCESS_STATE_TOP};
|
||||
|
||||
long timeUs = 0;
|
||||
|
||||
@@ -218,7 +218,7 @@ public class BatteryStatsHelperTest extends TestCase {
|
||||
sippers.add(sipperBg);
|
||||
sippers.add(sipperFg);
|
||||
|
||||
spc.smearScreenBatterySipper(sippers, mScreenBatterySipper);
|
||||
spc.smearScreenBatterySipper(sippers, mScreenBatterySipper, 0);
|
||||
|
||||
assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0);
|
||||
assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0);
|
||||
@@ -253,7 +253,7 @@ public class BatteryStatsHelperTest extends TestCase {
|
||||
doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP),
|
||||
anyLong(), anyInt());
|
||||
|
||||
final long time = spc.getProcessForegroundTimeMs(mUid);
|
||||
final long time = spc.getProcessForegroundTimeMs(mUid, 1000);
|
||||
|
||||
assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
|
||||
}
|
||||
@@ -296,7 +296,7 @@ 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(spc).getProcessForegroundTimeMs(eq(uid));
|
||||
doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid), anyLong());
|
||||
doReturn(uidCode).when(uid).getUid();
|
||||
sipper.uidObj = uid;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,12 @@ package com.android.internal.os;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Process;
|
||||
import android.os.SystemBatteryConsumer;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -33,20 +37,37 @@ import org.junit.runner.RunWith;
|
||||
@SmallTest
|
||||
public class ScreenPowerCalculatorTest {
|
||||
private static final double PRECISION = 0.00001;
|
||||
private static final int APP_UID1 = Process.FIRST_APPLICATION_UID + 42;
|
||||
private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 43;
|
||||
private static final long MINUTE_IN_MS = 60 * 1000;
|
||||
private static final long MINUTE_IN_US = 60 * 1000 * 1000;
|
||||
|
||||
@Rule
|
||||
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
|
||||
.setAveragePower(PowerProfile.POWER_SCREEN_ON, 360.0)
|
||||
.setAveragePower(PowerProfile.POWER_SCREEN_FULL, 3600.0);
|
||||
.setAveragePower(PowerProfile.POWER_SCREEN_ON, 36.0)
|
||||
.setAveragePower(PowerProfile.POWER_SCREEN_FULL, 48.0);
|
||||
|
||||
@Test
|
||||
public void testTimerBasedModel() {
|
||||
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
|
||||
public void testEnergyBasedModel() {
|
||||
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
|
||||
|
||||
stats.noteScreenStateLocked(Display.STATE_ON, 1000, 1000, 1000);
|
||||
stats.noteScreenBrightnessLocked(100, 1000, 1000);
|
||||
stats.noteScreenBrightnessLocked(200, 2000, 2000);
|
||||
stats.noteScreenStateLocked(Display.STATE_OFF, 3000, 3000, 3000);
|
||||
batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0);
|
||||
batteryStats.updateDisplayEnergyLocked(0, Display.STATE_ON, 2 * MINUTE_IN_MS);
|
||||
|
||||
setFgState(APP_UID1, true, 2 * MINUTE_IN_MS, 2 * MINUTE_IN_MS);
|
||||
setFgState(APP_UID1, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
|
||||
setFgState(APP_UID2, true, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
|
||||
|
||||
batteryStats.updateDisplayEnergyLocked(300_000_000, Display.STATE_ON,
|
||||
60 * MINUTE_IN_MS);
|
||||
|
||||
batteryStats.noteScreenStateLocked(Display.STATE_OFF,
|
||||
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
|
||||
|
||||
batteryStats.updateDisplayEnergyLocked(100_000_000, Display.STATE_DOZE,
|
||||
120 * MINUTE_IN_MS);
|
||||
|
||||
mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US);
|
||||
|
||||
ScreenPowerCalculator calculator =
|
||||
new ScreenPowerCalculator(mStatsRule.getPowerProfile());
|
||||
@@ -56,8 +77,79 @@ public class ScreenPowerCalculatorTest {
|
||||
SystemBatteryConsumer consumer =
|
||||
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
|
||||
assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
|
||||
.isEqualTo(2000);
|
||||
.isEqualTo(80 * MINUTE_IN_MS);
|
||||
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
|
||||
.isWithin(PRECISION).of(1.2);
|
||||
.isWithin(PRECISION).of(30.03003);
|
||||
|
||||
UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
|
||||
assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
|
||||
.isEqualTo(18 * MINUTE_IN_MS);
|
||||
assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
|
||||
.isWithin(PRECISION).of(8.44594);
|
||||
|
||||
UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
|
||||
assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
|
||||
.isEqualTo(90 * MINUTE_IN_MS);
|
||||
assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
|
||||
.isWithin(PRECISION).of(21.58408);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPowerProfileBasedModel() {
|
||||
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
|
||||
|
||||
batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0);
|
||||
|
||||
setFgState(APP_UID1, true, 2 * MINUTE_IN_MS, 2 * MINUTE_IN_MS);
|
||||
|
||||
batteryStats.noteScreenBrightnessLocked(100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS);
|
||||
batteryStats.noteScreenBrightnessLocked(200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
|
||||
|
||||
setFgState(APP_UID1, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
|
||||
|
||||
setFgState(APP_UID2, true, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
|
||||
|
||||
batteryStats.noteScreenStateLocked(Display.STATE_OFF,
|
||||
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
|
||||
|
||||
mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US);
|
||||
|
||||
ScreenPowerCalculator calculator =
|
||||
new ScreenPowerCalculator(mStatsRule.getPowerProfile());
|
||||
|
||||
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
|
||||
calculator);
|
||||
|
||||
SystemBatteryConsumer consumer =
|
||||
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN);
|
||||
assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE))
|
||||
.isEqualTo(80 * MINUTE_IN_MS);
|
||||
assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE))
|
||||
.isWithin(PRECISION).of(88.4);
|
||||
|
||||
UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
|
||||
assertThat(uid1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
|
||||
.isEqualTo(18 * MINUTE_IN_MS);
|
||||
assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
|
||||
.isWithin(PRECISION).of(14.73333);
|
||||
|
||||
UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
|
||||
assertThat(uid2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_SCREEN))
|
||||
.isEqualTo(90 * MINUTE_IN_MS);
|
||||
assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN))
|
||||
.isWithin(PRECISION).of(73.66666);
|
||||
}
|
||||
|
||||
private void setFgState(int uid, boolean fgOn, long realtimeMs, long uptimeMs) {
|
||||
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
|
||||
if (fgOn) {
|
||||
batteryStats.noteActivityResumedLocked(uid, realtimeMs, uptimeMs);
|
||||
batteryStats.noteUidProcessStateLocked(uid, ActivityManager.PROCESS_STATE_TOP,
|
||||
realtimeMs, uptimeMs);
|
||||
} else {
|
||||
batteryStats.noteActivityPausedLocked(uid, realtimeMs, uptimeMs);
|
||||
batteryStats.noteUidProcessStateLocked(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
|
||||
realtimeMs, uptimeMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user