Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47e331de authored by Michael Wachenschwanz's avatar Michael Wachenschwanz
Browse files

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

If a device has Modem Energy Consumption data alongside
ModemActivityInfo, the per Uid attribution of the Modem Energy
Consumption is further refined using granular time-in-state info of
ModemActivityInfo.

Fixes: 259154416
Test: atest MobileRadioPowerCalculatorTest
Change-Id: I085fb52fba6fcc131138997db5e631c210d909f0
parent 947220af
Loading
Loading
Loading
Loading
+241 −38
Original line number Diff line number Diff line
@@ -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},
@@ -12003,8 +12021,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();
@@ -12012,6 +12029,8 @@ public class BatteryStatsImpl extends BatteryStats {
                uidEstimatedConsumptionMah = null;
            }
            RxTxConsumption rxTxConsumption = null;
            boolean attributeWithModemActivityInfo = false;
            if (deltaInfo != null) {
                mHasModemReporting = true;
                mModemActivity.getOrCreateIdleTimeCounter()
@@ -12057,7 +12076,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);
@@ -12121,12 +12144,23 @@ public class BatteryStatsImpl extends BatteryStats {
                                (totalAppRadioTimeUs * appPackets) / totalPackets;
                        u.noteMobileRadioActiveTimeLocked(appRadioTimeUs, elapsedRealtimeMs);
                        if (uidEstimatedConsumptionMah != null) {
                            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
                        if (uidEstimatedConsumptionMah != null) {
                            uidEstimatedConsumptionMah.incrementValue(u.getUid(),
                                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
@@ -12164,13 +12198,25 @@ public class BatteryStatsImpl extends BatteryStats {
                    mMobileRadioActiveUnknownCount.addCountLocked(1);
                }
                // Update the EnergyConsumerStats information.
                if (uidEstimatedConsumptionMah != null) {
                    double totalEstimatedConsumptionMah = 0.0;
                    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(
                        final long totalRadioTimeMs =
                                mMobileRadioActiveTimer.getTimeSinceMarkLocked(
                                        elapsedRealtimeMs * 1000) / 1000;
                        mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
                        totalEstimatedConsumptionMah +=
@@ -12179,16 +12225,15 @@ public class BatteryStatsImpl extends BatteryStats {
                        // Estimate idle power consumption at each signal strength level
                        final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
                    for (int strengthLevel = 0; strengthLevel < numSignalStrengthLevels;
                            strengthLevel++) {
                        for (int lvl = 0; lvl < numSignalStrengthLevels; lvl++) {
                            final long strengthLevelDurationMs =
                                mPhoneSignalStrengthsTimer[strengthLevel].getTimeSinceMarkLocked(
                                    mPhoneSignalStrengthsTimer[lvl].getTimeSinceMarkLocked(
                                            elapsedRealtimeMs * 1000) / 1000;
                        mPhoneSignalStrengthsTimer[strengthLevel].setMark(elapsedRealtimeMs);
                            mPhoneSignalStrengthsTimer[lvl].setMark(elapsedRealtimeMs);
                            totalEstimatedConsumptionMah +=
                                    mMobileRadioPowerCalculator.calcIdlePowerAtSignalStrengthMah(
                                        strengthLevelDurationMs, strengthLevel);
                                            strengthLevelDurationMs, lvl);
                        }
                        // Estimate total active radio power consumption since last mark.
@@ -12197,21 +12242,51 @@ public class BatteryStatsImpl extends BatteryStats {
                        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)
@@ -12261,6 +12336,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
@@ -12270,6 +12355,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;
                        }
                    }
                }
@@ -12289,9 +12384,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;
                    }
                }
            }
        }
@@ -12301,6 +12415,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;
    }
    /**
@@ -14762,6 +14915,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];
@@ -14797,6 +14957,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;
@@ -14810,6 +15004,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
@@ -14826,6 +15023,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(',');
@@ -14903,6 +15101,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();
@@ -14971,6 +15172,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));
        }
    }
+26 −7
Original line number Diff line number Diff line
@@ -270,24 +270,27 @@ 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.
     */
+7 −0
Original line number Diff line number Diff line
@@ -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]);
+260 −1

File changed.

Preview size limit exceeded, changes collapsed.

+7 −0
Original line number Diff line number Diff line
@@ -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;