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

Commit dfce5289 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov
Browse files

Convert MobileRadioPowerCalculator to work with BatteryUsageStats

Test: atest FrameworksCoreTests:com.android.internal.os.MobileRadioPowerCalculatorTest
Bug: 175644968
Change-Id: Iea088a14adde4255767ca76d8ec4c40b404cb33c
parent 57d27a25
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ public abstract class BatteryConsumer {
            POWER_COMPONENT_AUDIO,
            POWER_COMPONENT_AUDIO,
            POWER_COMPONENT_VIDEO,
            POWER_COMPONENT_VIDEO,
            POWER_COMPONENT_FLASHLIGHT,
            POWER_COMPONENT_FLASHLIGHT,
            POWER_COMPONENT_MOBILE_RADIO,
            POWER_COMPONENT_SYSTEM_SERVICES,
            POWER_COMPONENT_SYSTEM_SERVICES,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
@@ -57,8 +58,9 @@ public abstract class BatteryConsumer {
    public static final int POWER_COMPONENT_VIDEO = 5;
    public static final int POWER_COMPONENT_VIDEO = 5;
    public static final int POWER_COMPONENT_FLASHLIGHT = 6;
    public static final int POWER_COMPONENT_FLASHLIGHT = 6;
    public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
    public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
    public static final int POWER_COMPONENT_MOBILE_RADIO = 8;


    public static final int POWER_COMPONENT_COUNT = 8;
    public static final int POWER_COMPONENT_COUNT = 9;


    public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
    public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
    public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
    public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -87,6 +89,7 @@ public abstract class BatteryConsumer {
            TIME_COMPONENT_BLUETOOTH,
            TIME_COMPONENT_BLUETOOTH,
            TIME_COMPONENT_CAMERA,
            TIME_COMPONENT_CAMERA,
            TIME_COMPONENT_FLASHLIGHT,
            TIME_COMPONENT_FLASHLIGHT,
            TIME_COMPONENT_MOBILE_RADIO,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public static @interface TimeComponent {
    public static @interface TimeComponent {
@@ -100,8 +103,9 @@ public abstract class BatteryConsumer {
    public static final int TIME_COMPONENT_AUDIO = 5;
    public static final int TIME_COMPONENT_AUDIO = 5;
    public static final int TIME_COMPONENT_VIDEO = 6;
    public static final int TIME_COMPONENT_VIDEO = 6;
    public static final int TIME_COMPONENT_FLASHLIGHT = 7;
    public static final int TIME_COMPONENT_FLASHLIGHT = 7;
    public static final int TIME_COMPONENT_MOBILE_RADIO = 8;


    public static final int TIME_COMPONENT_COUNT = 8;
    public static final int TIME_COMPONENT_COUNT = 9;


    public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
    public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
    public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
    public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
+2 −2
Original line number Original line Diff line number Diff line
@@ -41,7 +41,7 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable
            // Reserved: APP
            // Reserved: APP
            DRAIN_TYPE_BLUETOOTH,
            DRAIN_TYPE_BLUETOOTH,
            DRAIN_TYPE_CAMERA,
            DRAIN_TYPE_CAMERA,
            DRAIN_TYPE_CELL,
            DRAIN_TYPE_MOBILE_RADIO,
            DRAIN_TYPE_FLASHLIGHT,
            DRAIN_TYPE_FLASHLIGHT,
            DRAIN_TYPE_IDLE,
            DRAIN_TYPE_IDLE,
            DRAIN_TYPE_MEMORY,
            DRAIN_TYPE_MEMORY,
@@ -59,7 +59,7 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable
    public static final int DRAIN_TYPE_AMBIENT_DISPLAY = 0;
    public static final int DRAIN_TYPE_AMBIENT_DISPLAY = 0;
    public static final int DRAIN_TYPE_BLUETOOTH = 2;
    public static final int DRAIN_TYPE_BLUETOOTH = 2;
    public static final int DRAIN_TYPE_CAMERA = 3;
    public static final int DRAIN_TYPE_CAMERA = 3;
    public static final int DRAIN_TYPE_CELL = 4;
    public static final int DRAIN_TYPE_MOBILE_RADIO = 4;
    public static final int DRAIN_TYPE_FLASHLIGHT = 5;
    public static final int DRAIN_TYPE_FLASHLIGHT = 5;
    public static final int DRAIN_TYPE_IDLE = 6;
    public static final int DRAIN_TYPE_IDLE = 6;
    public static final int DRAIN_TYPE_MEMORY = 7;
    public static final int DRAIN_TYPE_MEMORY = 7;
+35 −34
Original line number Original line Diff line number Diff line
@@ -860,14 +860,11 @@ public class BatteryStatsImpl extends BatteryStats {
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected int mScreenState = Display.STATE_UNKNOWN;
    protected int mScreenState = Display.STATE_UNKNOWN;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    StopwatchTimer mScreenOnTimer;
    protected StopwatchTimer mScreenOnTimer;
    StopwatchTimer mScreenDozeTimer;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    protected StopwatchTimer mScreenDozeTimer;
    int mScreenBrightnessBin = -1;
    int mScreenBrightnessBin = -1;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    final StopwatchTimer[] mScreenBrightnessTimer =
    protected final StopwatchTimer[] mScreenBrightnessTimer =
            new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
            new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
    boolean mPretendScreenOff;
    boolean mPretendScreenOff;
@@ -912,8 +909,7 @@ public class BatteryStatsImpl extends BatteryStats {
    int mUsbDataState = USB_DATA_UNKNOWN;
    int mUsbDataState = USB_DATA_UNKNOWN;
    int mGpsSignalQualityBin = -1;
    int mGpsSignalQualityBin = -1;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    final StopwatchTimer[] mGpsSignalQualityTimer =
    protected final StopwatchTimer[] mGpsSignalQualityTimer =
        new StopwatchTimer[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
        new StopwatchTimer[GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS];
    int mPhoneSignalStrengthBin = -1;
    int mPhoneSignalStrengthBin = -1;
@@ -929,6 +925,7 @@ public class BatteryStatsImpl extends BatteryStats {
    final LongSamplingCounter[] mNetworkByteActivityCounters =
    final LongSamplingCounter[] mNetworkByteActivityCounters =
            new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
            new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
    final LongSamplingCounter[] mNetworkPacketActivityCounters =
    final LongSamplingCounter[] mNetworkPacketActivityCounters =
            new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
            new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -948,8 +945,7 @@ public class BatteryStatsImpl extends BatteryStats {
    /**
    /**
     * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
     * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
     */
     */
    @VisibleForTesting
    ControllerActivityCounterImpl mBluetoothActivity;
    protected ControllerActivityCounterImpl mBluetoothActivity;
    /**
    /**
     * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
     * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
@@ -993,8 +989,7 @@ public class BatteryStatsImpl extends BatteryStats {
    StopwatchTimer mWifiActiveTimer;
    StopwatchTimer mWifiActiveTimer;
    int mBluetoothScanNesting;
    int mBluetoothScanNesting;
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    StopwatchTimer mBluetoothScanTimer;
    protected StopwatchTimer mBluetoothScanTimer;
    int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
    int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
    long mMobileRadioActiveStartTimeMs;
    long mMobileRadioActiveStartTimeMs;
@@ -10718,6 +10713,31 @@ public class BatteryStatsImpl extends BatteryStats {
        mHandler = new MyHandler(handler.getLooper());
        mHandler = new MyHandler(handler.getLooper());
        mConstants = new Constants(mHandler);
        mConstants = new Constants(mHandler);
        mStartCount++;
        mStartCount++;
        initTimersAndCounters();
        mOnBattery = mOnBatteryInternal = false;
        long uptimeUs = mClocks.uptimeMillis() * 1000;
        long realtimeUs = mClocks.elapsedRealtime() * 1000;
        initTimes(uptimeUs, realtimeUs);
        mStartPlatformVersion = mEndPlatformVersion = Build.ID;
        mDischargeStartLevel = 0;
        mDischargeUnplugLevel = 0;
        mDischargePlugLevel = -1;
        mDischargeCurrentLevel = 0;
        mCurrentBatteryLevel = 0;
        initDischarge(realtimeUs);
        clearHistoryLocked();
        updateDailyDeadlineLocked();
        mPlatformIdleStateCallback = cb;
        mMeasuredEnergyRetriever = energyStatsCb;
        mUserInfoProvider = userInfoProvider;
        // Notify statsd that the system is initially not in doze.
        mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
        FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
    }
    @VisibleForTesting
    protected void initTimersAndCounters() {
        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
        mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
        mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
        mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
        for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -10789,26 +10809,6 @@ public class BatteryStatsImpl extends BatteryStats {
        mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
        mOnBattery = mOnBatteryInternal = false;
        long uptimeUs = mClocks.uptimeMillis() * 1000;
        long realtimeUs = mClocks.elapsedRealtime() * 1000;
        initTimes(uptimeUs, realtimeUs);
        mStartPlatformVersion = mEndPlatformVersion = Build.ID;
        mDischargeStartLevel = 0;
        mDischargeUnplugLevel = 0;
        mDischargePlugLevel = -1;
        mDischargeCurrentLevel = 0;
        mCurrentBatteryLevel = 0;
        initDischarge(realtimeUs);
        clearHistoryLocked();
        updateDailyDeadlineLocked();
        mPlatformIdleStateCallback = cb;
        mMeasuredEnergyRetriever = energyStatsCb;
        mUserInfoProvider = userInfoProvider;
        // Notify statsd that the system is initially not in doze.
        mDeviceIdleMode = DEVICE_IDLE_MODE_OFF;
        FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode);
    }
    }
    @UnsupportedAppUsage
    @UnsupportedAppUsage
@@ -11623,7 +11623,8 @@ public class BatteryStatsImpl extends BatteryStats {
    @GuardedBy("mModemNetworkLock")
    @GuardedBy("mModemNetworkLock")
    private NetworkStats mLastModemNetworkStats = new NetworkStats(0, -1);
    private NetworkStats mLastModemNetworkStats = new NetworkStats(0, -1);
    private NetworkStats readNetworkStatsLocked(String[] ifaces) {
    @VisibleForTesting
    protected NetworkStats readNetworkStatsLocked(String[] ifaces) {
        try {
        try {
            if (!ArrayUtils.isEmpty(ifaces)) {
            if (!ArrayUtils.isEmpty(ifaces)) {
                INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
                INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
@@ -11922,7 +11923,7 @@ public class BatteryStatsImpl extends BatteryStats {
    /**
    /**
     * Distribute Cell radio energy info and network traffic to apps.
     * Distribute Cell radio energy info and network traffic to apps.
     */
     */
    public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo,
    public void noteModemControllerActivity(@Nullable final ModemActivityInfo activityInfo,
            long elapsedRealtimeMs, long uptimeMs) {
            long elapsedRealtimeMs, long uptimeMs) {
        if (DEBUG_ENERGY) {
        if (DEBUG_ENERGY) {
            Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
            Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
+161 −85
Original line number Original line Diff line number Diff line
@@ -15,7 +15,12 @@
 */
 */
package com.android.internal.os;
package com.android.internal.os;


import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.SystemBatteryConsumer;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
import android.os.UserHandle;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrength;
import android.util.Log;
import android.util.Log;
@@ -26,103 +31,146 @@ import java.util.List;
public class MobileRadioPowerCalculator extends PowerCalculator {
public class MobileRadioPowerCalculator extends PowerCalculator {
    private static final String TAG = "MobRadioPowerCalculator";
    private static final String TAG = "MobRadioPowerCalculator";
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
    private final double mPowerRadioOn;
    private final double[] mPowerBins = new double[CellSignalStrength.getNumSignalStrengthLevels()];
    private final double mPowerScan;
    private BatteryStats mStats;
    private long mTotalAppMobileActiveMs = 0;


    /**
    private static final int NUM_SIGNAL_STRENGTH_LEVELS =
     * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio.
            CellSignalStrength.getNumSignalStrengthLevels();
     */
    private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) {
        final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
        final double MOBILE_POWER = mPowerRadioOn / 3600;


        final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
    private final UsageBasedPowerEstimator mActivePowerEstimator;
                statsType);
    private final UsageBasedPowerEstimator[] mIdlePowerEstimators =
        final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
            new UsageBasedPowerEstimator[NUM_SIGNAL_STRENGTH_LEVELS];
                statsType);
    private final UsageBasedPowerEstimator mScanPowerEstimator;
        final long mobileData = mobileRx + mobileTx;


        final long radioDataUptimeMs =
    private static class PowerAndDuration {
                mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
        public long durationMs;
        final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
        public double powerMah;
                ? (mobileData / (double) radioDataUptimeMs)
        public long totalAppDurationMs;
                : (((double) MOBILE_BPS) / 8 / 2048);
        public long signalDurationMs;
        return (MOBILE_POWER / mobilePps) / (60 * 60);
        public long noCoverageDurationMs;
    }
    }


    public MobileRadioPowerCalculator(PowerProfile profile) {
    public MobileRadioPowerCalculator(PowerProfile profile) {
        double temp =
        // Power consumption when radio is active
        double powerRadioActiveMa =
                profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
                profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
        if (temp != -1) {
        if (powerRadioActiveMa == -1) {
            mPowerRadioOn = temp;
        } else {
            double sum = 0;
            double sum = 0;
            sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
            sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
            for (int i = 0; i < mPowerBins.length; i++) {
            for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
                sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
                sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
            }
            }
            mPowerRadioOn = sum / (mPowerBins.length + 1);
            powerRadioActiveMa = sum / (NUM_SIGNAL_STRENGTH_LEVELS + 1);
        }
        }


        temp = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1);
        mActivePowerEstimator = new UsageBasedPowerEstimator(powerRadioActiveMa);
        if (temp != -1) {

            for (int i = 0; i < mPowerBins.length; i++) {
        // Power consumption when radio is on, but idle
                mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
        if (profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1) != -1) {
            for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
                mIdlePowerEstimators[i] = new UsageBasedPowerEstimator(
                        profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i));
            }
            }
        } else {
        } else {
            double idle = profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE);
            double idle = profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE);
            mPowerBins[0] = idle * 25 / 180;

            for (int i = 1; i < mPowerBins.length; i++) {
            // Magical calculations preserved for historical compatibility
                mPowerBins[i] = Math.max(1, idle / 256);
            mIdlePowerEstimators[0] = new UsageBasedPowerEstimator(idle * 25 / 180);
            for (int i = 1; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
                mIdlePowerEstimators[i] = new UsageBasedPowerEstimator(Math.max(1, idle / 256));
            }
        }

        mScanPowerEstimator = new UsageBasedPowerEstimator(
                profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0));
    }

    @Override
    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
            SparseArray<UserHandle> asUsers) {

        PowerAndDuration total = new PowerAndDuration();

        final double powerPerPacketMah = getMobilePowerPerPacket(batteryStats, rawRealtimeUs,
                BatteryStats.STATS_SINCE_CHARGED);
        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            final BatteryStats.Uid uid = app.getBatteryStatsUid();
            calculateApp(app, uid, powerPerPacketMah, total);
        }
        }

        calculateRemaining(total, batteryStats, rawRealtimeUs);

        if (total.powerMah != 0) {
            builder.getOrCreateSystemBatteryConsumerBuilder(
                    SystemBatteryConsumer.DRAIN_TYPE_MOBILE_RADIO)
                    .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
                            total.durationMs)
                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, total.powerMah);
        }
        }
    }

    private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
            double powerPerPacketMah, PowerAndDuration total) {
        final long radioActiveDurationMs = calculateDuration(u, BatteryStats.STATS_SINCE_CHARGED);
        total.totalAppDurationMs += radioActiveDurationMs;

        final double powerMah = calculatePower(u, powerPerPacketMah, radioActiveDurationMs);


        mPowerScan = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0);
        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_MOBILE_RADIO,
                radioActiveDurationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, powerMah);
    }
    }


    @Override
    @Override
    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
        mStats = batteryStats;
        final double mobilePowerPerPacket = getMobilePowerPerPacket(batteryStats, rawRealtimeUs,
        super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
                statsType);
        PowerAndDuration total = new PowerAndDuration();
        for (int i = sippers.size() - 1; i >= 0; i--) {
            final BatterySipper app = sippers.get(i);
            if (app.drainType == BatterySipper.DrainType.APP) {
                final BatteryStats.Uid u = app.uidObj;
                calculateApp(app, u, statsType, mobilePowerPerPacket, total);
            }
        }


        BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
        BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
        calculateRemaining(radio, mStats, rawRealtimeUs, rawUptimeUs, statsType);
        calculateRemaining(total, batteryStats, rawRealtimeUs);
        if (total.powerMah != 0) {
            if (total.signalDurationMs != 0) {
                radio.noCoveragePercent =
                        total.noCoverageDurationMs * 100.0 / total.signalDurationMs;
            }
            radio.mobileActive = total.durationMs;
            radio.mobileActiveCount = batteryStats.getMobileRadioActiveUnknownCount(statsType);
            radio.mobileRadioPowerMah = total.powerMah;
            radio.sumPower();
            radio.sumPower();
        }
        if (radio.totalPowerMah > 0) {
        if (radio.totalPowerMah > 0) {
            sippers.add(radio);
            sippers.add(radio);
        }
        }
    }
    }


    @Override
    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
            double powerPerPacketMah, PowerAndDuration total) {
            long rawUptimeUs, int statsType) {
        app.mobileActive = calculateDuration(u, statsType);
        app.mobileRadioPowerMah = calculatePower(u, powerPerPacketMah, app.mobileActive);
        total.totalAppDurationMs += app.mobileActive;

        // Add cost of mobile traffic.
        // Add cost of mobile traffic.
        app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
        app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
                statsType);
                statsType);
        app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
        app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
                statsType);
                statsType);
        app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;
        app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
        app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
        app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
        app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
                statsType);
                statsType);
        app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
        app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
                statsType);
                statsType);


        if (app.mobileActive > 0) {
            // We are tracking when the radio is up, so can use the active time to
            // determine power use.
            mTotalAppMobileActiveMs += app.mobileActive;
            app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000 * 60 * 60);
        } else {
            // We are not tracking when the radio is up, so must approximate power use
            // based on the number of packets.
            app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets)
                    * getMobilePowerPerPacket(rawRealtimeUs, statsType);
        }
        if (DEBUG && app.mobileRadioPowerMah != 0) {
        if (DEBUG && app.mobileRadioPowerMah != 0) {
            Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
            Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
                    + (app.mobileRxPackets + app.mobileTxPackets)
                    + (app.mobileRxPackets + app.mobileTxPackets)
@@ -131,52 +179,80 @@ public class MobileRadioPowerCalculator extends PowerCalculator {
        }
        }
    }
    }


    private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
    private long calculateDuration(BatteryStats.Uid u, int statsType) {
            long rawUptimeUs, int statsType) {
        return u.getMobileRadioActiveTime(statsType) / 1000;
        double power = 0;
    }

    private double calculatePower(BatteryStats.Uid u, double powerPerPacketMah,
            long radioActiveDurationMs) {
        if (radioActiveDurationMs > 0) {
            // We are tracking when the radio is up, so can use the active time to
            // determine power use.
            return mActivePowerEstimator.calculatePower(radioActiveDurationMs);
        } else {
            // We are not tracking when the radio is up, so must approximate power use
            // based on the number of packets.
            final long mobileRxPackets = u.getNetworkActivityPackets(
                    BatteryStats.NETWORK_MOBILE_RX_DATA,
                    BatteryStats.STATS_SINCE_CHARGED);
            final long mobileTxPackets = u.getNetworkActivityPackets(
                    BatteryStats.NETWORK_MOBILE_TX_DATA,
                    BatteryStats.STATS_SINCE_CHARGED);
            return (mobileRxPackets + mobileTxPackets) * powerPerPacketMah;
        }
    }

    private void calculateRemaining(MobileRadioPowerCalculator.PowerAndDuration total,
            BatteryStats batteryStats, long rawRealtimeUs) {
        long signalTimeMs = 0;
        long signalTimeMs = 0;
        long noCoverageTimeMs = 0;
        double powerMah = 0;
        for (int i = 0; i < mPowerBins.length; i++) {
        for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) {
            long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
            long strengthTimeMs = batteryStats.getPhoneSignalStrengthTime(i, rawRealtimeUs,
                    / 1000;
                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
            final double p = (strengthTimeMs * mPowerBins[i]) / (60 * 60 * 1000);
            final double p = mIdlePowerEstimators[i].calculatePower(strengthTimeMs);
            if (DEBUG && p != 0) {
            if (DEBUG && p != 0) {
                Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
                Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
                        + formatCharge(p));
                        + formatCharge(p));
            }
            }
            power += p;
            powerMah += p;
            signalTimeMs += strengthTimeMs;
            signalTimeMs += strengthTimeMs;
            if (i == 0) {
            if (i == 0) {
                noCoverageTimeMs = strengthTimeMs;
                total.noCoverageDurationMs = strengthTimeMs;
            }
            }
        }
        }


        final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
        final long scanningTimeMs = batteryStats.getPhoneSignalScanningTime(rawRealtimeUs,
                / 1000;
                BatteryStats.STATS_SINCE_CHARGED) / 1000;
        final double p = (scanningTimeMs * mPowerScan) / (60 * 60 * 1000);
        final double p = mScanPowerEstimator.calculatePower(scanningTimeMs);
        if (DEBUG && p != 0) {
        if (DEBUG && p != 0) {
            Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(p));
            Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + formatCharge(p));
        }
        }
        power += p;
        powerMah += p;
        long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
        long radioActiveTimeMs = batteryStats.getMobileRadioActiveTime(rawRealtimeUs,
        long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
                BatteryStats.STATS_SINCE_CHARGED) / 1000;
        long remainingActiveTimeMs = radioActiveTimeMs - total.totalAppDurationMs;
        if (remainingActiveTimeMs > 0) {
        if (remainingActiveTimeMs > 0) {
            power += (mPowerRadioOn * remainingActiveTimeMs) / (1000 * 60 * 60);
            powerMah += mActivePowerEstimator.calculatePower(remainingActiveTimeMs);
        }

        if (power != 0) {
            if (signalTimeMs != 0) {
                app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
            }
            app.mobileActive = remainingActiveTimeMs;
            app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType);
            app.mobileRadioPowerMah = power;
        }
        }
        total.durationMs = radioActiveTimeMs;
        total.powerMah = powerMah;
        total.signalDurationMs = signalTimeMs;
    }
    }


    @Override
    /**
    public void reset() {
     * Return estimated power (in mAh) of sending or receiving a packet with the mobile radio.
        mTotalAppMobileActiveMs = 0;
     */
        mStats = null;
    private double getMobilePowerPerPacket(BatteryStats stats, long rawRealtimeUs, int statsType) {
        final long radioDataUptimeMs =
                stats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
        final double mobilePower = mActivePowerEstimator.calculatePower(radioDataUptimeMs);

        final long mobileRx = stats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
                statsType);
        final long mobileTx = stats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
                statsType);
        final long mobilePackets = mobileRx + mobileTx;

        return mobilePackets != 0 ? mobilePower / mobilePackets : 0;
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,7 @@ import org.junit.runners.Suite;
        KernelWakelockReaderTest.class,
        KernelWakelockReaderTest.class,
        LongSamplingCounterTest.class,
        LongSamplingCounterTest.class,
        LongSamplingCounterArrayTest.class,
        LongSamplingCounterArrayTest.class,
        MobileRadioPowerCalculatorTest.class,
        PowerCalculatorTest.class,
        PowerCalculatorTest.class,
        PowerProfileTest.class,
        PowerProfileTest.class,
        ScreenPowerCalculatorTest.class,
        ScreenPowerCalculatorTest.class,
Loading