Loading core/java/android/os/BatteryConsumer.java +6 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading core/java/android/os/UidBatteryConsumer.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading core/java/com/android/internal/os/PowerCalculator.java +5 −1 Original line number Diff line number Diff line Loading @@ -143,7 +143,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; Loading core/java/com/android/internal/os/ScreenPowerCalculator.java +124 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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)); Loading @@ -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) { 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, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); .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. } /** Loading @@ -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 = Loading @@ -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); Loading @@ -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; Loading Loading
core/java/android/os/BatteryConsumer.java +6 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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 { Loading @@ -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; Loading
core/java/android/os/UidBatteryConsumer.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; } Loading
core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } Loading
core/java/com/android/internal/os/PowerCalculator.java +5 −1 Original line number Diff line number Diff line Loading @@ -143,7 +143,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; Loading
core/java/com/android/internal/os/ScreenPowerCalculator.java +124 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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)); Loading @@ -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) { 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, durationMs) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); .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. } /** Loading @@ -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 = Loading @@ -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); Loading @@ -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; Loading