diff options
| author | 2023-03-14 22:57:26 +0000 | |
|---|---|---|
| committer | 2023-03-16 21:03:22 +0000 | |
| commit | 1481bb02cd9e7465f874d775cd07a684d55a89ef (patch) | |
| tree | 6eb8d6ab09165f2d048280b96b6dfbd4b81cccb3 | |
| parent | 5a6351fabf68ad1012e4b5430f9f25967b065864 (diff) | |
Proportionally attribute Mobile Radio Energy Consumption to Phone usage.
Proportionally split out the energy consumption of phone usage from the
rest of the mobile radio energy consumption.
Fixes: 244603408
Test: atest MobileRadioPowerCalculator
Change-Id: I5db49ea7c88cfd502db36265ae5a6555f728d2f7
Merged-In: I5db49ea7c88cfd502db36265ae5a6555f728d2f7
(cherry picked from commit 4789053d52cdb92c44ccee76c7e4babc2bbbb3dc)
6 files changed, 90 insertions, 22 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 76475f2142c0..4f49f12691d0 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2808,6 +2808,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getMobileRadioMeasuredBatteryConsumptionUC(); /** + * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device + * power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getPhoneEnergyConsumptionUC(); + + /** * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on * device power measurement data. * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 05c684278427..852cfe32cc90 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -167,7 +167,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version. Must be updated when the format of the parcelable changes - public static final int VERSION = 210; + public static final int VERSION = 211; // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks @@ -6514,6 +6514,9 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = true; mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs); + if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) { + scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO); + } } } @@ -6532,6 +6535,7 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = false; mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs); + scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO); } } @@ -8509,6 +8513,12 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") @Override + public long getPhoneEnergyConsumptionUC() { + return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_PHONE); + } + + @GuardedBy("this") + @Override public long getScreenOnMeasuredBatteryConsumptionUC() { return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON); } @@ -13751,18 +13761,36 @@ public class BatteryStatsImpl extends BatteryStats { } synchronized (this) { + final long totalRadioDurationMs = + mMobileRadioActiveTimer.getTimeSinceMarkLocked( + elapsedRealtimeMs * 1000) / 1000; + mMobileRadioActiveTimer.setMark(elapsedRealtimeMs); + final long phoneOnDurationMs = Math.min(totalRadioDurationMs, + mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000); + mPhoneOnTimer.setMark(elapsedRealtimeMs); + if (!mOnBatteryInternal || mIgnoreNextExternalStats) { return; } final SparseDoubleArray uidEstimatedConsumptionMah; + final long dataConsumedChargeUC; if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null && mGlobalMeasuredEnergyStats != null) { + // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the + // numerator for long rounding. + final long phoneConsumedChargeUC = + (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2) + / totalRadioDurationMs; + dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC; mGlobalMeasuredEnergyStats.updateStandardBucket( - MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC); + MeasuredEnergyStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC); + mGlobalMeasuredEnergyStats.updateStandardBucket( + MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC); uidEstimatedConsumptionMah = new SparseDoubleArray(); } else { uidEstimatedConsumptionMah = null; + dataConsumedChargeUC = POWER_DATA_UNAVAILABLE; } if (deltaInfo != null) { @@ -13922,14 +13950,9 @@ public class BatteryStatsImpl extends BatteryStats { // Update the MeasuredEnergyStats information. if (uidEstimatedConsumptionMah != null) { double totalEstimatedConsumptionMah = 0.0; - - // Estimate total active radio power consumption since last mark. - final long totalRadioTimeMs = mMobileRadioActiveTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - mMobileRadioActiveTimer.setMark(elapsedRealtimeMs); totalEstimatedConsumptionMah += mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah( - totalRadioTimeMs); + totalRadioDurationMs); // Estimate idle power consumption at each signal strength level final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length; @@ -13953,7 +13976,7 @@ public class BatteryStatsImpl extends BatteryStats { mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs); distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, - consumedChargeUC, uidEstimatedConsumptionMah, + dataConsumedChargeUC, uidEstimatedConsumptionMah, totalEstimatedConsumptionMah, elapsedRealtimeMs); } @@ -16685,6 +16708,8 @@ public class BatteryStatsImpl extends BatteryStats { public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb"; public static final String KEY_BATTERY_CHARGED_DELAY_MS = "battery_charged_delay_ms"; + public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION = + "phone_on_external_stats_collection"; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000; @@ -16697,6 +16722,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64; private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/ private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */ + private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an @@ -16712,6 +16738,8 @@ public class BatteryStatsImpl extends BatteryStats { public int MAX_HISTORY_FILES; public int MAX_HISTORY_BUFFER; /*Bytes*/ public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS; + public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION = + DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -16788,6 +16816,11 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; + + PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean( + KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION, + DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION); + updateBatteryChargedDelayMsLocked(); } } @@ -16842,6 +16875,8 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(MAX_HISTORY_BUFFER/1024); pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("="); pw.println(BATTERY_CHARGED_DELAY_MS); + pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("="); + pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION); } } diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java index cb893defab14..f1c4ffe07788 100644 --- a/core/java/com/android/internal/os/PhonePowerCalculator.java +++ b/core/java/com/android/internal/os/PhonePowerCalculator.java @@ -40,14 +40,27 @@ public class PhonePowerCalculator extends PowerCalculator { @Override public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC(); + final int powerModel = getPowerModel(energyConsumerUC, query); + final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000; - final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); - if (phoneOnPower != 0) { - builder.getAggregateBatteryConsumerBuilder( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower) - .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs); + final double phoneOnPower; + switch (powerModel) { + case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: + phoneOnPower = uCtoMah(energyConsumerUC); + break; + case BatteryConsumer.POWER_MODEL_POWER_PROFILE: + default: + phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); } + + if (phoneOnPower == 0.0) return; + + builder.getAggregateBatteryConsumerBuilder( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel) + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs); + } } diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java index 7fb8696a217d..5bfdd62592c8 100644 --- a/core/java/com/android/internal/power/MeasuredEnergyStats.java +++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java @@ -59,7 +59,9 @@ public class MeasuredEnergyStats { public static final int POWER_BUCKET_BLUETOOTH = 5; public static final int POWER_BUCKET_GNSS = 6; public static final int POWER_BUCKET_MOBILE_RADIO = 7; - public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom. + public static final int POWER_BUCKET_CAMERA = 8; + public static final int POWER_BUCKET_PHONE = 9; + public static final int NUMBER_STANDARD_POWER_BUCKETS = 10; // Buckets above this are custom. @IntDef(prefix = {"POWER_BUCKET_"}, value = { POWER_BUCKET_UNKNOWN, diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java index 00ac1985f897..0bdf491e6377 100644 --- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java @@ -245,6 +245,8 @@ public class MobileRadioPowerCalculatorTest { stats.noteNetworkInterfaceForTransports("cellular", new int[]{NetworkCapabilities.TRANSPORT_CELLULAR}); + stats.notePhoneOnLocked(9800, 9800); + // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, @@ -257,27 +259,33 @@ public class MobileRadioPowerCalculatorTest { mStatsRule.setTime(12_000, 12_000); - MobileRadioPowerCalculator calculator = + MobileRadioPowerCalculator mobileRadioPowerCalculator = new MobileRadioPowerCalculator(mStatsRule.getPowerProfile()); - - mStatsRule.apply(calculator); + PhonePowerCalculator phonePowerCalculator = + new PhonePowerCalculator(mStatsRule.getPowerProfile()); + mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(1.53934); + .isWithin(PRECISION).of(1.38541); assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(2.77778); + .isWithin(PRECISION).of(2.5); assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE)) + .isWithin(PRECISION).of(0.27778); + assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(1.53934); + .isWithin(PRECISION).of(1.38541); assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 702526a4beab..dc1ef7eee0b6 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -891,6 +891,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { break; case EnergyConsumerType.MOBILE_RADIO: buckets[MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO] = true; + buckets[MeasuredEnergyStats.POWER_BUCKET_PHONE] = true; break; case EnergyConsumerType.DISPLAY: buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true; |