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

Commit cd1c0184 authored by Michael Wachenschwanz's avatar Michael Wachenschwanz Committed by Android (Google) Code Review
Browse files

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

parents e1fc7f4a 47e331de
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},
@@ -12038,8 +12056,7 @@ public class BatteryStatsImpl extends BatteryStats {
            }
            final SparseDoubleArray uidEstimatedConsumptionMah;
            if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null
                    && mGlobalEnergyConsumerStats != null) {
            if (consumedChargeUC > 0 && isMobileRadioEnergyConsumerSupportedLocked()) {
                mGlobalEnergyConsumerStats.updateStandardBucket(
                        EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
                uidEstimatedConsumptionMah = new SparseDoubleArray();
@@ -12047,6 +12064,8 @@ public class BatteryStatsImpl extends BatteryStats {
                uidEstimatedConsumptionMah = null;
            }
            RxTxConsumption rxTxConsumption = null;
            boolean attributeWithModemActivityInfo = false;
            if (deltaInfo != null) {
                mHasModemReporting = true;
                mModemActivity.getOrCreateIdleTimeCounter()
@@ -12092,7 +12111,11 @@ public class BatteryStatsImpl extends BatteryStats {
                    mTmpRailStats.resetCellularTotalEnergyUsed();
                }
                incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs);
                rxTxConsumption = incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs);
                attributeWithModemActivityInfo = mConstants.PER_UID_MODEM_MODEL
                        == PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX
                        && rxTxConsumption != null;
            }
            long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
                    elapsedRealtimeMs * 1000);
@@ -12156,12 +12179,23 @@ public class BatteryStatsImpl extends BatteryStats {
                                (totalAppRadioTimeUs * appPackets) / totalPackets;
                        u.noteMobileRadioActiveTimeLocked(appRadioTimeUs, elapsedRealtimeMs);
                        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
@@ -12199,13 +12233,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 +=
@@ -12214,16 +12260,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.
@@ -12232,21 +12277,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)
@@ -12296,6 +12371,16 @@ public class BatteryStatsImpl extends BatteryStats {
                                            + (totalLvlDurationMs / 2)) / totalLvlDurationMs;
                            ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs);
                            frequencyDurationMs += durationMs;
                            if (isMobileRadioEnergyConsumerSupportedLocked()) {
                                // Accumulate the power cost of time spent transmitting in a
                                // particular state.
                                final double txStatePowerConsumptionMah =
                                        mMobileRadioPowerCalculator.calcTxStatePowerMah(rat, freq,
                                                level, proportionalTxDurationMs);
                                txConsumptionMah += txStatePowerConsumptionMah;
                                txDurationMs += proportionalTxDurationMs;
                            }
                        }
                        final long totalRxDuration = deltaInfo.getReceiveTimeMillis();
                        // Smear HAL provided Rx power duration based on active modem
@@ -12305,6 +12390,16 @@ public class BatteryStatsImpl extends BatteryStats {
                                (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs
                                        / 2)) / totalActiveTimeMs;
                        ratStats.incrementRxDuration(freq, proportionalRxDurationMs);
                        if (isMobileRadioEnergyConsumerSupportedLocked()) {
                            // Accumulate the power cost of time spent receiving in a particular
                            // state.
                            final double rxStatePowerConsumptionMah =
                                    mMobileRadioPowerCalculator.calcRxStatePowerMah(rat, freq,
                                            proportionalRxDurationMs);
                            rxConsumptionMah += rxStatePowerConsumptionMah;
                            rxDurationMs += proportionalRxDurationMs;
                        }
                    }
                }
@@ -12324,9 +12419,28 @@ public class BatteryStatsImpl extends BatteryStats {
                final int[] txTimesMs = deltaInfo.getTransmitTimeMillis(rat, freq);
                ratStats.incrementRxDuration(freq, rxTimeMs);
                if (isMobileRadioEnergyConsumerSupportedLocked()) {
                    // Accumulate the power cost of time spent receiving in a particular state.
                    final double rxStatePowerConsumptionMah =
                            mMobileRadioPowerCalculator.calcRxStatePowerMah(ratBucket, freq,
                                    rxTimeMs);
                    rxConsumptionMah += rxStatePowerConsumptionMah;
                    rxDurationMs += rxTimeMs;
                }
                final int numTxLvl = txTimesMs.length;
                for (int lvl = 0; lvl < numTxLvl; lvl++) {
                    ratStats.incrementTxDuration(freq, lvl, txTimesMs[lvl]);
                    final long txTimeMs = txTimesMs[lvl];
                    ratStats.incrementTxDuration(freq, lvl, txTimeMs);
                    if (isMobileRadioEnergyConsumerSupportedLocked()) {
                        // Accumulate the power cost of time spent transmitting in a particular
                        // state.
                        final double txStatePowerConsumptionMah =
                                mMobileRadioPowerCalculator.calcTxStatePowerMah(ratBucket, freq,
                                        lvl, txTimeMs);
                        txConsumptionMah += txStatePowerConsumptionMah;
                        txDurationMs += txTimeMs;
                    }
                }
            }
        }
@@ -12336,6 +12450,45 @@ public class BatteryStatsImpl extends BatteryStats {
            if (ratStats == null) continue;
            ratStats.setMark(elapsedRealtimeMs);
        }
        if (isMobileRadioEnergyConsumerSupportedLocked()) {
            return new RxTxConsumption(rxConsumptionMah, rxDurationMs, txConsumptionMah,
                    txDurationMs);
        } else {
            return null;
        }
    }
    /**
     * Smear modem Rx/Tx power consumption calculated from {@link ModemActivityInfo} using Rx/Tx
     * packets.
     *
     * @return the combine Rx/Tx smeared power consumption in milliamp-hours.
     */
    private double smearModemActivityInfoRxTxConsumptionMah(RxTxConsumption rxTxConsumption,
            long rxPackets, long txPackets, long totalRxPackets, long totalTxPackets) {
        // Distribute measured mobile radio charge consumption based on
        // rx/tx packets and estimated rx/tx charge consumption.
        double consumptionMah = 0.0;
        if (totalRxPackets != 0) {
            // Proportionally distribute receive battery consumption.
            consumptionMah += rxTxConsumption.rxConsumptionMah * rxPackets
                    / totalRxPackets;
        }
        if (totalTxPackets != 0 || (totalRxPackets != 0 && rxTxConsumption.txToTotalRatio != 0.0)) {
            // ModemActivityInfo Tx time represents time spent both transmitting and receiving.
            // There is currently no way to distinguish how many Rx packets were received during
            // Rx time vs Tx time.
            // Assumption: The number of packets received while transmitting is proportional
            // to the time spent transmitting over total active time.
            final double totalPacketsDuringTxTime =
                    totalTxPackets + rxTxConsumption.txToTotalRatio * totalRxPackets;
            final double packetsDuringTxTime =
                    txPackets + rxTxConsumption.txToTotalRatio * rxPackets;
            consumptionMah += rxTxConsumption.txConsumptionMah * packetsDuringTxTime
                    / totalPacketsDuringTxTime;
        }
        return consumptionMah;
    }
    /**
@@ -14844,6 +14997,13 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    @GuardedBy("this")
    private boolean isMobileRadioEnergyConsumerSupportedLocked() {
        if (mGlobalEnergyConsumerStats == null) return false;
        return mGlobalEnergyConsumerStats.isStandardBucketSupported(
                EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO);
    }
    @NonNull
    private static String[] getBatteryConsumerProcessStateNames() {
        String[] procStateNames = new String[BatteryConsumer.PROCESS_STATE_COUNT];
@@ -14879,6 +15039,40 @@ public class BatteryStatsImpl extends BatteryStats {
                "battery_charged_delay_ms";
        public static final String KEY_RECORD_USAGE_HISTORY =
                "record_usage_history";
        public static final String KEY_PER_UID_MODEM_POWER_MODEL =
                "per_uid_modem_power_model";
        public static final String PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME =
                "mobile_radio_active_time";
        public static final String PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME =
                "modem_activity_info_rx_tx";
        /** Convert {@link PerUidModemPowerModel} to string */
        public String getPerUidModemModelName(@PerUidModemPowerModel int model) {
            switch(model) {
                case PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME:
                    return PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME;
                case PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX:
                    return PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME;
                default:
                    Slog.w(TAG, "Unexpected per uid modem model (" + model + ")");
                    return "unknown_" + model;
            }
        }
        /** Convert string to {@link PerUidModemPowerModel} */
        @PerUidModemPowerModel
        public int getPerUidModemModel(String name) {
            switch(name) {
                case PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME:
                    return PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME;
                case PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX_NAME:
                    return PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
                default:
                    Slog.w(TAG, "Unexpected per uid modem model name (" + name + ")");
                    return DEFAULT_PER_UID_MODEM_MODEL;
            }
        }
        private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
        private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
@@ -14892,6 +15086,9 @@ public class BatteryStatsImpl extends BatteryStats {
        private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
        private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
        private static final boolean DEFAULT_RECORD_USAGE_HISTORY = false;
        @PerUidModemPowerModel
        private static final int DEFAULT_PER_UID_MODEM_MODEL =
                PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
        public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
        /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -14908,6 +15105,7 @@ public class BatteryStatsImpl extends BatteryStats {
        public int MAX_HISTORY_BUFFER; /*Bytes*/
        public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
        public boolean RECORD_USAGE_HISTORY = DEFAULT_RECORD_USAGE_HISTORY;
        public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
        private ContentResolver mResolver;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -14985,6 +15183,9 @@ public class BatteryStatsImpl extends BatteryStats {
                        * 1024;
                RECORD_USAGE_HISTORY = mParser.getBoolean(
                        KEY_RECORD_USAGE_HISTORY, DEFAULT_RECORD_USAGE_HISTORY);
                final String perUidModemModel = mParser.getString(KEY_PER_UID_MODEM_POWER_MODEL,
                        "");
                PER_UID_MODEM_MODEL = getPerUidModemModel(perUidModemModel);
                updateBatteryChargedDelayMsLocked();
@@ -15053,6 +15254,8 @@ public class BatteryStatsImpl extends BatteryStats {
            pw.println(BATTERY_CHARGED_DELAY_MS);
            pw.print(KEY_RECORD_USAGE_HISTORY); pw.print("=");
            pw.println(RECORD_USAGE_HISTORY);
            pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
            pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
        }
    }
+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;