Merge "BatteryStats measured energy for Wifi & Bluetooth" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-17 16:32:53 +00:00
committed by Android (Google) Code Review
14 changed files with 588 additions and 170 deletions

View File

@@ -986,13 +986,13 @@ public abstract class BatteryStats implements Parcelable {
public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which);
/**
* Returns the battery consumption (in microcoulombs) of the screen while on and uid active,
* Returns the battery consumption (in microcoulombs) of bluetooth for this uid,
* derived from on device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getScreenOnMeasuredBatteryConsumptionUC();
public abstract long getBluetoothMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from
@@ -1003,6 +1003,24 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getCpuMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of the screen while on and uid active,
* derived from on device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getScreenOnMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of wifi for this uid,
* derived from on device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getWifiMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) used by this uid for each
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
@@ -2505,11 +2523,29 @@ public abstract class BatteryStats implements Parcelable {
};
/**
* Returned value if power data is unavailable
* Returned value if power data is unavailable.
*
* {@hide}
*/
public static final long POWER_DATA_UNAVAILABLE = -1;
public static final long POWER_DATA_UNAVAILABLE = -1L;
/**
* Returns the battery consumption (in microcoulombs) of bluetooth, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getBluetoothMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power
* measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getCpuMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
@@ -2530,13 +2566,13 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getScreenDozeMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power
* measurement data.
* Returns the battery consumption (in microcoulombs) of wifi, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
*
* {@hide}
*/
public abstract long getCpuMeasuredBatteryConsumptionUC();
public abstract long getWifiMeasuredBatteryConsumptionUC();
/**
* Returns the battery consumption (in microcoulombs) that each

View File

@@ -110,7 +110,7 @@ public final class WifiActivityEnergyInfo implements Parcelable {
}
// Calculate energy used using PowerProfile.
PowerProfile powerProfile = new PowerProfile(context);
final double rxIdleCurrent = powerProfile.getAveragePower(
final double idleCurrent = powerProfile.getAveragePower(
PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
final double rxCurrent = powerProfile.getAveragePower(
PowerProfile.POWER_WIFI_CONTROLLER_RX);
@@ -121,7 +121,7 @@ public final class WifiActivityEnergyInfo implements Parcelable {
return (long) ((txDurationMillis * txCurrent
+ rxDurationMillis * rxCurrent
+ idleDurationMillis * rxIdleCurrent)
+ idleDurationMillis * idleCurrent)
* voltage);
}

View File

@@ -169,7 +169,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
static final int VERSION = 194;
static final int VERSION = 195;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1009,8 +1009,12 @@ public class BatteryStatsImpl extends BatteryStats {
protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats;
/** Last known screen state. Needed for apportioning display energy. */
int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN;
/** Bluetooth Power calculator for attributing measured bluetooth charge consumption to uids */
@Nullable BluetoothPowerCalculator mBluetoothPowerCalculator = null;
/** Cpu Power calculator for attributing measured cpu charge consumption to uids */
@Nullable CpuPowerCalculator mCpuPowerCalculator = null;
/** Wifi Power calculator for attributing measured wifi charge consumption to uids */
@Nullable WifiPowerCalculator mWifiPowerCalculator = null;
/**
* These provide time bases that discount the time the device is plugged
@@ -6966,6 +6970,16 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
@Override
public long getBluetoothMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH);
}
@Override
public long getCpuMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
}
@Override
public long getScreenOnMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
@@ -6977,8 +6991,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
@Override
public long getCpuMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
public long getWifiMeasuredBatteryConsumptionUC() {
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_WIFI);
}
/**
@@ -7815,6 +7829,26 @@ public class BatteryStatsImpl extends BatteryStats {
return mUidMeasuredEnergyStats.getAccumulatedCustomBucketCharges();
}
@Override
public long getBluetoothMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH);
}
@Override
public long getCpuMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
}
@Override
public long getScreenOnMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
}
@Override
public long getWifiMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_WIFI);
}
/**
* Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time
* since last marked. Also sets the mark time for both these timers.
@@ -8482,16 +8516,6 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
@Override
public long getScreenOnMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
}
@Override
public long getCpuMeasuredBatteryConsumptionUC() {
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
}
void initNetworkActivityLocked() {
detachIfNotNull(mNetworkByteActivityCounters);
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -11437,7 +11461,7 @@ public class BatteryStatsImpl extends BatteryStats {
* @param info The energy information from the WiFi controller.
*/
public void updateWifiState(@Nullable final WifiActivityEnergyInfo info,
long elapsedRealtimeMs, long uptimeMs) {
final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating wifi stats: " + Arrays.toString(mWifiIfaces));
}
@@ -11459,9 +11483,21 @@ public class BatteryStatsImpl extends BatteryStats {
if (delta != null) {
mNetworkStatsPool.release(delta);
}
if (mIgnoreNextExternalStats) {
// TODO: Strictly speaking, we should re-mark all 5 timers for each uid (and the
// global one) here like we do for display. But I'm not sure it's worth the
// complicated code for a codepath that shouldn't ever actually happen in real
// life.
}
return;
}
final ArrayMap<Uid, Double> uidEstimatedConsumptionMah =
(mGlobalMeasuredEnergyStats != null
&& mWifiPowerCalculator != null && consumedChargeUC > 0) ?
new ArrayMap<>() : null;
double totalEstimatedConsumptionMah = 0;
SparseLongArray rxPackets = new SparseLongArray();
SparseLongArray txPackets = new SparseLongArray();
long totalTxPackets = 0;
@@ -11496,6 +11532,7 @@ public class BatteryStatsImpl extends BatteryStats {
mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
entry.rxPackets);
// TODO(b/182845426): What if u was a mapped isolated uid? Shouldn't we sum?
rxPackets.put(u.getUid(), entry.rxPackets);
// Sum the total number of packets so that the Rx Power can
@@ -11515,12 +11552,42 @@ public class BatteryStatsImpl extends BatteryStats {
mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
entry.txPackets);
// TODO(b/182845426): What if u was a mapped isolated uid? Shouldn't we sum?
txPackets.put(u.getUid(), entry.txPackets);
// Sum the total number of packets so that the Tx Power can
// be evenly distributed amongst the apps.
totalTxPackets += entry.txPackets;
}
// Calculate consumed energy for this uid. Only do so if WifiReporting isn't
// enabled (if it is, we'll do it later instead using info).
if (uidEstimatedConsumptionMah != null && info == null && !mHasWifiReporting) {
final long uidRunningMs = u.mWifiRunningTimer
.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000;
if (uidRunningMs > 0) u.mWifiRunningTimer.setMark(elapsedRealtimeMs);
final long uidScanMs = u.mWifiScanTimer
.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000;
if (uidScanMs > 0) u.mWifiScanTimer.setMark(elapsedRealtimeMs);
long uidBatchScanMs = 0;
for (int bn = 0; bn < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bn++) {
if (u.mWifiBatchedScanTimer[bn] != null) {
long bnMs = u.mWifiBatchedScanTimer[bn]
.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000;
if (bnMs > 0) {
u.mWifiBatchedScanTimer[bn].setMark(elapsedRealtimeMs);
}
uidBatchScanMs += bnMs;
}
}
addDoubleToUidMap(uidEstimatedConsumptionMah, u,
mWifiPowerCalculator.calcPowerWithoutControllerDataMah(
entry.rxPackets, entry.txPackets,
uidRunningMs, uidScanMs, uidBatchScanMs));
}
}
mNetworkStatsPool.release(delta);
delta = null;
@@ -11581,15 +11648,14 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i = 0; i < uidStatsSize; i++) {
final Uid uid = mUidStats.valueAt(i);
long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
final long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs; // not final
long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs; // not final
if (scanTimeSinceMarkMs > 0) {
// Set the new mark so that next time we get new data since this point.
uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
long scanRxTimeSinceMarkMs = scanTimeSinceMarkMs;
long scanTxTimeSinceMarkMs = scanTimeSinceMarkMs;
// Our total scan time is more than the reported Tx/Rx time.
// This is possible because the cost of a scan is approximate.
// Let's normalize the result so that we evenly blame each app
@@ -11623,6 +11689,7 @@ public class BatteryStatsImpl extends BatteryStats {
// Distribute evenly the power consumed while Idle to each app holding a WiFi
// lock.
long myIdleTimeMs = 0;
final long wifiLockTimeSinceMarkMs =
uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
@@ -11630,8 +11697,7 @@ public class BatteryStatsImpl extends BatteryStats {
// Set the new mark so that next time we get new data since this point.
uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs);
final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs)
/ totalWifiLockTimeMs;
myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs) / totalWifiLockTimeMs;
if (DEBUG_ENERGY) {
Slog.d(TAG, " IdleTime for UID " + uid.getUid() + ": "
+ myIdleTimeMs + " ms");
@@ -11639,6 +11705,12 @@ public class BatteryStatsImpl extends BatteryStats {
uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
.addCountLocked(myIdleTimeMs);
}
if (uidEstimatedConsumptionMah != null) {
double uidEstMah = mWifiPowerCalculator.calcPowerFromControllerDataMah(
scanRxTimeSinceMarkMs, scanTxTimeSinceMarkMs, myIdleTimeMs);
addDoubleToUidMap(uidEstimatedConsumptionMah, uid, uidEstMah);
}
}
if (DEBUG_ENERGY) {
@@ -11658,6 +11730,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
.addCountLocked(myTxTimeMs);
if (uidEstimatedConsumptionMah != null) {
addDoubleToUidMap(uidEstimatedConsumptionMah, uid,
mWifiPowerCalculator.calcPowerFromControllerDataMah(
0, myTxTimeMs, 0));
}
}
// Distribute the remaining Rx power appropriately between all apps that received
@@ -11672,6 +11749,11 @@ public class BatteryStatsImpl extends BatteryStats {
}
uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
.addCountLocked(myRxTimeMs);
if (uidEstimatedConsumptionMah != null) {
addDoubleToUidMap(uidEstimatedConsumptionMah, uid,
mWifiPowerCalculator.calcPowerFromControllerDataMah(
myRxTimeMs, 0, 0));
}
}
// Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
@@ -11690,10 +11772,11 @@ public class BatteryStatsImpl extends BatteryStats {
// POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
double controllerMaMs = 0;
if (opVolt != 0) {
// We store the power drain as mAms.
mWifiActivity.getPowerCounter().addCountLocked(
(long) (info.getControllerEnergyUsedMicroJoules() / opVolt));
controllerMaMs = info.getControllerEnergyUsedMicroJoules() / opVolt;
mWifiActivity.getPowerCounter().addCountLocked((long) controllerMaMs);
}
// Converting uWs to mAms.
// Conversion: (uWs * (1000ms / 1s) * (1mW / 1000uW)) / mV = mAms
@@ -11705,6 +11788,29 @@ public class BatteryStatsImpl extends BatteryStats {
(monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR);
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mTmpRailStats.resetWifiTotalEnergyUsed();
if (uidEstimatedConsumptionMah != null) {
totalEstimatedConsumptionMah = Math.max(controllerMaMs / MILLISECONDS_IN_HOUR,
mWifiPowerCalculator.calcPowerFromControllerDataMah(
rxTimeMs, txTimeMs, idleTimeMs));
}
}
// Update the MeasuredEnergyStats information.
if (uidEstimatedConsumptionMah != null) {
mGlobalMeasuredEnergyStats.updateStandardBucket(
MeasuredEnergyStats.POWER_BUCKET_WIFI, consumedChargeUC);
// Now calculate the consumption for each uid, according to its proportional usage.
if (!mHasWifiReporting) {
final long globalTimeMs = mGlobalWifiRunningTimer
.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000;
mGlobalWifiRunningTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah = mWifiPowerCalculator
.calcGlobalPowerWithoutControllerDataMah(globalTimeMs);
}
distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_WIFI,
consumedChargeUC, uidEstimatedConsumptionMah, totalEstimatedConsumptionMah);
}
}
}
@@ -11948,7 +12054,7 @@ public class BatteryStatsImpl extends BatteryStats {
* @param info The energy information from the bluetooth controller.
*/
public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info,
long elapsedRealtimeMs, long uptimeMs) {
final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating bluetooth stats: " + info);
}
@@ -11980,6 +12086,11 @@ public class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, " Idle Time: " + idleTimeMs + " ms");
}
final ArrayMap<Uid, Double> uidEstimatedConsumptionMah =
(mGlobalMeasuredEnergyStats != null
&& mBluetoothPowerCalculator != null && consumedChargeUC > 0) ?
new ArrayMap<>() : null;
long totalScanTimeMs = 0;
final int uidCount = mUidStats.size();
@@ -12038,6 +12149,12 @@ public class BatteryStatsImpl extends BatteryStats {
counter.getRxTimeCounter().addCountLocked(scanTimeRxSinceMarkMs);
counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
if (uidEstimatedConsumptionMah != null) {
addDoubleToUidMap(uidEstimatedConsumptionMah, u,
mBluetoothPowerCalculator.calculatePowerMah(
scanTimeRxSinceMarkMs, scanTimeTxSinceMarkMs, 0));
}
leftOverRxTimeMs -= scanTimeRxSinceMarkMs;
leftOverTxTimeMs -= scanTimeTxSinceMarkMs;
}
@@ -12098,6 +12215,11 @@ public class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
}
counter.getRxTimeCounter().addCountLocked(timeRxMs);
if (uidEstimatedConsumptionMah != null) {
addDoubleToUidMap(uidEstimatedConsumptionMah, u,
mBluetoothPowerCalculator.calculatePowerMah(timeRxMs, 0, 0));
}
}
if (totalTxBytes > 0 && txBytes > 0) {
@@ -12106,6 +12228,11 @@ public class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
}
counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
if (uidEstimatedConsumptionMah != null) {
addDoubleToUidMap(uidEstimatedConsumptionMah, u,
mBluetoothPowerCalculator.calculatePowerMah(0, timeTxMs, 0));
}
}
}
}
@@ -12117,12 +12244,26 @@ public class BatteryStatsImpl extends BatteryStats {
// POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
double controllerMaMs = 0;
if (opVolt != 0) {
controllerMaMs = (info.getControllerEnergyUsed() - mLastBluetoothActivityInfo.energy)
/ opVolt;
// We store the power drain as mAms.
mBluetoothActivity.getPowerCounter().addCountLocked(
(long) ((info.getControllerEnergyUsed() - mLastBluetoothActivityInfo.energy)
/ opVolt));
mBluetoothActivity.getPowerCounter().addCountLocked((long) controllerMaMs);
}
// Update the MeasuredEnergyStats information.
if (uidEstimatedConsumptionMah != null) {
mGlobalMeasuredEnergyStats.updateStandardBucket(
MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH, consumedChargeUC);
double totalEstimatedMah
= mBluetoothPowerCalculator.calculatePowerMah(rxTimeMs, txTimeMs, idleTimeMs);
totalEstimatedMah = Math.max(totalEstimatedMah, controllerMaMs / MILLISECONDS_IN_HOUR);
distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH,
consumedChargeUC, uidEstimatedConsumptionMah, totalEstimatedMah);
}
mLastBluetoothActivityInfo.set(info);
}
@@ -12311,37 +12452,17 @@ public class BatteryStatsImpl extends BatteryStats {
// If multidisplay becomes a reality, this is probably more reasonable than pooling.
// On the first pass, collect total time since mark so that we can normalize power.
long totalFgTimeMs = 0L;
final ArrayMap<Uid, Long> fgTimeMsArray = new ArrayMap<>();
final ArrayMap<Uid, Double> fgTimeUsArray = new ArrayMap<>();
final long elapsedRealtimeUs = elapsedRealtimeMs * 1000;
// TODO(b/175726779): Update and optimize the algorithm (e.g. avoid iterating over ALL uids)
final int uidStatsSize = mUidStats.size();
for (int i = 0; i < uidStatsSize; i++) {
final Uid uid = mUidStats.valueAt(i);
final long fgTimeMs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true) / 1000;
if (fgTimeMs == 0) continue;
fgTimeMsArray.put(uid, fgTimeMs);
totalFgTimeMs += fgTimeMs;
}
long totalDisplayChargeMC = chargeUC / 1000; // not final
// Actually assign and distribute power usage to apps based on their fg time since mark.
// TODO(b/175726326): Decide on 'energy' units and make sure algorithm won't overflow.
final long fgTimeArraySize = fgTimeMsArray.size();
for (int i = 0; i < fgTimeArraySize; i++) {
final Uid uid = fgTimeMsArray.keyAt(i);
final long fgTimeMs = fgTimeMsArray.valueAt(i);
// Using long division: "appEnergy = totalEnergy * appFg/totalFg + 0.5" with rounding
final long appDisplayChargeMC =
(totalDisplayChargeMC * fgTimeMs + (totalFgTimeMs / 2))
/ totalFgTimeMs;
uid.addChargeToStandardBucketLocked(appDisplayChargeMC * 1000, powerBucket);
// To mitigate round-off errors, remove this app from numerator & denominator totals
totalDisplayChargeMC -= appDisplayChargeMC;
totalFgTimeMs -= fgTimeMs;
final long fgTimeUs = uid.markProcessForegroundTimeUs(elapsedRealtimeMs, true);
if (fgTimeUs == 0) continue;
fgTimeUsArray.put(uid, (double) fgTimeUs);
}
distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0);
}
/**
@@ -12388,6 +12509,54 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
/**
* Attributes energy (for the given bucket) to each uid according to the following formula:
* blamedEnergy[uid] = totalEnergy * ratioNumerators[uid] / ratioDenominator;
* <p>Does nothing if ratioDenominator is 0.
*
* <p>Here, ratioDenominator = max(sumOfAllRatioNumerators, minRatioDenominator),
* so if given minRatioDenominator <= 0, then sumOfAllRatioNumerators will be used implicitly.
*
* <p>Note that ratioNumerators and minRatioDenominator must use the same units, but need not
* use the same units as totalConsumedChargeUC (which must be in microcoulombs).
*
* <p>A consequence of minRatioDenominator is that the sum over all uids might be less than
* totalConsumedChargeUC. This is intentional; the remainder is purposefully unnaccounted rather
* than incorrectly blamed on uids, and implies unknown (non-uid) sources of drain.
*/
// TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>.
private void distributeEnergyToUidsLocked(@StandardPowerBucket int bucket,
long totalConsumedChargeUC, ArrayMap<Uid, Double> ratioNumerators,
double minRatioDenominator) {
// If the sum of all app usage was greater than the total, use that instead:
double sumRatioNumerators = 0;
for (int i = ratioNumerators.size() - 1; i >= 0; i--) {
sumRatioNumerators += ratioNumerators.valueAt(i);
}
final double ratioDenominator = Math.max(sumRatioNumerators, minRatioDenominator);
if (ratioDenominator <= 0) return;
for (int i = ratioNumerators.size() - 1; i >= 0; i--) {
final Uid uid = ratioNumerators.keyAt(i);
final double ratioNumerator = ratioNumerators.valueAt(i);
final long uidActualUC
= (long) (totalConsumedChargeUC * ratioNumerator / ratioDenominator + 0.5);
uid.addChargeToStandardBucketLocked(uidActualUC, bucket);
}
}
/** Adds the summand to the value stored in uidMap for the given uid. */
// TODO(b/182845832): Use some sort of "SparseDoubleArray" instead of ArrayMap<Uid, Double>.
private static void addDoubleToUidMap(ArrayMap<Uid, Double> uidMap, Uid uid, double summand) {
if (uidMap == null) return;
final Double oldVal = uidMap.get(uid);
if (oldVal != null) {
summand += oldVal;
}
uidMap.put(uid, summand);
}
/**
* Read and record Rail Energy data.
*/
@@ -14222,15 +14391,20 @@ public class BatteryStatsImpl extends BatteryStats {
if (mGlobalMeasuredEnergyStats == null) {
mGlobalMeasuredEnergyStats =
new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
return;
} else {
supportedBucketMismatch = !mGlobalMeasuredEnergyStats.isSupportEqualTo(
supportedStandardBuckets, numCustomBuckets);
}
if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH]) {
mBluetoothPowerCalculator = new BluetoothPowerCalculator(mPowerProfile);
}
if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU]) {
mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
}
if (supportedStandardBuckets[MeasuredEnergyStats.POWER_BUCKET_WIFI]) {
mWifiPowerCalculator = new WifiPowerCalculator(mPowerProfile);
}
}
if (supportedBucketMismatch) {

View File

@@ -15,8 +15,11 @@
*/
package com.android.internal.os;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryStats.ControllerActivityCounter;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
@@ -65,17 +68,19 @@ public class BluetoothPowerCalculator extends PowerCalculator {
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateApp(app, total);
calculateApp(app, total, query);
if (app.getUid() == Process.BLUETOOTH_UID) {
app.excludeFromBatteryUsageStats();
systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
}
}
final BatteryStats.ControllerActivityCounter activityCounter =
final long measuredChargeUC = query.shouldForceUsePowerProfileModel() ?
POWER_DATA_UNAVAILABLE : batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
final ControllerActivityCounter activityCounter =
batteryStats.getBluetoothControllerActivity();
final long systemDurationMs = calculateDuration(activityCounter);
final double systemPowerMah = calculatePower(activityCounter);
final double systemPowerMah = calculatePowerMah(measuredChargeUC, activityCounter);
// Subtract what the apps used, but clamp to 0.
final long systemComponentDurationMs = Math.max(0, systemDurationMs - total.durationMs);
@@ -91,11 +96,16 @@ public class BluetoothPowerCalculator extends PowerCalculator {
systemComponentPowerMah);
}
private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total) {
final BatteryStats.ControllerActivityCounter activityCounter =
private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total,
BatteryUsageStatsQuery query) {
final long measuredChargeUC = query.shouldForceUsePowerProfileModel() ?
POWER_DATA_UNAVAILABLE :
app.getBatteryStatsUid().getBluetoothMeasuredBatteryConsumptionUC();
final ControllerActivityCounter activityCounter =
app.getBatteryStatsUid().getBluetoothControllerActivity();
final long durationMs = calculateDuration(activityCounter);
final double powerMah = calculatePower(activityCounter);
final double powerMah = calculatePowerMah(measuredChargeUC, activityCounter);
app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah);
@@ -121,10 +131,11 @@ public class BluetoothPowerCalculator extends PowerCalculator {
}
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
final BatteryStats.ControllerActivityCounter activityCounter =
final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
final ControllerActivityCounter activityCounter =
batteryStats.getBluetoothControllerActivity();
final double systemPowerMah = calculatePower(activityCounter);
final long systemDurationMs = calculateDuration(activityCounter);
final double systemPowerMah = calculatePowerMah(measuredChargeUC, activityCounter);
// Subtract what the apps used, but clamp to 0.
final double powerMah = Math.max(0, systemPowerMah - total.powerMah);
@@ -152,10 +163,11 @@ public class BluetoothPowerCalculator extends PowerCalculator {
private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
PowerAndDuration total) {
final BatteryStats.ControllerActivityCounter activityCounter =
u.getBluetoothControllerActivity();
final long measuredChargeUC = u.getBluetoothMeasuredBatteryConsumptionUC();
final ControllerActivityCounter activityCounter = u.getBluetoothControllerActivity();
final long durationMs = calculateDuration(activityCounter);
final double powerMah = calculatePower(activityCounter);
final double powerMah = calculatePowerMah(measuredChargeUC, activityCounter);
app.bluetoothRunningTimeMs = durationMs;
app.bluetoothPowerMah = powerMah;
@@ -166,7 +178,7 @@ public class BluetoothPowerCalculator extends PowerCalculator {
total.powerMah += powerMah;
}
private long calculateDuration(BatteryStats.ControllerActivityCounter counter) {
private long calculateDuration(ControllerActivityCounter counter) {
if (counter == null) {
return 0;
}
@@ -176,7 +188,11 @@ public class BluetoothPowerCalculator extends PowerCalculator {
+ counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
}
private double calculatePower(BatteryStats.ControllerActivityCounter counter) {
/** Returns bluetooth power usage based on the best data available. */
private double calculatePowerMah(long measuredChargeUC, ControllerActivityCounter counter) {
if (measuredChargeUC != POWER_DATA_UNAVAILABLE) {
return uCtoMah(measuredChargeUC);
}
if (counter == null) {
return 0;
}
@@ -195,6 +211,11 @@ public class BluetoothPowerCalculator extends PowerCalculator {
counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
final long txTimeMs =
counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
return calculatePowerMah(rxTimeMs, txTimeMs, idleTimeMs);
}
/** Returns estimated bluetooth power usage based on usage times. */
public double calculatePowerMah(long rxTimeMs, long txTimeMs, long idleTimeMs) {
return ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
/ (1000 * 60 * 60);
}

View File

@@ -15,6 +15,8 @@
*/
package com.android.internal.os;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
@@ -79,11 +81,6 @@ public class WifiPowerCalculator extends PowerCalculator {
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
// so always check this field.
final boolean hasWifiPowerReporting =
mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
builder.getOrCreateSystemBatteryConsumerBuilder(
SystemBatteryConsumer.DRAIN_TYPE_WIFI);
@@ -97,7 +94,8 @@ public class WifiPowerCalculator extends PowerCalculator {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED,
hasWifiPowerReporting);
batteryStats.hasWifiActivityReporting(),
query.shouldForceUsePowerProfileModel());
totalAppDurationMs += powerDurationAndTraffic.durationMs;
totalAppPowerMah += powerDurationAndTraffic.powerMah;
@@ -115,7 +113,9 @@ public class WifiPowerCalculator extends PowerCalculator {
calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED,
hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
batteryStats.hasWifiActivityReporting(),
query.shouldForceUsePowerProfileModel(),
totalAppDurationMs, totalAppPowerMah);
systemBatteryConsumerBuilder
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
@@ -135,11 +135,6 @@ public class WifiPowerCalculator extends PowerCalculator {
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
// batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
// so always check this field.
final boolean hasWifiPowerReporting =
mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
long totalAppDurationMs = 0;
@@ -149,7 +144,7 @@ public class WifiPowerCalculator extends PowerCalculator {
final BatterySipper app = sippers.get(i);
if (app.drainType == BatterySipper.DrainType.APP) {
calculateApp(powerDurationAndTraffic, app.uidObj, rawRealtimeUs, statsType,
hasWifiPowerReporting);
batteryStats.hasWifiActivityReporting(), /* force use power model*/ false);
totalAppDurationMs += powerDurationAndTraffic.durationMs;
totalAppPowerMah += powerDurationAndTraffic.powerMah;
@@ -169,7 +164,8 @@ public class WifiPowerCalculator extends PowerCalculator {
}
calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs, statsType,
hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
batteryStats.hasWifiActivityReporting(), /* force use power model*/ false,
totalAppDurationMs, totalAppPowerMah);
bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
@@ -180,8 +176,9 @@ public class WifiPowerCalculator extends PowerCalculator {
}
private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic, BatteryStats.Uid u,
long rawRealtimeUs,
int statsType, boolean hasWifiPowerReporting) {
long rawRealtimeUs, int statsType,
boolean hasWifiActivityReporting, boolean shouldForceUsePowerProfileModel) {
powerDurationAndTraffic.wifiRxPackets = u.getNetworkActivityPackets(
BatteryStats.NETWORK_WIFI_RX_DATA,
statsType);
@@ -195,7 +192,14 @@ public class WifiPowerCalculator extends PowerCalculator {
BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
if (hasWifiPowerReporting) {
final long measuredChargeUC = u.getWifiMeasuredBatteryConsumptionUC();
final boolean isMeasuredPowerAvailable
= !shouldForceUsePowerProfileModel && measuredChargeUC != POWER_DATA_UNAVAILABLE;
if (isMeasuredPowerAvailable) {
powerDurationAndTraffic.powerMah = uCtoMah(measuredChargeUC);
}
if (hasWifiActivityReporting && mHasWifiPowerController) {
final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
if (counter != null) {
final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
@@ -203,9 +207,10 @@ public class WifiPowerCalculator extends PowerCalculator {
final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
powerDurationAndTraffic.powerMah = mIdlePowerEstimator.calculatePower(idleTime)
+ mTxPowerEstimator.calculatePower(txTime)
+ mRxPowerEstimator.calculatePower(rxTime);
if (!isMeasuredPowerAvailable) {
powerDurationAndTraffic.powerMah
= calcPowerFromControllerDataMah(rxTime, txTime, idleTime);
}
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
@@ -214,21 +219,20 @@ public class WifiPowerCalculator extends PowerCalculator {
}
}
} else {
final double wifiPacketPower = (
powerDurationAndTraffic.wifiRxPackets + powerDurationAndTraffic.wifiTxPackets)
* mWifiPowerPerPacket;
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
long batchScanTimeMs = 0;
for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
batchScanTimeMs += u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
}
powerDurationAndTraffic.durationMs = wifiRunningTime;
powerDurationAndTraffic.powerMah = wifiPacketPower
+ mPowerOnPowerEstimator.calculatePower(wifiRunningTime)
+ mScanPowerEstimator.calculatePower(wifiScanTimeMs)
+ mBatchScanPowerEstimator.calculatePower(batchScanTimeMs);
if (!isMeasuredPowerAvailable) {
final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
long batchTimeMs = 0;
for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
batchTimeMs += u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
}
powerDurationAndTraffic.powerMah = calcPowerWithoutControllerDataMah(
powerDurationAndTraffic.wifiRxPackets,
powerDurationAndTraffic.wifiTxPackets,
wifiRunningTime, wifiScanTimeMs, batchTimeMs);
}
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
@@ -238,12 +242,20 @@ public class WifiPowerCalculator extends PowerCalculator {
}
private void calculateRemaining(PowerDurationAndTraffic powerDurationAndTraffic,
BatteryStats stats, long rawRealtimeUs,
int statsType, boolean hasWifiPowerReporting, long totalAppDurationMs,
double totalAppPowerMah) {
BatteryStats stats, long rawRealtimeUs, int statsType,
boolean hasWifiActivityReporting, boolean shouldForceUsePowerProfileModel,
long totalAppDurationMs, double totalAppPowerMah) {
long totalDurationMs;
double totalPowerMah;
if (hasWifiPowerReporting) {
double totalPowerMah = 0;
final long measuredChargeUC = stats.getWifiMeasuredBatteryConsumptionUC();
final boolean isMeasuredPowerAvailable
= !shouldForceUsePowerProfileModel && measuredChargeUC != POWER_DATA_UNAVAILABLE;
if (isMeasuredPowerAvailable) {
totalPowerMah = uCtoMah(measuredChargeUC);
}
if (hasWifiActivityReporting && mHasWifiPowerController) {
final BatteryStats.ControllerActivityCounter counter =
stats.getWifiControllerActivity();
@@ -253,17 +265,19 @@ public class WifiPowerCalculator extends PowerCalculator {
totalDurationMs = idleTimeMs + rxTimeMs + txTimeMs;
totalPowerMah =
counter.getPowerCounter().getCountLocked(statsType) / (double) (1000 * 60 * 60);
if (totalPowerMah == 0) {
// Some controllers do not report power drain, so we can calculate it here.
totalPowerMah = mIdlePowerEstimator.calculatePower(idleTimeMs)
+ mTxPowerEstimator.calculatePower(txTimeMs)
+ mRxPowerEstimator.calculatePower(rxTimeMs);
if (!isMeasuredPowerAvailable) {
totalPowerMah = counter.getPowerCounter().getCountLocked(statsType)
/ (double) (1000 * 60 * 60);
if (totalPowerMah == 0) {
// Some controllers do not report power drain, so we can calculate it here.
totalPowerMah = calcPowerFromControllerDataMah(rxTimeMs, txTimeMs, idleTimeMs);
}
}
} else {
totalDurationMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000;
totalPowerMah = mPowerOnPowerEstimator.calculatePower(totalDurationMs);
if (!isMeasuredPowerAvailable) {
totalPowerMah = calcGlobalPowerWithoutControllerDataMah(totalDurationMs);
}
}
powerDurationAndTraffic.durationMs = Math.max(0, totalDurationMs - totalAppDurationMs);
@@ -274,6 +288,29 @@ public class WifiPowerCalculator extends PowerCalculator {
}
}
/** Returns (global or uid) estimated wifi power used using WifiControllerActivity data. */
public double calcPowerFromControllerDataMah(long rxTimeMs, long txTimeMs, long idleTimeMs) {
return mRxPowerEstimator.calculatePower(rxTimeMs)
+ mTxPowerEstimator.calculatePower(txTimeMs)
+ mIdlePowerEstimator.calculatePower(idleTimeMs);
}
/** Returns per-uid estimated wifi power used using non-WifiControllerActivity data. */
public double calcPowerWithoutControllerDataMah(long rxPackets, long txPackets,
long wifiRunningTimeMs, long wifiScanTimeMs, long wifiBatchScanTimeMs) {
return
(rxPackets + txPackets) * mWifiPowerPerPacket
+ mPowerOnPowerEstimator.calculatePower(wifiRunningTimeMs)
+ mScanPowerEstimator.calculatePower(wifiScanTimeMs)
+ mBatchScanPowerEstimator.calculatePower(wifiBatchScanTimeMs);
}
/** Returns global estimated wifi power used using non-WifiControllerActivity data. */
public double calcGlobalPowerWithoutControllerDataMah(long globalWifiRunningTimeMs) {
return mPowerOnPowerEstimator.calculatePower(globalWifiRunningTimeMs);
}
/**
* Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
*/

View File

@@ -52,7 +52,9 @@ public class MeasuredEnergyStats {
public static final int POWER_BUCKET_SCREEN_DOZE = 1;
public static final int POWER_BUCKET_SCREEN_OTHER = 2;
public static final int POWER_BUCKET_CPU = 3;
public static final int NUMBER_STANDARD_POWER_BUCKETS = 4; // Buckets above this are custom.
public static final int POWER_BUCKET_WIFI = 4;
public static final int POWER_BUCKET_BLUETOOTH = 5;
public static final int NUMBER_STANDARD_POWER_BUCKETS = 6; // Buckets above this are custom.
@IntDef(prefix = {"POWER_BUCKET_"}, value = {
POWER_BUCKET_UNKNOWN,
@@ -60,6 +62,8 @@ public class MeasuredEnergyStats {
POWER_BUCKET_SCREEN_DOZE,
POWER_BUCKET_SCREEN_OTHER,
POWER_BUCKET_CPU,
POWER_BUCKET_WIFI,
POWER_BUCKET_BLUETOOTH,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StandardPowerBucket {

View File

@@ -33,11 +33,15 @@ import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import com.android.internal.power.MeasuredEnergyStats;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
public class BatteryUsageStatsRule implements TestRule {
private final PowerProfile mPowerProfile;
private final MockClocks mMockClocks = new MockClocks();
@@ -98,6 +102,16 @@ public class BatteryUsageStatsRule implements TestRule {
return this;
}
/** Call only after setting the power profile information. */
public BatteryUsageStatsRule initMeasuredEnergyStatsLocked(int numCustom) {
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
Arrays.fill(supportedStandardBuckets, true);
mBatteryStats.initMeasuredEnergyStatsLocked(supportedStandardBuckets, numCustom);
mBatteryStats.informThatAllExternalStatsAreFlushed();
return this;
}
public BatteryUsageStatsRule startWithScreenOn(boolean screenOn) {
mScreenOn = screenOn;
return this;

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.annotation.Nullable;
import android.os.BatteryConsumer;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.SystemBatteryConsumer;
@@ -60,7 +61,8 @@ public class BluetoothPowerCalculatorTest {
BluetoothPowerCalculator calculator =
new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
calculator);
assertBluetoothPowerAndDuration(
mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),
@@ -91,7 +93,8 @@ public class BluetoothPowerCalculatorTest {
BluetoothPowerCalculator calculator =
new BluetoothPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
calculator);
assertBluetoothPowerAndDuration(
mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID),

View File

@@ -46,6 +46,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
initTimersAndCounters();
setExternalStatsSyncLocked(new DummyExternalStatsSync());
informThatAllExternalStatsAreFlushed();
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];

View File

@@ -17,11 +17,14 @@
package com.android.internal.os;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
@@ -50,10 +53,11 @@ public class WifiPowerCalculatorTest {
.setAveragePower(PowerProfile.POWER_WIFI_ON, 360.0)
.setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
.setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
.setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0);
.setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0)
.initMeasuredEnergyStatsLocked(0);
@Test
public void testPowerControllerBasedModel() {
/** Sets up a batterystats object with pre-populated network values. */
private BatteryStatsImpl setupTestNetworkNumbers() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.noteNetworkInterfaceForTransports("wifi",
@@ -64,13 +68,25 @@ public class WifiPowerCalculatorTest {
.insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
mStatsRule.setNetworkStats(networkStats);
WifiActivityEnergyInfo energyInfo = new WifiActivityEnergyInfo(10000,
WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
return batteryStats;
}
batteryStats.updateWifiState(energyInfo, 1000, 1000);
/** Sets up an WifiActivityEnergyInfo for ActivityController-model-based tests. */
private WifiActivityEnergyInfo setupPowerControllerBasedModelEnergyNumbersInfo() {
return new WifiActivityEnergyInfo(10000,
WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
}
@Test
public void testPowerControllerBasedModel_nonMeasured() {
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 1000, 1000);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
@@ -87,30 +103,54 @@ public class WifiPowerCalculatorTest {
}
@Test
public void testTimerBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
public void testPowerControllerBasedModel_measured() {
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
batteryStats.noteNetworkInterfaceForTransports("wifi",
new int[]{NetworkCapabilities.TRANSPORT_WIFI});
batteryStats.updateWifiState(energyInfo, 1_000_000, 1000, 1000);
NetworkStats networkStats = new NetworkStats(10000, 1)
.insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
.insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
mStatsRule.setNetworkStats(networkStats);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(1423);
/* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.2214666 / (0.2214666 + 0.645200) * 1_000_000 / 3600000);
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(5577);
/* Same ratio as in testPowerControllerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.645200 / (0.2214666 + 0.645200) * 1_000_000 / 3600000);
}
/** Sets up batterystats object with prepopulated network & timer data for Timer-model tests. */
private BatteryStatsImpl setupTimerBasedModelTestNumbers() {
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
batteryStats.noteWifiScanStartedLocked(APP_UID, 1000, 1000);
batteryStats.noteWifiScanStoppedLocked(APP_UID, 2000, 2000);
batteryStats.noteWifiRunningLocked(new WorkSource(APP_UID), 3000, 3000);
batteryStats.noteWifiStoppedLocked(new WorkSource(APP_UID), 4000, 4000);
batteryStats.noteWifiRunningLocked(new WorkSource(Process.WIFI_UID), 1111, 2222);
batteryStats.noteWifiStoppedLocked(new WorkSource(Process.WIFI_UID), 3333, 4444);
return batteryStats;
}
@Test
public void testTimerBasedModel_nonMeasured() {
final BatteryStatsImpl batteryStats = setupTimerBasedModelTestNumbers();
// Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
// on the packet counts.
batteryStats.updateWifiState(/* energyInfo */ null, 1000, 1000);
batteryStats.updateWifiState(/* energyInfo */ null, POWER_DATA_UNAVAILABLE, 1000, 1000);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
@@ -125,4 +165,31 @@ public class WifiPowerCalculatorTest {
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8759216);
}
@Test
public void testTimerBasedModel_measured() {
final BatteryStatsImpl batteryStats = setupTimerBasedModelTestNumbers();
// Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
// on the packet counts.
batteryStats.updateWifiState(/* energyInfo */ null, 1_000_000, 1000, 1000);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(1000);
/* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8231573 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);
SystemBatteryConsumer systemConsumer =
mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
.isEqualTo(2222);
/* Same ratio as in testTimerBasedModel_nonMeasured but scaled by 1_000_000uC. */
assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
.isWithin(PRECISION).of(0.8759216 / (0.8231573 + 0.8759216) * 1_000_000 / 3600000);
}
}

View File

@@ -589,9 +589,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
Slog.w(TAG, "exception reading modem stats: " + e.getCause());
}
final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDelta;
final MeasuredEnergySnapshot.MeasuredEnergyDeltaData measuredEnergyDeltas;
if (mMeasuredEnergySnapshot == null || futureECRs == null) {
measuredEnergyDelta = null;
measuredEnergyDeltas = null;
} else {
final int voltageMv;
synchronized (mStats) {
@@ -610,7 +610,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
ecrs = null;
}
measuredEnergyDelta = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs, voltageMv);
measuredEnergyDeltas = mMeasuredEnergySnapshot.updateAndGetDelta(ecrs, voltageMv);
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -633,10 +633,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
final long[] cpuClusterChargeUC;
if (measuredEnergyDelta == null) {
if (measuredEnergyDeltas == null) {
cpuClusterChargeUC = null;
} else {
cpuClusterChargeUC = measuredEnergyDelta.cpuClusterChargeUC;
cpuClusterChargeUC = measuredEnergyDeltas.cpuClusterChargeUC;
}
mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff, cpuClusterChargeUC);
}
@@ -650,9 +650,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mStats.updateRpmStatsLocked(elapsedRealtimeUs);
}
// Inform mStats about each applicable measured energy.
if (measuredEnergyDelta != null) {
final long displayChargeUC = measuredEnergyDelta.displayChargeUC;
// Inform mStats about each applicable measured energy (unless addressed elsewhere).
if (measuredEnergyDeltas != null) {
final long displayChargeUC = measuredEnergyDeltas.displayChargeUC;
if (displayChargeUC != MeasuredEnergySnapshot.UNAVAILABLE) {
// If updating, pass in what BatteryExternalStatsWorker thinks screenState is.
mStats.updateDisplayMeasuredEnergyStatsLocked(displayChargeUC, screenState,
@@ -660,19 +660,23 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
}
// Inform mStats about each applicable custom energy bucket.
if (measuredEnergyDelta != null
&& measuredEnergyDelta.otherTotalChargeUC != null) {
if (measuredEnergyDeltas != null
&& measuredEnergyDeltas.otherTotalChargeUC != null) {
// Iterate over the custom (EnergyConsumerType.OTHER) ordinals.
for (int ord = 0; ord < measuredEnergyDelta.otherTotalChargeUC.length; ord++) {
long totalEnergy = measuredEnergyDelta.otherTotalChargeUC[ord];
SparseLongArray uidEnergies = measuredEnergyDelta.otherUidChargesUC[ord];
for (int ord = 0; ord < measuredEnergyDeltas.otherTotalChargeUC.length; ord++) {
long totalEnergy = measuredEnergyDeltas.otherTotalChargeUC[ord];
SparseLongArray uidEnergies = measuredEnergyDeltas.otherUidChargesUC[ord];
mStats.updateCustomMeasuredEnergyStatsLocked(ord, totalEnergy, uidEnergies);
}
}
if (bluetoothInfo != null) {
if (bluetoothInfo.isValid()) {
mStats.updateBluetoothStateLocked(bluetoothInfo, elapsedRealtime, uptime);
final long btChargeUC = measuredEnergyDeltas != null
? measuredEnergyDeltas.bluetoothChargeUC
: MeasuredEnergySnapshot.UNAVAILABLE;
mStats.updateBluetoothStateLocked(bluetoothInfo,
btChargeUC, elapsedRealtime, uptime);
} else {
Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
}
@@ -684,10 +688,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
if (wifiInfo != null) {
if (wifiInfo.isValid()) {
// TODO: wifiEnergyDelta = measuredEnergyDelta.consumerTypeEnergyUJ
// .get(EnergyConsumerType.WIFI, MeasuredEnergySnapshot.UNAVAILABLE)
mStats.updateWifiState(extractDeltaLocked(wifiInfo)
/*, TODO: wifiEnergyDelta */, elapsedRealtime, uptime);
final long wifiChargeUC = measuredEnergyDeltas != null ?
measuredEnergyDeltas.wifiChargeUC : MeasuredEnergySnapshot.UNAVAILABLE;
mStats.updateWifiState(
extractDeltaLocked(wifiInfo), wifiChargeUC, elapsedRealtime, uptime);
} else {
Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
}
@@ -820,13 +824,19 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
for (int idx = 0; idx < size; idx++) {
final EnergyConsumer consumer = idToConsumer.valueAt(idx);
switch (consumer.type) {
case EnergyConsumerType.BLUETOOTH:
buckets[MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH] = true;
break;
case EnergyConsumerType.CPU_CLUSTER:
buckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
break;
case EnergyConsumerType.DISPLAY:
buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true;
buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE] = true;
buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_OTHER] = true;
break;
case EnergyConsumerType.CPU_CLUSTER:
buckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
case EnergyConsumerType.WIFI:
buckets[MeasuredEnergyStats.POWER_BUCKET_WIFI] = true;
break;
}
}
@@ -864,13 +874,18 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
final IntArray energyConsumerIds = new IntArray();
if ((flags & UPDATE_BT) != 0) {
addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.BLUETOOTH);
}
if ((flags & UPDATE_CPU) != 0) {
addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.CPU_CLUSTER);
}
if ((flags & UPDATE_DISPLAY) != 0) {
addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.DISPLAY);
}
// TODO: Wifi, Bluetooth, etc., go here
if ((flags & UPDATE_WIFI) != 0) {
addEnergyConsumerIdLocked(energyConsumerIds, EnergyConsumerType.WIFI);
}
if (energyConsumerIds.size() == 0) {
return null;

View File

@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import android.annotation.NonNull;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -1927,7 +1928,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
mStats.updateWifiState(info, elapsedRealtime, uptime);
mStats.updateWifiState(info, POWER_DATA_UNAVAILABLE, elapsedRealtime, uptime);
});
}
}
@@ -1945,7 +1946,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
synchronized (mStats) {
mStats.updateBluetoothStateLocked(info, elapsedRealtime, uptime);
mStats.updateBluetoothStateLocked(
info, POWER_DATA_UNAVAILABLE, elapsedRealtime, uptime);
}
});
}

View File

@@ -41,7 +41,7 @@ public class MeasuredEnergySnapshot {
private static final int MILLIVOLTS_PER_VOLT = 1000;
public static final long UNAVAILABLE = -1L;
public static final long UNAVAILABLE = android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
/** Map of {@link EnergyConsumer#id} to its corresponding {@link EnergyConsumer}. */
private final SparseArray<EnergyConsumer> mEnergyConsumers;
@@ -109,12 +109,18 @@ public class MeasuredEnergySnapshot {
/** Class for returning the relevant data calculated from the measured energy delta */
static class MeasuredEnergyDeltaData {
/** The chargeUC for {@link EnergyConsumerType#DISPLAY}. */
public long displayChargeUC = UNAVAILABLE;
/** The chargeUC for {@link EnergyConsumerType#BLUETOOTH}. */
public long bluetoothChargeUC = UNAVAILABLE;
/** The chargeUC for {@link EnergyConsumerType#CPU_CLUSTER}s. */
public long[] cpuClusterChargeUC = null;
/** The chargeUC for {@link EnergyConsumerType#DISPLAY}. */
public long displayChargeUC = UNAVAILABLE;
/** The chargeUC for {@link EnergyConsumerType#WIFI}. */
public long wifiChargeUC = UNAVAILABLE;
/** Map of {@link EnergyConsumerType#OTHER} ordinals to their total chargeUC. */
public @Nullable long[] otherTotalChargeUC = null;
@@ -196,8 +202,8 @@ public class MeasuredEnergySnapshot {
final long deltaChargeUC = calculateChargeConsumedUC(deltaUJ, avgVoltageMV);
switch (type) {
case EnergyConsumerType.DISPLAY:
output.displayChargeUC = deltaChargeUC;
case EnergyConsumerType.BLUETOOTH:
output.bluetoothChargeUC = deltaChargeUC;
break;
case EnergyConsumerType.CPU_CLUSTER:
@@ -207,6 +213,14 @@ public class MeasuredEnergySnapshot {
output.cpuClusterChargeUC[ordinal] = deltaChargeUC;
break;
case EnergyConsumerType.DISPLAY:
output.displayChargeUC = deltaChargeUC;
break;
case EnergyConsumerType.WIFI:
output.wifiChargeUC = deltaChargeUC;
break;
case EnergyConsumerType.OTHER:
if (output.otherTotalChargeUC == null) {
output.otherTotalChargeUC = new long[getNumOtherOrdinals()];
@@ -215,6 +229,7 @@ public class MeasuredEnergySnapshot {
output.otherTotalChargeUC[ordinal] = deltaChargeUC;
output.otherUidChargesUC[ordinal] = otherUidCharges;
break;
default:
Slog.w(TAG, "Ignoring consumer " + consumer.name + " of unknown type " + type);

View File

@@ -17,8 +17,10 @@
package com.android.server.am;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_BT;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -39,6 +41,7 @@ import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
import org.junit.Before;
import org.junit.Test;
@@ -61,7 +64,7 @@ public class BatteryExternalStatsWorkerTest {
public void setUp() {
final Context context = InstrumentationRegistry.getContext();
mBatteryStatsImpl = new TestBatteryStatsImpl();
mBatteryStatsImpl = new TestBatteryStatsImpl(context);
mPowerStatsInternal = new TestPowerStatsInternal();
mBatteryExternalStatsWorker = new BatteryExternalStatsWorker(new TestInjector(context),
mBatteryStatsImpl);
@@ -72,13 +75,24 @@ public class BatteryExternalStatsWorkerTest {
final int numCpuClusters = 4;
final int numOther = 3;
final IntArray tempAllIds = new IntArray();
// Add some energy consumers used by BatteryExternalStatsWorker.
final IntArray tempAllIds = new IntArray();
final int displayId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.DISPLAY, 0,
"display");
tempAllIds.add(displayId);
mPowerStatsInternal.incrementEnergyConsumption(displayId, 12345);
final int wifiId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.WIFI, 0,
"wifi");
tempAllIds.add(wifiId);
mPowerStatsInternal.incrementEnergyConsumption(wifiId, 23456);
final int btId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.BLUETOOTH, 0,
"bt");
tempAllIds.add(btId);
mPowerStatsInternal.incrementEnergyConsumption(btId, 34567);
final int[] cpuClusterIds = new int[numCpuClusters];
for (int i = 0; i < numCpuClusters; i++) {
cpuClusterIds[i] = mPowerStatsInternal.addEnergyConsumer(
@@ -109,6 +123,18 @@ public class BatteryExternalStatsWorkerTest {
assertEquals(1, displayResults.length);
assertEquals(displayId, displayResults[0].id);
final EnergyConsumerResult[] wifiResults =
mBatteryExternalStatsWorker.getMeasuredEnergyLocked(UPDATE_WIFI).getNow(null);
// Results should only have the wifi energy consumer
assertEquals(1, wifiResults.length);
assertEquals(wifiId, wifiResults[0].id);
final EnergyConsumerResult[] bluetoothResults =
mBatteryExternalStatsWorker.getMeasuredEnergyLocked(UPDATE_BT).getNow(null);
// Results should only have the bluetooth energy consumer
assertEquals(1, bluetoothResults.length);
assertEquals(btId, bluetoothResults[0].id);
final EnergyConsumerResult[] cpuResults =
mBatteryExternalStatsWorker.getMeasuredEnergyLocked(UPDATE_CPU).getNow(null);
// Results should only have the cpu cluster energy consumers
@@ -148,6 +174,9 @@ public class BatteryExternalStatsWorkerTest {
}
public class TestBatteryStatsImpl extends BatteryStatsImpl {
public TestBatteryStatsImpl(Context context) {
mPowerProfile = new PowerProfile(context, true /* forTest */);
}
}
public class TestPowerStatsInternal extends PowerStatsInternal {