Merge "Attribute per Uid Modem Energy Consumption with Rx/Tx data."

This commit is contained in:
Michael Wachenschwanz
2023-01-13 22:01:56 +00:00
committed by Android (Google) Code Review
5 changed files with 542 additions and 47 deletions

View File

@@ -310,6 +310,24 @@ public class BatteryStatsImpl extends BatteryStats {
/** Container for Rail Energy Data stats. */
private final RailStats mTmpRailStats = new RailStats();
/**
* Estimate UID modem power usage based on their estimated mobile radio active time.
*/
public static final int PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME = 1;
/**
* Estimate UID modem power consumption by proportionally attributing estimated Rx and Tx
* power consumption individually.
* ModemActivityInfo must be available.
*/
public static final int PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX = 2;
@IntDef(flag = true, prefix = "PER_UID_MODEM_MODEL_", value = {
PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME,
PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PerUidModemPowerModel {
}
/**
* Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
* {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
@@ -12038,8 +12056,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
final SparseDoubleArray uidEstimatedConsumptionMah;
if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null
&& mGlobalEnergyConsumerStats != null) {
if (consumedChargeUC > 0 && isMobileRadioEnergyConsumerSupportedLocked()) {
mGlobalEnergyConsumerStats.updateStandardBucket(
EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
uidEstimatedConsumptionMah = new SparseDoubleArray();
@@ -12047,6 +12064,8 @@ public class BatteryStatsImpl extends BatteryStats {
uidEstimatedConsumptionMah = null;
}
RxTxConsumption rxTxConsumption = null;
boolean attributeWithModemActivityInfo = false;
if (deltaInfo != null) {
mHasModemReporting = true;
mModemActivity.getOrCreateIdleTimeCounter()
@@ -12092,7 +12111,11 @@ public class BatteryStatsImpl extends BatteryStats {
mTmpRailStats.resetCellularTotalEnergyUsed();
}
incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs);
rxTxConsumption = incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs);
attributeWithModemActivityInfo = mConstants.PER_UID_MODEM_MODEL
== PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX
&& rxTxConsumption != null;
}
long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
@@ -12156,12 +12179,23 @@ public class BatteryStatsImpl extends BatteryStats {
(totalAppRadioTimeUs * appPackets) / totalPackets;
u.noteMobileRadioActiveTimeLocked(appRadioTimeUs, elapsedRealtimeMs);
// Distribute mobile radio charge consumption based on app radio
// active time
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.incrementValue(u.getUid(),
final double uidConsumptionMah;
if (attributeWithModemActivityInfo) {
// Distribute measured mobile radio charge consumption based on
// rx/tx packets and estimated rx/tx charge consumption.
uidConsumptionMah = smearModemActivityInfoRxTxConsumptionMah(
rxTxConsumption, entry.getRxPackets(), entry.getTxPackets(),
totalRxPackets, totalTxPackets);
} else {
// Distribute mobile radio charge consumption based on app radio
// active time
uidConsumptionMah =
mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
appRadioTimeUs / 1000));
appRadioTimeUs / 1000);
}
uidEstimatedConsumptionMah.incrementValue(u.getUid(),
uidConsumptionMah);
}
// Remove this app from the totals, so that we don't lose any time
@@ -12199,54 +12233,95 @@ public class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveUnknownCount.addCountLocked(1);
}
// Update the EnergyConsumerStats 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);
// Estimate idle power consumption at each signal strength level
final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
for (int strengthLevel = 0; strengthLevel < numSignalStrengthLevels;
strengthLevel++) {
final long strengthLevelDurationMs =
mPhoneSignalStrengthsTimer[strengthLevel].getTimeSinceMarkLocked(
if (attributeWithModemActivityInfo) {
// Estimate inactive modem power consumption and combine with previously
// estimated active power consumption for an estimate of total modem
// power consumption.
final long sleepTimeMs = deltaInfo.getSleepTimeMillis();
final long idleTimeMs = deltaInfo.getIdleTimeMillis();
final double inactiveConsumptionMah =
mMobileRadioPowerCalculator.calcInactiveStatePowerMah(sleepTimeMs,
idleTimeMs);
totalEstimatedConsumptionMah += inactiveConsumptionMah;
totalEstimatedConsumptionMah += rxTxConsumption.rxConsumptionMah;
totalEstimatedConsumptionMah += rxTxConsumption.txConsumptionMah;
} else {
// Estimate total active radio power consumption since last mark.
final long totalRadioTimeMs =
mMobileRadioActiveTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
mPhoneSignalStrengthsTimer[strengthLevel].setMark(elapsedRealtimeMs);
mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcIdlePowerAtSignalStrengthMah(
strengthLevelDurationMs, strengthLevel);
mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
totalRadioTimeMs);
// Estimate idle power consumption at each signal strength level
final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
for (int lvl = 0; lvl < numSignalStrengthLevels; lvl++) {
final long strengthLevelDurationMs =
mPhoneSignalStrengthsTimer[lvl].getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
mPhoneSignalStrengthsTimer[lvl].setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcIdlePowerAtSignalStrengthMah(
strengthLevelDurationMs, lvl);
}
// Estimate total active radio power consumption since last mark.
final long scanTimeMs = mPhoneSignalScanningTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
mPhoneSignalScanningTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
}
// Estimate total active radio power consumption since last mark.
final long scanTimeMs = mPhoneSignalScanningTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000) / 1000;
mPhoneSignalScanningTimer.setMark(elapsedRealtimeMs);
totalEstimatedConsumptionMah +=
mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
distributeEnergyToUidsLocked(EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO,
consumedChargeUC, uidEstimatedConsumptionMah,
totalEstimatedConsumptionMah, elapsedRealtimeMs);
}
}
}
}
delta = null;
private static class RxTxConsumption {
public final double rxConsumptionMah;
public final long rxDurationMs;
public final double txConsumptionMah;
public final long txDurationMs;
/**
* Represents the ratio between time spent transmitting and the total active time.
*/
public final double txToTotalRatio;
RxTxConsumption(double rxMah, long rxMs, double txMah, long txMs) {
rxConsumptionMah = rxMah;
rxDurationMs = rxMs;
txConsumptionMah = txMah;
txDurationMs = txMs;
final long activeDurationMs = txDurationMs + rxDurationMs;
if (activeDurationMs == 0) {
txToTotalRatio = 0.0;
} else {
txToTotalRatio = ((double) txDurationMs) / activeDurationMs;
}
}
}
@GuardedBy("this")
private void incrementPerRatDataLocked(ModemActivityInfo deltaInfo, long elapsedRealtimeMs) {
final int infoSize = deltaInfo.getSpecificInfoLength();
@Nullable
private RxTxConsumption incrementPerRatDataLocked(ModemActivityInfo deltaInfo,
long elapsedRealtimeMs) {
double rxConsumptionMah = 0.0;
long rxDurationMs = 0;
double txConsumptionMah = 0.0;
long txDurationMs = 0;
final int infoSize = deltaInfo.getSpecificInfoLength();
if (infoSize == 1 && deltaInfo.getSpecificInfoRat(0)
== AccessNetworkConstants.AccessNetworkType.UNKNOWN
&& deltaInfo.getSpecificInfoFrequencyRange(0)
@@ -12296,6 +12371,16 @@ public class BatteryStatsImpl extends BatteryStats {
+ (totalLvlDurationMs / 2)) / totalLvlDurationMs;
ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs);
frequencyDurationMs += durationMs;
if (isMobileRadioEnergyConsumerSupportedLocked()) {
// Accumulate the power cost of time spent transmitting in a
// particular state.
final double txStatePowerConsumptionMah =
mMobileRadioPowerCalculator.calcTxStatePowerMah(rat, freq,
level, proportionalTxDurationMs);
txConsumptionMah += txStatePowerConsumptionMah;
txDurationMs += proportionalTxDurationMs;
}
}
final long totalRxDuration = deltaInfo.getReceiveTimeMillis();
// Smear HAL provided Rx power duration based on active modem
@@ -12305,6 +12390,16 @@ public class BatteryStatsImpl extends BatteryStats {
(frequencyDurationMs * totalRxDuration + (totalActiveTimeMs
/ 2)) / totalActiveTimeMs;
ratStats.incrementRxDuration(freq, proportionalRxDurationMs);
if (isMobileRadioEnergyConsumerSupportedLocked()) {
// Accumulate the power cost of time spent receiving in a particular
// state.
final double rxStatePowerConsumptionMah =
mMobileRadioPowerCalculator.calcRxStatePowerMah(rat, freq,
proportionalRxDurationMs);
rxConsumptionMah += rxStatePowerConsumptionMah;
rxDurationMs += proportionalRxDurationMs;
}
}
}
@@ -12324,9 +12419,28 @@ public class BatteryStatsImpl extends BatteryStats {
final int[] txTimesMs = deltaInfo.getTransmitTimeMillis(rat, freq);
ratStats.incrementRxDuration(freq, rxTimeMs);
if (isMobileRadioEnergyConsumerSupportedLocked()) {
// Accumulate the power cost of time spent receiving in a particular state.
final double rxStatePowerConsumptionMah =
mMobileRadioPowerCalculator.calcRxStatePowerMah(ratBucket, freq,
rxTimeMs);
rxConsumptionMah += rxStatePowerConsumptionMah;
rxDurationMs += rxTimeMs;
}
final int numTxLvl = txTimesMs.length;
for (int lvl = 0; lvl < numTxLvl; lvl++) {
ratStats.incrementTxDuration(freq, lvl, txTimesMs[lvl]);
final long txTimeMs = txTimesMs[lvl];
ratStats.incrementTxDuration(freq, lvl, txTimeMs);
if (isMobileRadioEnergyConsumerSupportedLocked()) {
// Accumulate the power cost of time spent transmitting in a particular
// state.
final double txStatePowerConsumptionMah =
mMobileRadioPowerCalculator.calcTxStatePowerMah(ratBucket, freq,
lvl, txTimeMs);
txConsumptionMah += txStatePowerConsumptionMah;
txDurationMs += txTimeMs;
}
}
}
}
@@ -12336,6 +12450,45 @@ public class BatteryStatsImpl extends BatteryStats {
if (ratStats == null) continue;
ratStats.setMark(elapsedRealtimeMs);
}
if (isMobileRadioEnergyConsumerSupportedLocked()) {
return new RxTxConsumption(rxConsumptionMah, rxDurationMs, txConsumptionMah,
txDurationMs);
} else {
return null;
}
}
/**
* Smear modem Rx/Tx power consumption calculated from {@link ModemActivityInfo} using Rx/Tx
* packets.
*
* @return the combine Rx/Tx smeared power consumption in milliamp-hours.
*/
private double smearModemActivityInfoRxTxConsumptionMah(RxTxConsumption rxTxConsumption,
long rxPackets, long txPackets, long totalRxPackets, long totalTxPackets) {
// Distribute measured mobile radio charge consumption based on
// rx/tx packets and estimated rx/tx charge consumption.
double consumptionMah = 0.0;
if (totalRxPackets != 0) {
// Proportionally distribute receive battery consumption.
consumptionMah += rxTxConsumption.rxConsumptionMah * rxPackets
/ totalRxPackets;
}
if (totalTxPackets != 0 || (totalRxPackets != 0 && rxTxConsumption.txToTotalRatio != 0.0)) {
// ModemActivityInfo Tx time represents time spent both transmitting and receiving.
// There is currently no way to distinguish how many Rx packets were received during
// Rx time vs Tx time.
// Assumption: The number of packets received while transmitting is proportional
// to the time spent transmitting over total active time.
final double totalPacketsDuringTxTime =
totalTxPackets + rxTxConsumption.txToTotalRatio * totalRxPackets;
final double packetsDuringTxTime =
txPackets + rxTxConsumption.txToTotalRatio * rxPackets;
consumptionMah += rxTxConsumption.txConsumptionMah * packetsDuringTxTime
/ totalPacketsDuringTxTime;
}
return consumptionMah;
}
/**
@@ -14844,6 +14997,13 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
@GuardedBy("this")
private boolean isMobileRadioEnergyConsumerSupportedLocked() {
if (mGlobalEnergyConsumerStats == null) return false;
return mGlobalEnergyConsumerStats.isStandardBucketSupported(
EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO);
}
@NonNull
private static String[] getBatteryConsumerProcessStateNames() {
String[] procStateNames = new String[BatteryConsumer.PROCESS_STATE_COUNT];
@@ -14879,6 +15039,40 @@ public class BatteryStatsImpl extends BatteryStats {
"battery_charged_delay_ms";
public static final String KEY_RECORD_USAGE_HISTORY =
"record_usage_history";
public static final String KEY_PER_UID_MODEM_POWER_MODEL =
"per_uid_modem_power_model";
public static final String PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME =
"mobile_radio_active_time";
public static final String PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME =
"modem_activity_info_rx_tx";
/** Convert {@link PerUidModemPowerModel} to string */
public String getPerUidModemModelName(@PerUidModemPowerModel int model) {
switch(model) {
case PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME:
return PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME;
case PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX:
return PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME;
default:
Slog.w(TAG, "Unexpected per uid modem model (" + model + ")");
return "unknown_" + model;
}
}
/** Convert string to {@link PerUidModemPowerModel} */
@PerUidModemPowerModel
public int getPerUidModemModel(String name) {
switch(name) {
case PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME:
return PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME;
case PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME:
return PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
default:
Slog.w(TAG, "Unexpected per uid modem model name (" + name + ")");
return DEFAULT_PER_UID_MODEM_MODEL;
}
}
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -14892,6 +15086,9 @@ public class BatteryStatsImpl extends BatteryStats {
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_RECORD_USAGE_HISTORY = false;
@PerUidModemPowerModel
private static final int DEFAULT_PER_UID_MODEM_MODEL =
PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
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
@@ -14908,6 +15105,7 @@ public class BatteryStatsImpl extends BatteryStats {
public int MAX_HISTORY_BUFFER; /*Bytes*/
public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
public boolean RECORD_USAGE_HISTORY = DEFAULT_RECORD_USAGE_HISTORY;
public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -14985,6 +15183,9 @@ public class BatteryStatsImpl extends BatteryStats {
* 1024;
RECORD_USAGE_HISTORY = mParser.getBoolean(
KEY_RECORD_USAGE_HISTORY, DEFAULT_RECORD_USAGE_HISTORY);
final String perUidModemModel = mParser.getString(KEY_PER_UID_MODEM_POWER_MODEL,
"");
PER_UID_MODEM_MODEL = getPerUidModemModel(perUidModemModel);
updateBatteryChargedDelayMsLocked();
@@ -15053,6 +15254,8 @@ public class BatteryStatsImpl extends BatteryStats {
pw.println(BATTERY_CHARGED_DELAY_MS);
pw.print(KEY_RECORD_USAGE_HISTORY); pw.print("=");
pw.println(RECORD_USAGE_HISTORY);
pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
}
}

View File

@@ -270,25 +270,28 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
// Calculate the inactive modem power consumption.
final BatteryStats.ControllerActivityCounter modemActivity =
batteryStats.getModemControllerActivity();
if (modemActivity != null && (mSleepPowerEstimator != null
|| mIdlePowerEstimator != null)) {
double inactivePowerMah = Double.NaN;
if (modemActivity != null) {
final long sleepDurationMs = modemActivity.getSleepTimeCounter().getCountLocked(
BatteryStats.STATS_SINCE_CHARGED);
total.remainingPowerMah += mSleepPowerEstimator.calculatePower(sleepDurationMs);
final long idleDurationMs = modemActivity.getIdleTimeCounter().getCountLocked(
BatteryStats.STATS_SINCE_CHARGED);
total.remainingPowerMah += mIdlePowerEstimator.calculatePower(idleDurationMs);
} else {
inactivePowerMah = calcInactiveStatePowerMah(sleepDurationMs, idleDurationMs);
}
if (Double.isNaN(inactivePowerMah)) {
// Modem activity counters unavailable. Use legacy calculations for inactive usage.
final long scanningTimeMs = batteryStats.getPhoneSignalScanningTime(rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED) / 1000;
total.remainingPowerMah += calcScanTimePowerMah(scanningTimeMs);
inactivePowerMah = calcScanTimePowerMah(scanningTimeMs);
for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
long strengthTimeMs = batteryStats.getPhoneSignalStrengthTime(i, rawRealtimeUs,
BatteryStats.STATS_SINCE_CHARGED) / 1000;
total.remainingPowerMah += calcIdlePowerAtSignalStrengthMah(strengthTimeMs, i);
inactivePowerMah += calcIdlePowerAtSignalStrengthMah(strengthTimeMs, i);
}
}
if (!Double.isNaN(inactivePowerMah)) {
total.remainingPowerMah += inactivePowerMah;
}
}
@@ -508,6 +511,22 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
return consumptionMah;
}
/**
* Calculates active transmit radio power consumption (in milliamp-hours) from the given state's
* duration.
*/
public double calcInactiveStatePowerMah(long sleepDurationMs, long idleDurationMs) {
if (mSleepPowerEstimator == null || mIdlePowerEstimator == null) return Double.NaN;
final double sleepConsumptionMah = mSleepPowerEstimator.calculatePower(sleepDurationMs);
final double idleConsumptionMah = mIdlePowerEstimator.calculatePower(idleDurationMs);
if (DEBUG) {
Log.d(TAG, "Calculated sleep consumption " + sleepConsumptionMah
+ " mAH from a duration of " + sleepDurationMs + " ms and idle consumption "
+ idleConsumptionMah + " mAH from a duration of " + idleDurationMs);
}
return sleepConsumptionMah + idleConsumptionMah;
}
/**
* Calculates active radio power consumption (in milliamp-hours) from active radio duration.
*/

View File

@@ -137,6 +137,13 @@ public class BatteryUsageStatsRule implements TestRule {
return this;
}
public BatteryUsageStatsRule setPerUidModemModel(int perUidModemModel) {
synchronized (mBatteryStats) {
mBatteryStats.setPerUidModemModel(perUidModemModel);
}
return this;
}
/** Call only after setting the power profile information. */
public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() {
return initMeasuredEnergyStatsLocked(new String[0]);

View File

@@ -574,8 +574,10 @@ public class MobileRadioPowerCalculatorTest {
}
@Test
public void testMeasuredEnergyBasedModel() {
public void testMeasuredEnergyBasedModel_mobileRadioActiveTimeModel() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem)
.setPerUidModemModel(
BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME)
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
@@ -637,6 +639,263 @@ public class MobileRadioPowerCalculatorTest {
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
@Test
public void testMeasuredEnergyBasedModel_modemActivityInfoRxTxModel() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator_multiactive)
.setPerUidModemModel(
BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX)
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
// Scan for a cell
stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
TelephonyManager.SIM_STATE_READY,
2000, 2000);
// Found a cell
stats.notePhoneStateLocked(ServiceState.STATE_IN_SERVICE, TelephonyManager.SIM_STATE_READY,
5000, 5000);
ArrayList<CellSignalStrength> perRatCellStrength = new ArrayList();
CellSignalStrength gsmSignalStrength = mock(CellSignalStrength.class);
when(gsmSignalStrength.getLevel()).thenReturn(
SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
perRatCellStrength.add(gsmSignalStrength);
// Note cell signal strength
SignalStrength signalStrength = mock(SignalStrength.class);
when(signalStrength.getCellSignalStrengths()).thenReturn(perRatCellStrength);
stats.notePhoneSignalStrengthLocked(signalStrength, 5000, 5000);
stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
8_000_000_000L, APP_UID, 8000, 8000);
// Note established network
stats.noteNetworkInterfaceForTransports("cellular",
new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
// Spend some time in each signal strength level. It doesn't matter how long.
// The ModemActivityInfo reported level residency should be trusted over the BatteryStats
// timers.
when(gsmSignalStrength.getLevel()).thenReturn(
SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
stats.notePhoneSignalStrengthLocked(signalStrength, 8111, 8111);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_POOR);
stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
9_500_000_000L, APP_UID2, 9500, 9500);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GREAT);
stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);
// Note application network activity
NetworkStats networkStats = new NetworkStats(10000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 300, 10, 100))
.addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 2000, 30, 111));
mStatsRule.setNetworkStats(networkStats);
ActivityStatsTechSpecificInfo cdmaInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.CDMA2000, ServiceState.FREQUENCY_RANGE_UNKNOWN,
new int[]{10, 11, 12, 13, 14}, 15);
ActivityStatsTechSpecificInfo lteInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.EUTRAN, ServiceState.FREQUENCY_RANGE_UNKNOWN,
new int[]{20, 21, 22, 23, 24}, 25);
ActivityStatsTechSpecificInfo nrLowFreqInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.NGRAN, ServiceState.FREQUENCY_RANGE_LOW,
new int[]{30, 31, 32, 33, 34}, 35);
ActivityStatsTechSpecificInfo nrMidFreqInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.NGRAN, ServiceState.FREQUENCY_RANGE_MID,
new int[]{40, 41, 42, 43, 44}, 45);
ActivityStatsTechSpecificInfo nrHighFreqInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.NGRAN, ServiceState.FREQUENCY_RANGE_HIGH,
new int[]{50, 51, 52, 53, 54}, 55);
ActivityStatsTechSpecificInfo nrMmwaveFreqInfo = new ActivityStatsTechSpecificInfo(
AccessNetwork.NGRAN, ServiceState.FREQUENCY_RANGE_MMWAVE,
new int[]{60, 61, 62, 63, 64}, 65);
ActivityStatsTechSpecificInfo[] ratInfos =
new ActivityStatsTechSpecificInfo[]{cdmaInfo, lteInfo, nrLowFreqInfo, nrMidFreqInfo,
nrHighFreqInfo, nrMmwaveFreqInfo};
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, ratInfos);
stats.noteModemControllerActivity(mai, 10_000_000, 10000, 10000,
mNetworkStatsManager);
mStatsRule.setTime(10_000, 10_000);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.77778);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
// CDMA2000 [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// [720, 1080, 1440, 1800, 2160, 1440] mA . [10, 11, 12, 13, 14, 15] ms = 111600 mA-ms
// LTE [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// [800, 1200, 1600, 2000, 2400, 2000] mA . [20, 21, 22, 23, 24, 25] ms = 230000 mA-ms
// 5G Low Frequency [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// (nrFrequency="LOW" values was not defined so fall back to nrFrequency="DEFAULT")
// [999, 1333, 1888, 2222, 2666, 2222] mA . [30, 31, 32, 33, 34, 35] ms = 373449 mA-ms
// 5G Mid Frequency [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// (nrFrequency="MID" values was not defined so fall back to nrFrequency="DEFAULT")
// [999, 1333, 1888, 2222, 2666, 2222] mA . [40, 41, 42, 43, 44, 45] ms = 486749 mA-ms
// 5G High Frequency [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// [1818, 2727, 3636, 4545, 5454, 2727] mA . [50, 51, 52, 53, 54, 55] ms = 1104435 mA-ms
// 5G Mmwave Frequency [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
// [2345, 3456, 4567, 5678, 6789, 3456] mA . [60, 61, 62, 63, 64, 65] ms = 1651520 mA-ms
// _________________
// = 3957753 mA-ms estimated active consumption
//
// Idle drain rate * idle duration
// 360 mA * 3000 ms = 1080000 mA-ms
// Sleep drain rate * sleep duration
// 70 mA * 2000 ms = 140000 mA-ms
// _________________
// = 5177753 mA-ms estimated total consumption
//
// 2.77778 mA-h measured total consumption * 3957753 / 5177753 = 2.123268 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.123268);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
// 240 ms Rx Time, 1110 ms Tx Time, 1350 ms active time
// 150 App 1 Rx Packets, 10 App 1 Tx packets
// 50 App 2 Rx Packets, 30 App 2 Tx packets
// 200 total Rx Packets, 40 total Tx packets
// 623985 mA-ms Rx consumption, 3333768 mA-ms Tx consumption
//
// Rx Power consumption * Ratio of App1 / Total Rx Packets:
// 623985 * 150 / 200 = 467988.75 mA-ms App 1 Rx Power Consumption
//
// App 1 Tx Packets + App 1 Rx Packets * Ratio of Tx / Total active time
// 10 + 150 * 1110 / 1350 = 133.3333 Estimated App 1 Rx/Tx Packets during Tx
// Total Tx Packets + Total Rx Packets * Ratio of Tx / Total active time
// 40 + 200 * 1110 / 1350 = 204.44444 Estimated Total Rx/Tx Packets during Tx
// Tx Power consumption * Ratio of App 1 / Total Estimated Tx Packets:
// 3333768 * 133.33333 / 204.44444 = 2174196.52174 mA-ms App 1 Tx Power Consumption
//
// Total App Power consumption * Ratio of App 1 / Total Estimated Power Consumption
// 2.123268 * (467988.75 + 2174196.52174) / 3957753 = 1.41749 App 1 Power Consumption
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.41749);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
// Rest should go to the other app
UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.705778);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
@Test
public void testMeasuredEnergyBasedModel_modemActivityInfoRxTxModel_legacyPowerProfile() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem)
.setPerUidModemModel(
BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX)
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
// Scan for a cell
stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
TelephonyManager.SIM_STATE_READY,
2000, 2000);
ArrayList<CellSignalStrength> perRatCellStrength = new ArrayList();
CellSignalStrength gsmSignalStrength = mock(CellSignalStrength.class);
when(gsmSignalStrength.getLevel()).thenReturn(
SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
perRatCellStrength.add(gsmSignalStrength);
// Found a cell
stats.notePhoneStateLocked(ServiceState.STATE_IN_SERVICE, TelephonyManager.SIM_STATE_READY,
5000, 5000);
// Note cell signal strength
SignalStrength signalStrength = mock(SignalStrength.class);
when(signalStrength.getCellSignalStrengths()).thenReturn(perRatCellStrength);
stats.notePhoneSignalStrengthLocked(signalStrength, 5000, 5000);
stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
8_000_000_000L, APP_UID, 8000, 8000);
// Note established network
stats.noteNetworkInterfaceForTransports("cellular",
new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
// Spend some time in each signal strength level. It doesn't matter how long.
// The ModemActivityInfo reported level residency should be trusted over the BatteryStats
// timers.
when(gsmSignalStrength.getLevel()).thenReturn(
SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
stats.notePhoneSignalStrengthLocked(signalStrength, 8111, 8111);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_POOR);
stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GREAT);
stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);
// Note application network activity
NetworkStats networkStats = new NetworkStats(10000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100));
mStatsRule.setNetworkStats(networkStats);
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
new int[]{100, 200, 300, 400, 500}, 600);
stats.noteModemControllerActivity(mai, 10_000_000, 10000, 10000, mNetworkStatsManager);
mStatsRule.setTime(12_000, 12_000);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
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);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
// Estimated Rx/Tx modem consumption = 0.94 mAh
// Estimated total modem consumption = 1.27888 mAh
// 2.77778 * 0.94 / 1.27888 = 2.04170 mAh
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.04170);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.04170);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
}
@Test
public void testMeasuredEnergyBasedModel_byProcessState() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem)

View File

@@ -213,6 +213,13 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return this;
}
@GuardedBy("this")
public MockBatteryStatsImpl setPerUidModemModel(int perUidModemModel) {
mConstants.PER_UID_MODEM_MODEL = perUidModemModel;
mConstants.onChange();
return this;
}
public int getAndClearExternalStatsSyncFlags() {
final int flags = mExternalStatsSync.flags;
mExternalStatsSync.flags = 0;