diff options
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 { |