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

Commit 802df78a authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Attribution of Bluetooth power per process state"

parents 5636d17f 4cd04a25
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ public abstract class BatteryConsumer {
            POWER_COMPONENT_CPU,
            POWER_COMPONENT_MOBILE_RADIO,
            POWER_COMPONENT_WIFI,
            POWER_COMPONENT_BLUETOOTH,
    };

    static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0;
+10 −0
Original line number Diff line number Diff line
@@ -1036,6 +1036,16 @@ public abstract class BatteryStats implements Parcelable {
         */
        public abstract long getBluetoothMeasuredBatteryConsumptionUC();

        /**
         * Returns the battery consumption (in microcoulombs) of the uid's bluetooth usage
         * when in the specified process state.
         * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
         *
         * {@hide}
         */
        public abstract long getBluetoothMeasuredBatteryConsumptionUC(
                @BatteryConsumer.ProcessState int processState);

        /**
         * Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from
         * on device power measurement data.
+22 −1
Original line number Diff line number Diff line
@@ -265,6 +265,7 @@ public class BatteryStatsImpl extends BatteryStats {
            MeasuredEnergyStats.POWER_BUCKET_CPU,
            MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO,
            MeasuredEnergyStats.POWER_BUCKET_WIFI,
            MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH,
    };
    // TimeInState counters need NUM_PROCESS_STATE states in order to accommodate
@@ -8371,6 +8372,11 @@ public class BatteryStatsImpl extends BatteryStats {
            if (wifiControllerActivity != null) {
                wifiControllerActivity.setState(batteryConsumerProcessState, elapsedTimeMs);
            }
            final ControllerActivityCounterImpl bluetoothControllerActivity =
                    getBluetoothControllerActivity();
            if (bluetoothControllerActivity != null) {
                bluetoothControllerActivity.setState(batteryConsumerProcessState, elapsedTimeMs);
            }
            final MeasuredEnergyStats energyStats =
                    getOrCreateMeasuredEnergyStatsIfSupportedLocked();
            if (energyStats != null) {
@@ -8718,7 +8724,7 @@ public class BatteryStatsImpl extends BatteryStats {
        }
        @Override
        public ControllerActivityCounter getBluetoothControllerActivity() {
        public ControllerActivityCounterImpl getBluetoothControllerActivity() {
            return mBluetoothControllerActivity;
        }
@@ -8837,6 +8843,14 @@ public class BatteryStatsImpl extends BatteryStats {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH);
        }
        @GuardedBy("mBsi")
        @Override
        public long getBluetoothMeasuredBatteryConsumptionUC(
                @BatteryConsumer.ProcessState int processState) {
            return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_BLUETOOTH,
                    processState);
        }
        @GuardedBy("mBsi")
        @Override
        public long getCpuMeasuredBatteryConsumptionUC() {
@@ -11424,6 +11438,13 @@ public class BatteryStatsImpl extends BatteryStats {
                    wifiControllerActivity.setState(batteryConsumerProcessState, elapsedRealtimeMs);
                }
                final ControllerActivityCounterImpl bluetoothControllerActivity =
                        getBluetoothControllerActivity();
                if (bluetoothControllerActivity != null) {
                    bluetoothControllerActivity.setState(batteryConsumerProcessState,
                            elapsedRealtimeMs);
                }
                final MeasuredEnergyStats energyStats =
                        getOrCreateMeasuredEnergyStatsIfSupportedLocked();
                if (energyStats != null) {
+152 −70
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.internal.os;

import android.annotation.Nullable;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryStats.ControllerActivityCounter;
@@ -26,19 +27,33 @@ import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;

import java.util.Arrays;
import java.util.List;

public class BluetoothPowerCalculator extends PowerCalculator {
    private static final String TAG = "BluetoothPowerCalc";
    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;

    private static final BatteryConsumer.Key[] UNINITIALIZED_KEYS = new BatteryConsumer.Key[0];

    private final double mIdleMa;
    private final double mRxMa;
    private final double mTxMa;
    private final boolean mHasBluetoothPowerController;

    private static class PowerAndDuration {
        // Return value of BT duration per app
        public long durationMs;
        // Return value of BT power per app
        public double powerMah;

        public BatteryConsumer.Key[] keys;
        public double[] powerPerKeyMah;

        // Aggregated BT duration across all apps
        public long totalDurationMs;
        // Aggregated BT power across all apps
        public double totalPowerMah;
    }

    public BluetoothPowerCalculator(PowerProfile profile) {
@@ -55,59 +70,88 @@ public class BluetoothPowerCalculator extends PowerCalculator {
            return;
        }

        final PowerAndDuration total = new PowerAndDuration();
        BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS;
        final PowerAndDuration powerAndDuration = new PowerAndDuration();

        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
                builder.getUidBatteryConsumerBuilders();
        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
            calculateApp(app, total, query);
            if (keys == UNINITIALIZED_KEYS) {
                if (query.isProcessStateDataNeeded()) {
                    keys = app.getKeys(BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
                    powerAndDuration.keys = keys;
                    powerAndDuration.powerPerKeyMah = new double[keys.length];
                } else {
                    keys = null;
                }
            }
            calculateApp(app, powerAndDuration, query);
        }

        final long measuredChargeUC = batteryStats.getBluetoothMeasuredBatteryConsumptionUC();
        final int powerModel = getPowerModel(measuredChargeUC, query);
        final ControllerActivityCounter activityCounter =
                batteryStats.getBluetoothControllerActivity();
        final long systemDurationMs = calculateDuration(activityCounter);
        final double systemPowerMah = calculatePowerMah(powerModel, measuredChargeUC,
                activityCounter, query.shouldForceUsePowerProfileModel());
        calculatePowerAndDuration(null, powerModel, measuredChargeUC,
                activityCounter, query.shouldForceUsePowerProfileModel(), powerAndDuration);

        // Subtract what the apps used, but clamp to 0.
        final long systemComponentDurationMs = Math.max(0, systemDurationMs - total.durationMs);
        final long systemComponentDurationMs = Math.max(0,
                powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
        if (DEBUG) {
            Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs)
                    + " power=" + formatCharge(systemPowerMah));
                    + " power=" + formatCharge(powerAndDuration.powerMah));
        }

        builder.getAggregateBatteryConsumerBuilder(
                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, systemDurationMs)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                        powerAndDuration.durationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                        Math.max(systemPowerMah, total.powerMah), powerModel);
                        Math.max(powerAndDuration.powerMah, powerAndDuration.totalPowerMah),
                        powerModel);

        builder.getAggregateBatteryConsumerBuilder(
                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, total.durationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, total.powerMah,
                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                        powerAndDuration.totalDurationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
                        powerAndDuration.totalPowerMah,
                        powerModel);
    }

    private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total,
    private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration powerAndDuration,
            BatteryUsageStatsQuery query) {
        final long measuredChargeUC =
                app.getBatteryStatsUid().getBluetoothMeasuredBatteryConsumptionUC();
        final int powerModel = getPowerModel(measuredChargeUC, query);
        final ControllerActivityCounter activityCounter =
                app.getBatteryStatsUid().getBluetoothControllerActivity();
        final long durationMs = calculateDuration(activityCounter);
        final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter,
                query.shouldForceUsePowerProfileModel());
        calculatePowerAndDuration(app.getBatteryStatsUid(), powerModel, measuredChargeUC,
                activityCounter, query.shouldForceUsePowerProfileModel(), powerAndDuration);

        app.setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, durationMs)
                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah, powerModel);
        app.setUsageDurationMillis(
                        BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerAndDuration.durationMs)
                .setConsumedPower(
                        BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerAndDuration.powerMah,
                        powerModel);

        powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
        powerAndDuration.totalPowerMah += powerAndDuration.powerMah;

        if (query.isProcessStateDataNeeded() && powerAndDuration.keys != null) {
            for (int j = 0; j < powerAndDuration.keys.length; j++) {
                BatteryConsumer.Key key = powerAndDuration.keys[j];
                final int processState = key.processState;
                if (processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
                    // Already populated with the powerAndDuration across all process states
                    continue;
                }

        total.durationMs += durationMs;
        total.powerMah += powerMah;
                app.setConsumedPower(key, powerAndDuration.powerPerKeyMah[j], powerModel);
            }
        }
    }

    @Override
@@ -117,12 +161,12 @@ public class BluetoothPowerCalculator extends PowerCalculator {
            return;
        }

        PowerAndDuration total = new PowerAndDuration();
        PowerAndDuration powerAndDuration = new PowerAndDuration();

        for (int i = sippers.size() - 1; i >= 0; i--) {
            final BatterySipper app = sippers.get(i);
            if (app.drainType == BatterySipper.DrainType.APP) {
                calculateApp(app, app.uidObj, statsType, total);
                calculateApp(app, app.uidObj, statsType, powerAndDuration);
            }
        }

@@ -131,13 +175,14 @@ public class BluetoothPowerCalculator extends PowerCalculator {
        final int powerModel = getPowerModel(measuredChargeUC);
        final ControllerActivityCounter activityCounter =
                batteryStats.getBluetoothControllerActivity();
        final long systemDurationMs = calculateDuration(activityCounter);
        final double systemPowerMah =
                calculatePowerMah(powerModel, measuredChargeUC, activityCounter, false);
        calculatePowerAndDuration(null, powerModel, measuredChargeUC, activityCounter, false,
                powerAndDuration);

        // Subtract what the apps used, but clamp to 0.
        final double powerMah = Math.max(0, systemPowerMah - total.powerMah);
        final long durationMs = Math.max(0, systemDurationMs - total.durationMs);
        final double powerMah = Math.max(0,
                powerAndDuration.powerMah - powerAndDuration.totalPowerMah);
        final long durationMs = Math.max(0,
                powerAndDuration.durationMs - powerAndDuration.totalDurationMs);
        if (DEBUG && powerMah != 0) {
            Log.d(TAG, "Bluetooth active: time=" + (durationMs)
                    + " power=" + formatCharge(powerMah));
@@ -160,65 +205,102 @@ public class BluetoothPowerCalculator extends PowerCalculator {
    }

    private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType,
            PowerAndDuration total) {

            PowerAndDuration powerAndDuration) {
        final long measuredChargeUC = u.getBluetoothMeasuredBatteryConsumptionUC();
        final int powerModel = getPowerModel(measuredChargeUC);
        final ControllerActivityCounter activityCounter = u.getBluetoothControllerActivity();
        final long durationMs = calculateDuration(activityCounter);
        final double powerMah = calculatePowerMah(powerModel, measuredChargeUC, activityCounter,
                false);
        calculatePowerAndDuration(u, powerModel, measuredChargeUC, activityCounter,
                false, powerAndDuration);

        app.bluetoothRunningTimeMs = durationMs;
        app.bluetoothPowerMah = powerMah;
        app.bluetoothRunningTimeMs = powerAndDuration.durationMs;
        app.bluetoothPowerMah = powerAndDuration.powerMah;
        app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
        app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);

        total.durationMs += durationMs;
        total.powerMah += powerMah;
        powerAndDuration.totalDurationMs += powerAndDuration.durationMs;
        powerAndDuration.totalPowerMah += powerAndDuration.powerMah;
    }

    private long calculateDuration(ControllerActivityCounter counter) {
    /** Returns bluetooth power usage based on the best data available. */
    private void calculatePowerAndDuration(@Nullable BatteryStats.Uid uid,
            @BatteryConsumer.PowerModel int powerModel,
            long measuredChargeUC, ControllerActivityCounter counter, boolean ignoreReportedPower,
            PowerAndDuration powerAndDuration) {
        if (counter == null) {
            return 0;
            powerAndDuration.durationMs = 0;
            powerAndDuration.powerMah = 0;
            if (powerAndDuration.powerPerKeyMah != null) {
                Arrays.fill(powerAndDuration.powerPerKeyMah, 0);
            }

        return counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
                + counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
                + counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
            return;
        }

    /** Returns bluetooth power usage based on the best data available. */
    private double calculatePowerMah(@BatteryConsumer.PowerModel int powerModel,
            long measuredChargeUC, ControllerActivityCounter counter, boolean ignoreReportedPower) {
        final BatteryStats.LongCounter idleTimeCounter = counter.getIdleTimeCounter();
        final BatteryStats.LongCounter rxTimeCounter = counter.getRxTimeCounter();
        final BatteryStats.LongCounter txTimeCounter = counter.getTxTimeCounters()[0];
        final long idleTimeMs = idleTimeCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
        final long rxTimeMs = rxTimeCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
        final long txTimeMs = txTimeCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED);

        powerAndDuration.durationMs = idleTimeMs + rxTimeMs + txTimeMs;

        if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
            return uCtoMah(measuredChargeUC);
            powerAndDuration.powerMah = uCtoMah(measuredChargeUC);
            if (uid != null && powerAndDuration.keys != null) {
                for (int i = 0; i < powerAndDuration.keys.length; i++) {
                    BatteryConsumer.Key key = powerAndDuration.keys[i];
                    final int processState = key.processState;
                    if (processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
                        // Already populated with the powerAndDuration across all process states
                        continue;
                    }

        if (counter == null) {
            return 0;
                    powerAndDuration.powerPerKeyMah[i] =
                            uCtoMah(uid.getBluetoothMeasuredBatteryConsumptionUC(processState));
                }

            }
        } else {
            if (!ignoreReportedPower) {
                final double powerMah =
                        counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
                                / (double) (1000 * 60 * 60);
                if (powerMah != 0) {
                return powerMah;
                    powerAndDuration.powerMah = powerMah;
                    if (powerAndDuration.powerPerKeyMah != null) {
                        // Leave this use case unsupported: used energy is reported
                        // via BluetoothActivityEnergyInfo rather than PowerStats HAL.
                        Arrays.fill(powerAndDuration.powerPerKeyMah, 0);
                    }
                    return;
                }
            }

        if (!mHasBluetoothPowerController) {
            return 0;
            if (mHasBluetoothPowerController) {
                powerAndDuration.powerMah = calculatePowerMah(rxTimeMs, txTimeMs, idleTimeMs);

                if (powerAndDuration.keys != null) {
                    for (int i = 0; i < powerAndDuration.keys.length; i++) {
                        BatteryConsumer.Key key = powerAndDuration.keys[i];
                        final int processState = key.processState;
                        if (processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
                            // Already populated with the powerAndDuration across all process states
                            continue;
                        }

        final long idleTimeMs =
                counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
        final long rxTimeMs =
                counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
        final long txTimeMs =
                counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
        return calculatePowerMah(rxTimeMs, txTimeMs, idleTimeMs);
                        powerAndDuration.powerPerKeyMah[i] =
                                calculatePowerMah(
                                        rxTimeCounter.getCountForProcessState(processState),
                                        txTimeCounter.getCountForProcessState(processState),
                                        idleTimeCounter.getCountForProcessState(processState));
                    }
                }
            } else {
                powerAndDuration.powerMah = 0;
                if (powerAndDuration.powerPerKeyMah != null) {
                    Arrays.fill(powerAndDuration.powerPerKeyMah, 0);
                }
            }
        }
    }

    /** Returns estimated bluetooth power usage based on usage times. */
+1 −1
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ public class BatteryUsageStatsTest {
        final Parcel parcel = Parcel.obtain();
        parcel.writeParcelable(outBatteryUsageStats, 0);

        assertThat(parcel.dataSize()).isLessThan(6000);
        assertThat(parcel.dataSize()).isLessThan(7000);

        parcel.setDataPosition(0);

Loading