blob: 2e647c4ef78da3b7a53e9809416e3faef7d0066f [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.power.stats;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.ROAMING_NO;
import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.usage.NetworkStatsManager;
import android.hardware.radio.V1_5.AccessNetwork;
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.telephony.ActivityStatsTechSpecificInfo;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.servicestests.R;
import com.google.common.collect.Range;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import java.util.ArrayList;
@RunWith(AndroidJUnit4.class)
@SmallTest
@SuppressWarnings("GuardedBy")
public class MobileRadioPowerCalculatorTest {
private static final double PRECISION = 0.00001;
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;
@Mock
NetworkStatsManager mNetworkStatsManager;
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
@Test
public void testCounterBasedModel() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator)
.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, 2000, 30, 100))
.addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 111));
mStatsRule.setNetworkStats(networkStats);
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
new int[]{100, 200, 300, 400, 500}, 600);
stats.noteModemControllerActivity(mai, POWER_DATA_UNAVAILABLE, 10000, 10000,
mNetworkStatsManager);
mStatsRule.setTime(10_000, 10_000);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 720 mA * 100 ms (level 0 TX drain rate * level 0 TX duration)
// + 1080 mA * 200 ms (level 1 TX drain rate * level 1 TX duration)
// + 1440 mA * 300 ms (level 2 TX drain rate * level 2 TX duration)
// + 1800 mA * 400 ms (level 3 TX drain rate * level 3 TX duration)
// + 2160 mA * 500 ms (level 4 TX drain rate * level 4 TX duration)
// + 1440 mA * 600 ms (RX drain rate * RX duration)
// + 360 mA * 3000 ms (idle drain rate * idle duration)
// + 70 mA * 2000 ms (sleep drain rate * sleep duration)
// _________________
// = 4604000 mA-ms or 1.27888 mA-h
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.27888);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 720 mA * 100 ms (level 0 TX drain rate * level 0 TX duration)
// + 1080 mA * 200 ms (level 1 TX drain rate * level 1 TX duration)
// + 1440 mA * 300 ms (level 2 TX drain rate * level 2 TX duration)
// + 1800 mA * 400 ms (level 3 TX drain rate * level 3 TX duration)
// + 2160 mA * 500 ms (level 4 TX drain rate * level 4 TX duration)
// + 1440 mA * 600 ms (RX drain rate * RX duration)
// _________________
// = 3384000 mA-ms or 0.94 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.94);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 3/4 of total packets were sent by APP_UID so 75% of total
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.705);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 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.235);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
@Test
public void testCounterBasedModel_multipleDefinedRat() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator_multiactive)
.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, 2000, 30, 100))
.addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 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, POWER_DATA_UNAVAILABLE, 10000, 10000,
mNetworkStatsManager);
mStatsRule.setTime(10_000, 10_000);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 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 or 1.09938 mA-h 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 or 1.43826 mA-h total consumption
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.43826);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 720 mA * 100 ms (level 0 TX drain rate * level 0 TX duration)
// + 1080 mA * 200 ms (level 1 TX drain rate * level 1 TX duration)
// + 1440 mA * 300 ms (level 2 TX drain rate * level 2 TX duration)
// + 1800 mA * 400 ms (level 3 TX drain rate * level 3 TX duration)
// + 2160 mA * 500 ms (level 4 TX drain rate * level 4 TX duration)
// + 1440 mA * 600 ms (RX drain rate * RX duration)
// _________________
// = 3384000 mA-ms or 0.94 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.09938);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 3/4 of total packets were sent by APP_UID so 75% of total
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.82453);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 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.27484);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
@Test
public void testCounterBasedModel_legacyPowerProfile() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem)
.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, 2000, 30, 100))
.addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 111));
mStatsRule.setNetworkStats(networkStats);
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
new int[]{100, 200, 300, 400, 500}, 600);
stats.noteModemControllerActivity(mai, POWER_DATA_UNAVAILABLE, 10000, 10000,
mNetworkStatsManager);
mStatsRule.setTime(10_000, 10_000);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 720 mA * 100 ms (level 0 TX drain rate * level 0 TX duration)
// + 1080 mA * 200 ms (level 1 TX drain rate * level 1 TX duration)
// + 1440 mA * 300 ms (level 2 TX drain rate * level 2 TX duration)
// + 1800 mA * 400 ms (level 3 TX drain rate * level 3 TX duration)
// + 2160 mA * 500 ms (level 4 TX drain rate * level 4 TX duration)
// + 1440 mA * 600 ms (RX drain rate * RX duration)
// + 360 mA * 3000 ms (idle drain rate * idle duration)
// + 70 mA * 2000 ms (sleep drain rate * sleep duration)
// _________________
// = 4604000 mA-ms or 1.27888 mA-h
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.27888);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 720 mA * 100 ms (level 0 TX drain rate * level 0 TX duration)
// + 1080 mA * 200 ms (level 1 TX drain rate * level 1 TX duration)
// + 1440 mA * 300 ms (level 2 TX drain rate * level 2 TX duration)
// + 1800 mA * 400 ms (level 3 TX drain rate * level 3 TX duration)
// + 2160 mA * 500 ms (level 4 TX drain rate * level 4 TX duration)
// + 1440 mA * 600 ms (RX drain rate * RX duration)
// _________________
// = 3384000 mA-ms or 0.94 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.94);
assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 3/4 of total packets were sent by APP_UID so 75% of total
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(0.705);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
// 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.235);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
}
@Test
public void testTimerBasedModel_byProcessState() {
mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem)
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
BatteryStatsImpl.Uid uid = stats.getUidStatsLocked(APP_UID);
mStatsRule.setTime(1000, 1000);
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
// 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
mStatsRule.setNetworkStats(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)));
stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 10000, 10000,
mNetworkStatsManager);
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000);
mStatsRule.setNetworkStats(new NetworkStats(12000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));
stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 12000, 12000,
mNetworkStatsManager);
assertThat(uid.getMobileRadioEnergyConsumptionUC()).isAtMost(0);
// 12000-8000 = 4000 ms == 4_000_000 us
assertThat(uid.getMobileRadioActiveTimeInProcessState(BatteryConsumer.PROCESS_STATE_ANY))
.isEqualTo(4_000_000);
assertThat(uid.getMobileRadioActiveTimeInProcessState(
BatteryConsumer.PROCESS_STATE_FOREGROUND))
.isEqualTo(3_000_000);
assertThat(uid.getMobileRadioActiveTimeInProcessState(
BatteryConsumer.PROCESS_STATE_BACKGROUND))
.isEqualTo(1_000_000);
assertThat(uid.getMobileRadioActiveTimeInProcessState(
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE))
.isEqualTo(0);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.setTime(12_000, 12_000);
mStatsRule.apply(new BatteryUsageStatsQuery.Builder()
.powerProfileModeledOnly()
.includePowerModels()
.includeProcessStateData()
.build(), calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
final BatteryConsumer.Key foreground = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_FOREGROUND);
final BatteryConsumer.Key background = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_BACKGROUND);
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.6);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(1.2);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.4);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
}
@Test
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();
// 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);
// Note cell signal strength
SignalStrength signalStrength = mock(SignalStrength.class);
when(signalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
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});
stats.notePhoneOnLocked(9800, 9800);
// 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 mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
PhonePowerCalculator phonePowerCalculator =
new PhonePowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
// 1800ms data duration / 2000 total duration * 2.77778 mAh = 2.5
// 200ms phone on duration / 2000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
.isWithin(PRECISION).of(0.27778);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.38541);
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(1.38541);
assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.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();
stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
0, 0);
// 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);
stats.notePhoneOnLocked(9000, 9000);
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 mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
PhonePowerCalculator phonePowerCalculator =
new PhonePowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
// 9000ms data duration / 10000 total duration * 2.77778 mAh = 2.5
// 1000ms phone on duration / 10000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
.isWithin(PRECISION).of(0.27778);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
.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.5 mA-h measured total consumption * 3957753 / 5177753 = 1.91094 mA-h
BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.91094);
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
// 1.91094 * (467988.75 + 2174196.52174) / 3957753 = 1.27574 App 1 Power Consumption
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.27574);
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.63520);
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();
stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
0, 0);
// 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);
stats.notePhoneOnLocked(9000, 9000);
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 mobileRadioPowerCalculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
PhonePowerCalculator phonePowerCalculator =
new PhonePowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
// 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
// 9000ms data duration / 10000 total duration * 2.77778 mAh = 2.5
// 1000ms phone on duration / 10000 total duration * 2.77778 mAh = 0.27777
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(2.5);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
.isWithin(PRECISION).of(0.27778);
assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
.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.5 * 0.94 / 1.27888 = 1.83754 mAh
assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
.isWithin(PRECISION).of(1.83754);
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(1.83754);
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)
.initMeasuredEnergyStatsLocked();
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
BatteryStatsImpl.Uid uid = stats.getUidStatsLocked(APP_UID);
mStatsRule.setTime(1000, 1000);
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
// 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);
// Note cell signal strength
SignalStrength signalStrength = mock(SignalStrength.class);
when(signalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
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});
// Note application network activity
mStatsRule.setNetworkStats(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)));
stats.noteModemControllerActivity(null, 10_000_000, 10000, 10000, mNetworkStatsManager);
uid.setProcessStateForTest(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000);
mStatsRule.setNetworkStats(new NetworkStats(12000, 1)
.addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));
stats.noteModemControllerActivity(null, 15_000_000, 12000, 12000, mNetworkStatsManager);
mStatsRule.setTime(20000, 20000);
assertThat(uid.getMobileRadioEnergyConsumptionUC())
.isIn(Range.open(20_000_000L, 21_000_000L));
assertThat(uid.getMobileRadioEnergyConsumptionUC(
BatteryConsumer.PROCESS_STATE_FOREGROUND))
.isIn(Range.open(13_000_000L, 14_000_000L));
assertThat(uid.getMobileRadioEnergyConsumptionUC(
BatteryConsumer.PROCESS_STATE_BACKGROUND))
.isIn(Range.open(7_000_000L, 8_000_000L));
assertThat(uid.getMobileRadioEnergyConsumptionUC(
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE))
.isEqualTo(0);
MobileRadioPowerCalculator calculator =
new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(new BatteryUsageStatsQuery.Builder()
.includePowerModels()
.includeProcessStateData()
.build(), calculator);
UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
final BatteryConsumer.Key foreground = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_FOREGROUND);
final BatteryConsumer.Key background = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_BACKGROUND);
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(3.62064);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(2.08130);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
}
}