Merge "Collect fine grain time-in-state Modem durations"

This commit is contained in:
Michael Wachenschwanz
2022-01-28 18:11:53 +00:00
committed by Android (Google) Code Review
6 changed files with 602 additions and 10 deletions

View File

@@ -34,6 +34,7 @@ import android.server.ServerProtoEnums;
import android.service.batterystats.BatteryStatsServiceDumpHistoryProto;
import android.service.batterystats.BatteryStatsServiceDumpProto;
import android.telephony.CellSignalStrength;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
import android.util.ArrayMap;
@@ -2654,6 +2655,46 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract Timer getPhoneDataConnectionTimer(int dataType);
/** @hide */
public static final int RADIO_ACCESS_TECHNOLOGY_OTHER = 0;
/** @hide */
public static final int RADIO_ACCESS_TECHNOLOGY_LTE = 1;
/** @hide */
public static final int RADIO_ACCESS_TECHNOLOGY_NR = 2;
/** @hide */
public static final int RADIO_ACCESS_TECHNOLOGY_COUNT = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "RADIO_ACCESS_TECHNOLOGY_",
value = {RADIO_ACCESS_TECHNOLOGY_OTHER, RADIO_ACCESS_TECHNOLOGY_LTE,
RADIO_ACCESS_TECHNOLOGY_NR})
public @interface RadioAccessTechnology {
}
/** @hide */
public static final String[] RADIO_ACCESS_TECHNOLOGY_NAMES = {"Other", "LTE", "NR"};
/**
* Returns the time in microseconds that the mobile radio has been active on a
* given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
* transmission power level.
*
* @param rat Radio Access Technology {@see RadioAccessTechnology}
* @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
* RADIO_ACCESS_TECHNOLOGY_NR. Use
* {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
* Technologies.
* @param signalStrength the cellular signal strength. {@see CellSignalStrength#getLevel()}
* @param elapsedRealtimeMs current elapsed realtime
* @return time (in milliseconds) the mobile radio spent active in the specified state,
* while on battery.
* @hide
*/
public abstract long getActiveRadioDurationMs(@RadioAccessTechnology int rat,
@ServiceState.FrequencyRange int frequencyRange, int signalStrength,
long elapsedRealtimeMs);
static final String[] WIFI_SUPPL_STATE_NAMES = {
"invalid", "disconn", "disabled", "inactive", "scanning",
"authenticating", "associating", "associated", "4-way-handshake",
@@ -3997,6 +4038,89 @@ public abstract class BatteryStats implements Parcelable {
}
}
private void printCellularPerRatBreakdown(PrintWriter pw, StringBuilder sb, String prefix,
long rawRealtimeMs) {
final String allFrequenciesHeader =
" All frequencies:\n";
final String[] nrFrequencyRangeDescription = new String[]{
" Unknown frequency:\n",
" Low frequency (less than 1GHz):\n",
" Middle frequency (1GHz to 3GHz):\n",
" High frequency (3GHz to 6GHz):\n",
" Mmwave frequency (greater than 6GHz):\n"};
final String signalStrengthHeader =
" Signal Strength Time:\n";
final String[] signalStrengthDescription = new String[]{
" unknown: ",
" poor: ",
" moderate: ",
" good: ",
" great: "};
final long totalActiveTimesMs = getMobileRadioActiveTime(rawRealtimeMs * 1000,
STATS_SINCE_CHARGED) / 1000;
sb.setLength(0);
sb.append(prefix);
sb.append("Active Cellular Radio Access Technology Breakdown:");
pw.println(sb);
boolean hasData = false;
final int numSignalStrength = CellSignalStrength.getNumSignalStrengthLevels();
for (int rat = RADIO_ACCESS_TECHNOLOGY_COUNT - 1; rat >= 0; rat--) {
sb.setLength(0);
sb.append(prefix);
sb.append(" ");
sb.append(RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
sb.append(":\n");
sb.append(prefix);
final int numFreqLvl =
rat == RADIO_ACCESS_TECHNOLOGY_NR ? nrFrequencyRangeDescription.length : 1;
for (int freqLvl = numFreqLvl - 1; freqLvl >= 0; freqLvl--) {
final int freqDescriptionStart = sb.length();
boolean hasFreqData = false;
if (rat == RADIO_ACCESS_TECHNOLOGY_NR) {
sb.append(nrFrequencyRangeDescription[freqLvl]);
} else {
sb.append(allFrequenciesHeader);
}
sb.append(prefix);
sb.append(signalStrengthHeader);
for (int strength = 0; strength < numSignalStrength; strength++) {
final long timeMs = getActiveRadioDurationMs(rat, freqLvl, strength,
rawRealtimeMs);
if (timeMs <= 0) continue;
hasFreqData = true;
sb.append(prefix);
sb.append(signalStrengthDescription[strength]);
formatTimeMs(sb, timeMs);
sb.append("(");
sb.append(formatRatioLocked(timeMs, totalActiveTimesMs));
sb.append(")\n");
}
if (hasFreqData) {
hasData = true;
pw.print(sb);
sb.setLength(0);
sb.append(prefix);
} else {
// No useful data was printed, rewind sb to before the start of this frequency.
sb.setLength(freqDescriptionStart);
}
}
}
if (!hasData) {
sb.setLength(0);
sb.append(prefix);
sb.append(" (no activity)");
pw.println(sb);
}
}
/**
* Temporary for settings.
*/
@@ -5269,6 +5393,8 @@ public abstract class BatteryStats implements Parcelable {
printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
getModemControllerActivity(), which);
printCellularPerRatBreakdown(pw, sb, prefix + " ", rawRealtimeMs);
pw.print(" Cellular data received: "); pw.println(formatBytesLocked(mobileRxTotalBytes));
pw.print(" Cellular data sent: "); pw.println(formatBytesLocked(mobileTxTotalBytes));
pw.print(" Cellular packets received: "); pw.println(mobileRxTotalPackets);

View File

@@ -113,7 +113,7 @@ interface IBatteryStats {
void notePhoneOn();
void notePhoneOff();
void notePhoneSignalStrength(in SignalStrength signalStrength);
void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType);
void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType, int nrFrequency);
void notePhoneState(int phoneState);
void noteWifiOn();
void noteWifiOff();

View File

@@ -69,10 +69,14 @@ import android.os.connectivity.GpsBatteryStats;
import android.os.connectivity.WifiActivityEnergyInfo;
import android.os.connectivity.WifiBatteryStats;
import android.provider.Settings;
import android.telephony.Annotation.NetworkType;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthNr;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RegState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -935,6 +939,119 @@ public class BatteryStatsImpl extends BatteryStats {
final StopwatchTimer[] mPhoneDataConnectionsTimer =
new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
@RadioAccessTechnology
int mActiveRat = RADIO_ACCESS_TECHNOLOGY_OTHER;
private static class RadioAccessTechnologyBatteryStats {
/**
* This RAT is currently being used.
*/
private boolean mActive = false;
/**
* Current active frequency range for this RAT.
*/
@ServiceState.FrequencyRange
private int mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
/**
* Current signal strength for this RAT.
*/
private int mSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
/**
* Timers for each combination of frequency range and signal strength.
*/
public final StopwatchTimer[][] perStateTimers;
RadioAccessTechnologyBatteryStats(int freqCount, Clock clock, TimeBase timeBase) {
perStateTimers =
new StopwatchTimer[freqCount][CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS];
for (int i = 0; i < freqCount; i++) {
for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
perStateTimers[i][j] = new StopwatchTimer(clock, null, -1, null, timeBase);
}
}
}
/**
* Note this RAT is currently being used.
*/
public void noteActive(boolean active, long elapsedRealtimeMs) {
if (mActive == active) return;
mActive = active;
if (mActive) {
perStateTimers[mFrequencyRange][mSignalStrength].startRunningLocked(
elapsedRealtimeMs);
} else {
perStateTimers[mFrequencyRange][mSignalStrength].stopRunningLocked(
elapsedRealtimeMs);
}
}
/**
* Note current frequency range has changed.
*/
public void noteFrequencyRange(@ServiceState.FrequencyRange int frequencyRange,
long elapsedRealtimeMs) {
if (mFrequencyRange == frequencyRange) return;
if (!mActive) {
// RAT not in use, note the frequency change and move on.
mFrequencyRange = frequencyRange;
return;
}
perStateTimers[mFrequencyRange][mSignalStrength].stopRunningLocked(elapsedRealtimeMs);
perStateTimers[frequencyRange][mSignalStrength].startRunningLocked(elapsedRealtimeMs);
mFrequencyRange = frequencyRange;
}
/**
* Note current signal strength has changed.
*/
public void noteSignalStrength(int signalStrength, long elapsedRealtimeMs) {
if (mSignalStrength == signalStrength) return;
if (!mActive) {
// RAT not in use, note the signal strength change and move on.
mSignalStrength = signalStrength;
return;
}
perStateTimers[mFrequencyRange][mSignalStrength].stopRunningLocked(elapsedRealtimeMs);
perStateTimers[mFrequencyRange][signalStrength].startRunningLocked(elapsedRealtimeMs);
mSignalStrength = signalStrength;
}
/**
* Reset display timers.
*/
public void reset(long elapsedRealtimeUs) {
final int size = perStateTimers.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
perStateTimers[i][j].reset(false, elapsedRealtimeUs);
}
}
}
}
/**
* Number of frequency ranges, keep in sync with {@link ServiceState.FrequencyRange}
*/
private static final int NR_FREQUENCY_COUNT = 5;
RadioAccessTechnologyBatteryStats[] mPerRatBatteryStats =
new RadioAccessTechnologyBatteryStats[RADIO_ACCESS_TECHNOLOGY_COUNT];
@GuardedBy("this")
private RadioAccessTechnologyBatteryStats getRatBatteryStatsLocked(
@RadioAccessTechnology int rat) {
RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
if (stats == null) {
final int freqCount = rat == RADIO_ACCESS_TECHNOLOGY_NR ? NR_FREQUENCY_COUNT : 1;
stats = new RadioAccessTechnologyBatteryStats(freqCount, mClock, mOnBatteryTimeBase);
mPerRatBatteryStats[rat] = stats;
}
return stats;
}
final LongSamplingCounter[] mNetworkByteActivityCounters =
new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -5886,6 +6003,10 @@ public class BatteryStatsImpl extends BatteryStats {
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mMobileRadioPowerState = powerState;
// Inform current RatBatteryStats that the modem active state might have changed.
getRatBatteryStatsLocked(mActiveRat).noteActive(active, elapsedRealtimeMs);
if (active) {
mMobileRadioActiveTimer.startRunningLocked(elapsedRealtimeMs);
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtimeMs);
@@ -6307,21 +6428,86 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength,
long elapsedRealtimeMs, long uptimeMs) {
// Bin the strength.
int bin = signalStrength.getLevel();
updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin,
final int overallSignalStrength = signalStrength.getLevel();
final SparseIntArray perRatSignalStrength = new SparseIntArray(
BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT);
// Extract signal strength level for each RAT.
final List<CellSignalStrength> cellSignalStrengths =
signalStrength.getCellSignalStrengths();
final int size = cellSignalStrengths.size();
for (int i = 0; i < size; i++) {
CellSignalStrength cellSignalStrength = cellSignalStrengths.get(i);
// Map each CellSignalStrength to a BatteryStats.RadioAccessTechnology
final int ratType;
final int level;
if (cellSignalStrength instanceof CellSignalStrengthNr) {
ratType = RADIO_ACCESS_TECHNOLOGY_NR;
level = cellSignalStrength.getLevel();
} else if (cellSignalStrength instanceof CellSignalStrengthLte) {
ratType = RADIO_ACCESS_TECHNOLOGY_LTE;
level = cellSignalStrength.getLevel();
} else {
ratType = RADIO_ACCESS_TECHNOLOGY_OTHER;
level = cellSignalStrength.getLevel();
}
// According to SignalStrength#getCellSignalStrengths(), multiple of the same
// cellSignalStrength can be present. Just take the highest level one for each RAT.
if (perRatSignalStrength.get(ratType, -1) < level) {
perRatSignalStrength.put(ratType, level);
}
}
notePhoneSignalStrengthLocked(overallSignalStrength, perRatSignalStrength,
elapsedRealtimeMs, uptimeMs);
}
/**
* Note phone signal strength change, including per RAT signal strength.
*
* @param signalStrength overall signal strength {@see SignalStrength#getLevel()}
* @param perRatSignalStrength signal strength of available RATs
*/
@GuardedBy("this")
public void notePhoneSignalStrengthLocked(int signalStrength,
SparseIntArray perRatSignalStrength) {
notePhoneSignalStrengthLocked(signalStrength, perRatSignalStrength,
mClock.elapsedRealtime(), mClock.uptimeMillis());
}
/**
* Note phone signal strength change, including per RAT signal strength.
*
* @param signalStrength overall signal strength {@see SignalStrength#getLevel()}
* @param perRatSignalStrength signal strength of available RATs
*/
@GuardedBy("this")
public void notePhoneSignalStrengthLocked(int signalStrength,
SparseIntArray perRatSignalStrength,
long elapsedRealtimeMs, long uptimeMs) {
// Note each RAT's signal strength.
final int size = perRatSignalStrength.size();
for (int i = 0; i < size; i++) {
final int rat = perRatSignalStrength.keyAt(i);
final int ratSignalStrength = perRatSignalStrength.valueAt(i);
getRatBatteryStatsLocked(rat).noteSignalStrength(ratSignalStrength, elapsedRealtimeMs);
}
updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, signalStrength,
elapsedRealtimeMs, uptimeMs);
}
@UnsupportedAppUsage
@GuardedBy("this")
public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType) {
notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
public void notePhoneDataConnectionStateLocked(@NetworkType int dataType, boolean hasData,
@RegState int serviceType, @ServiceState.FrequencyRange int nrFrequency) {
notePhoneDataConnectionStateLocked(dataType, hasData, serviceType, nrFrequency,
mClock.elapsedRealtime(), mClock.uptimeMillis());
}
@GuardedBy("this")
public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType,
public void notePhoneDataConnectionStateLocked(@NetworkType int dataType, boolean hasData,
@RegState int serviceType, @ServiceState.FrequencyRange int nrFrequency,
long elapsedRealtimeMs, long uptimeMs) {
// BatteryStats uses 0 to represent no network type.
// Telephony does not have a concept of no network type, and uses 0 to represent unknown.
@@ -6344,6 +6530,13 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
}
final int newRat = mapNetworkTypeToRadioAccessTechnology(bin);
if (newRat == RADIO_ACCESS_TECHNOLOGY_NR) {
// Note possible frequency change for the NR RAT.
getRatBatteryStatsLocked(newRat).noteFrequencyRange(nrFrequency, elapsedRealtimeMs);
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
@@ -6357,6 +6550,45 @@ public class BatteryStatsImpl extends BatteryStats {
}
mPhoneDataConnectionType = bin;
mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtimeMs);
if (mActiveRat != newRat) {
getRatBatteryStatsLocked(mActiveRat).noteActive(false, elapsedRealtimeMs);
mActiveRat = newRat;
}
final boolean modemActive = mMobileRadioActiveTimer.isRunningLocked();
getRatBatteryStatsLocked(newRat).noteActive(modemActive, elapsedRealtimeMs);
}
}
@RadioAccessTechnology
private static int mapNetworkTypeToRadioAccessTechnology(@NetworkType int dataType) {
switch (dataType) {
case TelephonyManager.NETWORK_TYPE_NR:
return RADIO_ACCESS_TECHNOLOGY_NR;
case TelephonyManager.NETWORK_TYPE_LTE:
return RADIO_ACCESS_TECHNOLOGY_LTE;
case TelephonyManager.NETWORK_TYPE_UNKNOWN: //fallthrough
case TelephonyManager.NETWORK_TYPE_GPRS: //fallthrough
case TelephonyManager.NETWORK_TYPE_EDGE: //fallthrough
case TelephonyManager.NETWORK_TYPE_UMTS: //fallthrough
case TelephonyManager.NETWORK_TYPE_CDMA: //fallthrough
case TelephonyManager.NETWORK_TYPE_EVDO_0: //fallthrough
case TelephonyManager.NETWORK_TYPE_EVDO_A: //fallthrough
case TelephonyManager.NETWORK_TYPE_1xRTT: //fallthrough
case TelephonyManager.NETWORK_TYPE_HSDPA: //fallthrough
case TelephonyManager.NETWORK_TYPE_HSUPA: //fallthrough
case TelephonyManager.NETWORK_TYPE_HSPA: //fallthrough
case TelephonyManager.NETWORK_TYPE_IDEN: //fallthrough
case TelephonyManager.NETWORK_TYPE_EVDO_B: //fallthrough
case TelephonyManager.NETWORK_TYPE_EHRPD: //fallthrough
case TelephonyManager.NETWORK_TYPE_HSPAP: //fallthrough
case TelephonyManager.NETWORK_TYPE_GSM: //fallthrough
case TelephonyManager.NETWORK_TYPE_TD_SCDMA: //fallthrough
case TelephonyManager.NETWORK_TYPE_IWLAN: //fallthrough
return RADIO_ACCESS_TECHNOLOGY_OTHER;
default:
Slog.w(TAG, "Unhandled NetworkType (" + dataType + "), mapping to OTHER");
return RADIO_ACCESS_TECHNOLOGY_OTHER;
}
}
@@ -7731,6 +7963,23 @@ public class BatteryStatsImpl extends BatteryStats {
return mPhoneDataConnectionsTimer[dataType];
}
@Override public long getActiveRadioDurationMs(@RadioAccessTechnology int rat,
@ServiceState.FrequencyRange int frequencyRange, int signalStrength,
long elapsedRealtimeMs) {
final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
if (stats == null) return 0L;
final int freqCount = stats.perStateTimers.length;
if (frequencyRange < 0 || frequencyRange >= freqCount) return 0L;
final StopwatchTimer[] strengthTimers = stats.perStateTimers[frequencyRange];
final int strengthCount = strengthTimers.length;
if (signalStrength < 0 || signalStrength >= strengthCount) return 0L;
return stats.perStateTimers[frequencyRange][signalStrength].getTotalTimeLocked(
elapsedRealtimeMs * 1000, STATS_SINCE_CHARGED) / 1000;
}
@UnsupportedAppUsage
@Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
@@ -12553,6 +12802,11 @@ public class BatteryStatsImpl extends BatteryStats {
mNetworkByteActivityCounters[i].reset(false, elapsedRealtimeUs);
mNetworkPacketActivityCounters[i].reset(false, elapsedRealtimeUs);
}
for (int i = 0; i < RADIO_ACCESS_TECHNOLOGY_COUNT; i++) {
final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[i];
if (stats == null) continue;
stats.reset(elapsedRealtimeUs);
}
mMobileRadioActiveTimer.reset(false, elapsedRealtimeUs);
mMobileRadioActivePerAppTimer.reset(false, elapsedRealtimeUs);
mMobileRadioActiveAdjustedTime.reset(false, elapsedRealtimeUs);

View File

@@ -17,6 +17,7 @@
package com.android.internal.os;
import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
@@ -30,6 +31,12 @@ import android.os.BatteryStats.Uid.Sensor;
import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
import android.telephony.Annotation;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.Display;
@@ -1165,6 +1172,185 @@ public class BatteryStatsNoteTest extends TestCase {
"D", totalBlameA, totalBlameB, uid1, blame1A, blame1B, uid2, blame2A, blame2B, bi);
}
@SmallTest
public void testGetPerStateActiveRadioDurationMs() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
final int ratCount = BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
for (int rat = 0; rat < ratCount; rat++) {
for (int freq = 0; freq < frequencyCount; freq++) {
for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
expectedDurationsMs[rat][freq][txLvl] = 0;
}
}
}
class ModemAndBatteryState {
public long currentTimeMs = 100;
public boolean onBattery = false;
public boolean modemActive = false;
@Annotation.NetworkType
public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
@BatteryStats.RadioAccessTechnology
public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
@ServiceState.FrequencyRange
public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
public SparseIntArray currentSignalStrengths = new SparseIntArray();
void setOnBattery(boolean onBattery) {
this.onBattery = onBattery;
bi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
currentTimeMs * 1000);
}
void setModemActive(boolean active) {
modemActive = active;
final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
: DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
bi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
}
void setRatType(@Annotation.NetworkType int dataType,
@BatteryStats.RadioAccessTechnology int rat) {
currentNetworkDataType = dataType;
currentRat = rat;
bi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
currentFrequencyRange);
}
void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
currentFrequencyRange = frequency;
bi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
ServiceState.STATE_IN_SERVICE, frequency);
}
void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
currentSignalStrengths.put(rat, strength);
final int size = currentSignalStrengths.size();
final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
bi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
}
}
final ModemAndBatteryState state = new ModemAndBatteryState();
IntConsumer incrementTime = inc -> {
state.currentTimeMs += inc;
clock.realtime = clock.uptime = state.currentTimeMs;
// If the device is not on battery, no timers should increment.
if (!state.onBattery) return;
// If the modem is not active, no timers should increment.
if (!state.modemActive) return;
final int currentRat = state.currentRat;
final int currentFrequencyRange =
currentRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0;
int currentSignalStrength = state.currentSignalStrengths.get(currentRat);
expectedDurationsMs[currentRat][currentFrequencyRange][currentSignalStrength] += inc;
};
state.setOnBattery(false);
state.setModemActive(false);
state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// While not on battery, the timers should not increase.
state.setModemActive(true);
incrementTime.accept(100);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(200);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(500);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
incrementTime.accept(300);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
incrementTime.accept(400);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
incrementTime.accept(500);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
// start counting up.
state.setOnBattery(true);
incrementTime.accept(600);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Changing LTE signal strength should be tracked.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(700);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
incrementTime.accept(800);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(900);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GREAT);
incrementTime.accept(1000);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Change in the signal strength of nonactive RAT should not affect anything.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(1100);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Changing to OTHER Rat should start tracking the poor signal strength.
state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
incrementTime.accept(1200);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
incrementTime.accept(1300);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Now the NR Rat, HIGH frequency range, good signal strength should start counting.
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(1400);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
incrementTime.accept(1500);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
// Modem no longer active, should not be tracking any more.
state.setModemActive(false);
incrementTime.accept(1500);
checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
}
private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) {
// Note that noteUidProcessStateLocked uses ActivityManager process states.
if (fgOn) {
@@ -1238,4 +1424,30 @@ public class BatteryStatsNoteTest extends TestCase {
bi.getScreenBrightnessTime(bin, currentTimeMs * 1000, STATS_SINCE_CHARGED));
}
}
private void checkPerStateActiveRadioDurations(long[][][] expectedDurationsMs,
BatteryStatsImpl bi, long currentTimeMs) {
for (int rat = 0; rat < expectedDurationsMs.length; rat++) {
final long[][] expectedRatDurationsMs = expectedDurationsMs[rat];
for (int freq = 0; freq < expectedRatDurationsMs.length; freq++) {
final long[] expectedFreqDurationsMs = expectedRatDurationsMs[freq];
for (int strength = 0; strength < expectedFreqDurationsMs.length; strength++) {
final long expectedSignalStrengthDurationMs = expectedFreqDurationsMs[strength];
final long actualDurationMs = bi.getActiveRadioDurationMs(rat, freq,
strength, currentTimeMs);
// Build a verbose fail message, just in case.
final StringBuilder sb = new StringBuilder();
sb.append("Wrong time in state for RAT:");
sb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
sb.append(", frequency:");
sb.append(ServiceState.frequencyRangeToString(freq));
sb.append(", strength:");
sb.append(strength);
assertEquals(sb.toString(), expectedSignalStrengthDurationMs, actualDurationMs);
}
}
}
}
}

View File

@@ -1365,7 +1365,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
public void notePhoneDataConnectionState(final int dataType, final boolean hasData,
final int serviceType) {
final int serviceType, final int nrFrequency) {
enforceCallingPermission();
synchronized (mLock) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -1373,7 +1373,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mHandler.post(() -> {
synchronized (mStats) {
mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
elapsedRealtime, uptime);
nrFrequency, elapsedRealtime, uptime);
}
});
}

View File

@@ -109,7 +109,7 @@ public class DataConnectionStats extends BroadcastReceiver {
}
try {
mBatteryStats.notePhoneDataConnectionState(networkType, visible,
mServiceState.getState());
mServiceState.getState(), mServiceState.getNrFrequencyRange());
} catch (RemoteException e) {
Log.w(TAG, "Error noting data connection state", e);
}