summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/BatteryStats.java50
-rw-r--r--core/java/android/os/connectivity/WifiActivityEnergyInfo.java4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java278
-rw-r--r--core/java/com/android/internal/os/BluetoothPowerCalculator.java47
-rw-r--r--core/java/com/android/internal/os/WifiPowerCalculator.java129
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java14
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java7
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java99
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java57
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java6
-rw-r--r--services/core/java/com/android/server/am/MeasuredEnergySnapshot.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java33
14 files changed, 587 insertions, 169 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4c26e2f33fb2..fa6472ee4a79 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -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
@@ -1004,6 +1004,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
* type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
@@ -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 = -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 static final long POWER_DATA_UNAVAILABLE = -1;
+ 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
diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
index 016cc2f3cdad..ad74a9f5c906 100644
--- a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
+++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
@@ -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);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 11466f4bc042..33b55ac2f0a0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -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
@@ -6967,6 +6971,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);
}
/**
@@ -12389,6 +12510,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.
*/
public void updateRailStatsLocked() {
@@ -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) {
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 7d42de4486a4..db1403479f8a 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -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);
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 98f613fc1c40..b6bfde709cb8 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -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.
*/
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index e3d5464ca413..845b3e501c08 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -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 {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
index 8aeb761ffc4d..80ab36ec84cf 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java
@@ -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;
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index f6aa08bf0645..99cca0b26b1a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -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),
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index a47c4d832083..26adbe9e7c59 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -46,6 +46,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
initTimersAndCounters();
setExternalStatsSyncLocked(new DummyExternalStatsSync());
+ informThatAllExternalStatsAreFlushed();
final boolean[] supportedStandardBuckets =
new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index e1005457c289..2e23dc8dbba8 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -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,
+ return batteryStats;
+ }
+
+ /** 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, 1000, 1000);
+ 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);
+ }
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index e2086b01ec13..e74c936af02d 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -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;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6b9fc0718879..c3f97adbd9c3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -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);
}
});
}
diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
index 9b2ca136bdfb..4c9ab63a100b 100644
--- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java
@@ -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);
diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java
index 8d54ead75761..73a2febf72aa 100644
--- a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java
@@ -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 {