diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index c476a59cc0a60..bf8ac6e55d8ad 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -36,7 +36,9 @@ public abstract class BatteryConsumer { * @hide */ @IntDef(prefix = {"POWER_COMPONENT_"}, value = { + POWER_COMPONENT_USAGE, POWER_COMPONENT_CPU, + POWER_COMPONENT_BLUETOOTH, }) @Retention(RetentionPolicy.SOURCE) public static @interface PowerComponent { @@ -44,8 +46,9 @@ public abstract class BatteryConsumer { public static final int POWER_COMPONENT_USAGE = 0; public static final int POWER_COMPONENT_CPU = 1; + public static final int POWER_COMPONENT_BLUETOOTH = 2; - public static final int POWER_COMPONENT_COUNT = 2; + public static final int POWER_COMPONENT_COUNT = 3; public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000; public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; @@ -68,8 +71,10 @@ public abstract class BatteryConsumer { * @hide */ @IntDef(prefix = {"TIME_COMPONENT_"}, value = { + TIME_COMPONENT_USAGE, TIME_COMPONENT_CPU, TIME_COMPONENT_CPU_FOREGROUND, + TIME_COMPONENT_BLUETOOTH, }) @Retention(RetentionPolicy.SOURCE) public static @interface TimeComponent { @@ -78,8 +83,9 @@ public abstract class BatteryConsumer { public static final int TIME_COMPONENT_USAGE = 0; public static final int TIME_COMPONENT_CPU = 1; public static final int TIME_COMPONENT_CPU_FOREGROUND = 2; + public static final int TIME_COMPONENT_BLUETOOTH = 3; - public static final int TIME_COMPONENT_COUNT = 3; + public static final int TIME_COMPONENT_COUNT = 4; public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000; public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999; diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java index 4a73b24a70998..18dca6816c556 100644 --- a/core/java/android/os/PowerComponents.java +++ b/core/java/android/os/PowerComponents.java @@ -289,6 +289,15 @@ class PowerComponents { return this; } + public void addPowerAndDuration(Builder other) { + for (int i = 0; i < mPowerComponents.length; i++) { + mPowerComponents[i] += other.mPowerComponents[i]; + } + for (int i = 0; i < mTimeComponents.length; i++) { + mTimeComponents[i] += other.mTimeComponents[i]; + } + } + /** * Creates a read-only object out of the Builder values. */ diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java index bda2f23ffc627..08e358f9094ed 100644 --- a/core/java/android/os/SystemBatteryConsumer.java +++ b/core/java/android/os/SystemBatteryConsumer.java @@ -21,6 +21,8 @@ import android.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** @@ -118,6 +120,7 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable public static final class Builder extends BaseBuilder { @DrainType private final int mDrainType; + private List mUidBatteryConsumers; Builder(int customPowerComponentCount, int customTimeComponentCount, boolean includeModeledComponents, @DrainType int drainType) { @@ -125,11 +128,36 @@ public class SystemBatteryConsumer extends BatteryConsumer implements Parcelable mDrainType = drainType; } + /** + * Add a UidBatteryConsumer to this SystemBatteryConsumer. For example, + * the UidBatteryConsumer with the UID == {@link Process#BLUETOOTH_UID} should + * be added to the SystemBatteryConsumer with the drain type == {@link + * #DRAIN_TYPE_BLUETOOTH}. + *

+ * Calculated power and duration components of the added battery consumers + * are aggregated at the time the SystemBatteryConsumer is built by the {@link #build()} + * method. + *

+ */ + public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) { + if (mUidBatteryConsumers == null) { + mUidBatteryConsumers = new ArrayList<>(); + } + mUidBatteryConsumers.add(uidBatteryConsumerBuilder); + } + /** * Creates a read-only object out of the Builder values. */ @NonNull public SystemBatteryConsumer build() { + if (mUidBatteryConsumers != null) { + for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) { + UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i); + mPowerComponentsBuilder.addPowerAndDuration( + uidBatteryConsumer.mPowerComponentsBuilder); + } + } return new SystemBatteryConsumer(this); } } diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java index c5da22b2dc55b..31617668be08f 100644 --- a/core/java/android/os/UidBatteryConsumer.java +++ b/core/java/android/os/UidBatteryConsumer.java @@ -29,11 +29,21 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela private final int mUid; @Nullable private final String mPackageWithHighestDrain; + private boolean mSystemComponent; public int getUid() { return mUid; } + /** + * Returns true if this battery consumer is considered to be a part of the operating + * system itself. For example, the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID} + * is a system component. + */ + public boolean isSystemComponent() { + return mSystemComponent; + } + @Nullable public String getPackageWithHighestDrain() { return mPackageWithHighestDrain; @@ -42,6 +52,7 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela private UidBatteryConsumer(@NonNull Builder builder) { super(builder.mPowerComponentsBuilder.build()); mUid = builder.mUid; + mSystemComponent = builder.mSystemComponent; mPackageWithHighestDrain = builder.mPackageWithHighestDrain; } @@ -84,6 +95,7 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela private final BatteryStats.Uid mBatteryStatsUid; private final int mUid; private String mPackageWithHighestDrain; + private boolean mSystemComponent; public Builder(int customPowerComponentCount, int customTimeComponentCount, boolean includeModeledComponents, BatteryStats.Uid batteryStatsUid) { @@ -117,5 +129,14 @@ public final class UidBatteryConsumer extends BatteryConsumer implements Parcela mPackageWithHighestDrain = packageName; return this; } + + /** + * Marks the UidBatteryConsumer as part of the system. For example, + * the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID} is considered + * as a system component. + */ + public void setSystemComponent(boolean systemComponent) { + mSystemComponent = systemComponent; + } } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index bdd96c24ade41..0fa0df6426e2e 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -953,7 +953,8 @@ public class BatteryStatsImpl extends BatteryStats { /** * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device. */ - ControllerActivityCounterImpl mBluetoothActivity; + @VisibleForTesting + protected ControllerActivityCounterImpl mBluetoothActivity; /** * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device. diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java index 11099bee576eb..f5690e0de38fa 100644 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java @@ -15,8 +15,13 @@ */ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; import android.os.Process; +import android.os.SystemBatteryConsumer; +import android.os.UidBatteryConsumer; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -30,8 +35,16 @@ public class BluetoothPowerCalculator extends PowerCalculator { private final double mRxMa; private final double mTxMa; private final boolean mHasBluetoothPowerController; - private double mAppTotalPowerMah = 0; - private long mAppTotalTimeMs = 0; + + private static class PowerAndDuration { + public long durationMs; + public double powerMah; + } + + // Objects used for passing calculation results. Fields are used to avoid allocations. + private final PowerAndDuration mUidPowerAndDuration = new PowerAndDuration(); + private final PowerAndDuration mTotalPowerAndDuration = new PowerAndDuration(); + private final PowerAndDuration mSystemPowerAndDuration = new PowerAndDuration(); public BluetoothPowerCalculator(PowerProfile profile) { mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); @@ -40,6 +53,63 @@ public class BluetoothPowerCalculator extends PowerCalculator { mHasBluetoothPowerController = mIdleMa != 0 && mRxMa != 0 && mTxMa != 0; } + @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray asUsers) { + if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) { + return; + } + + mTotalPowerAndDuration.durationMs = 0; + mTotalPowerAndDuration.powerMah = 0; + + SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = + builder.getOrCreateSystemBatteryConsumerBuilder( + SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH); + + final SparseArray uidBatteryConsumerBuilders = + builder.getUidBatteryConsumerBuilders(); + for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { + final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); + calculateApp(app); + if (app.getUid() == Process.BLUETOOTH_UID) { + app.setSystemComponent(true); + systemBatteryConsumerBuilder.addUidBatteryConsumer(app); + } + } + + final BatteryStats.ControllerActivityCounter counter = + batteryStats.getBluetoothControllerActivity(); + + calculatePowerAndDuration(counter, mSystemPowerAndDuration); + + // Subtract what the apps used, but clamp to 0. + final long systemComponentDurationMs = Math.max(0, + mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs); + final double systemComponentPowerMah = Math.max(0, + mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah); + + systemBatteryConsumerBuilder + .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, + systemComponentDurationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, + systemComponentPowerMah); + } + + private void calculateApp(UidBatteryConsumer.Builder app) { + calculatePowerAndDuration(app.getBatteryStatsUid().getBluetoothControllerActivity(), + mUidPowerAndDuration); + + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, + mUidPowerAndDuration.durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, + mUidPowerAndDuration.powerMah); + + mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah; + mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs; + } + @Override public void calculate(List sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray asUsers) { @@ -47,10 +117,27 @@ public class BluetoothPowerCalculator extends PowerCalculator { return; } + mTotalPowerAndDuration.durationMs = 0; + mTotalPowerAndDuration.powerMah = 0; + super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers); BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0); - calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType); + calculatePowerAndDuration(batteryStats.getBluetoothControllerActivity(), + mSystemPowerAndDuration); + + // Subtract what the apps used, but clamp to 0. + double powerMah = + Math.max(0, mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah); + final long durationMs = + Math.max(0, mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs); + if (DEBUG && powerMah != 0) { + Log.d(TAG, "Bluetooth active: time=" + (durationMs) + + " power=" + formatCharge(powerMah)); + } + + bs.bluetoothPowerMah = powerMah; + bs.bluetoothRunningTimeMs = durationMs; for (int i = sippers.size() - 1; i >= 0; i--) { BatterySipper app = sippers.get(i); @@ -69,65 +156,42 @@ public class BluetoothPowerCalculator extends PowerCalculator { protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { - final BatteryStats.ControllerActivityCounter counter = u.getBluetoothControllerActivity(); - if (counter == null) { - return; - } + calculatePowerAndDuration(u.getBluetoothControllerActivity(), mUidPowerAndDuration); - final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType); - final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType); - final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType); - final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs; - double powerMah = counter.getPowerCounter().getCountLocked(statsType) - / (double)(1000*60*60); - - if (powerMah == 0) { - powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa)) - / (1000*60*60); - } - - app.bluetoothPowerMah = powerMah; - app.bluetoothRunningTimeMs = totalTimeMs; + app.bluetoothPowerMah = mUidPowerAndDuration.powerMah; + app.bluetoothRunningTimeMs = mUidPowerAndDuration.durationMs; app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType); app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType); - mAppTotalPowerMah += powerMah; - mAppTotalTimeMs += totalTimeMs; + mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah; + mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs; } - private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - final BatteryStats.ControllerActivityCounter counter = - stats.getBluetoothControllerActivity(); + private void calculatePowerAndDuration(BatteryStats.ControllerActivityCounter counter, + PowerAndDuration powerAndDuration) { + if (counter == null) { + powerAndDuration.durationMs = 0; + powerAndDuration.powerMah = 0; + return; + } - final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType); - final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType); - final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType); + 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); final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs; - double powerMah = counter.getPowerCounter().getCountLocked(statsType) - / (double)(1000*60*60); + double powerMah = + counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED) + / (double) (1000 * 60 * 60); if (powerMah == 0) { - // Some devices do not report the power, so calculate it. powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa)) - / (1000*60*60); + / (1000 * 60 * 60); } - // Subtract what the apps used, but clamp to 0. - powerMah = Math.max(0, powerMah - mAppTotalPowerMah); - - if (DEBUG && powerMah != 0) { - Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs) - + " power=" + formatCharge(powerMah)); - } - - app.bluetoothPowerMah = powerMah; - app.bluetoothRunningTimeMs = Math.max(0, totalTimeMs - mAppTotalTimeMs); - } - - @Override - public void reset() { - mAppTotalPowerMah = 0; - mAppTotalTimeMs = 0; + powerAndDuration.durationMs = totalTimeMs; + powerAndDuration.powerMah = powerMah; } } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java index cfa8c4ded81f6..67f4c8a16da69 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -39,6 +39,7 @@ import org.junit.runners.Suite; BatteryStatsTimerTest.class, BatteryStatsUidTest.class, BatteryStatsUserLifecycleTests.class, + BluetoothPowerCalculatorTest.class, BstatsCpuTimesValidationTest.class, KernelCpuProcStringReaderTest.class, KernelCpuUidActiveTimeReaderTest.class, diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java new file mode 100644 index 0000000000000..96eb8da71ddb0 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.annotation.Nullable; +import android.os.BatteryConsumer; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.Process; +import android.os.SystemBatteryConsumer; +import android.os.UidBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BluetoothPowerCalculatorTest { + private static final double PRECISION = 0.00001; + private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Mock + private PowerProfile mMockPowerProfile; + private MockBatteryStatsImpl mMockBatteryStats; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) { + @Override + public boolean hasBluetoothActivityReporting() { + return true; + } + }; + mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000); + when(mMockPowerProfile.getAveragePower( + PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)).thenReturn(10.0); + when(mMockPowerProfile.getAveragePower( + PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)).thenReturn(50.0); + when(mMockPowerProfile.getAveragePower( + PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)).thenReturn(100.0); + } + + @Test + public void testTimerBasedModel() { + setDurationsAndPower( + mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID) + .getOrCreateBluetoothControllerActivityLocked(), + 1000, 2000, 3000, 0); + + setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID) + .getOrCreateBluetoothControllerActivityLocked(), + 4000, 5000, 6000, 0); + + setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl) + mMockBatteryStats.getBluetoothControllerActivity(), + 6000, 8000, 10000, 0); + + BatteryUsageStats batteryUsageStats = buildBatteryUsageStats(); + + assertBluetoothPowerAndDuration( + getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID), + 0.11388, 6000); + assertBluetoothPowerAndDuration( + getUidBatteryConsumer(batteryUsageStats, APP_UID), + 0.24722, 15000); + assertBluetoothPowerAndDuration( + getBluetoothSystemBatteryConsumer(batteryUsageStats, + SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), + 0.15833, 9000); + } + + @Test + public void testReportedPowerBasedModel() { + setDurationsAndPower( + mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID) + .getOrCreateBluetoothControllerActivityLocked(), + 1000, 2000, 3000, 360000); + + setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID) + .getOrCreateBluetoothControllerActivityLocked(), + 4000, 5000, 6000, 720000); + + setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl) + mMockBatteryStats.getBluetoothControllerActivity(), + 6000, 8000, 10000, 1260000); + + BatteryUsageStats batteryUsageStats = buildBatteryUsageStats(); + + assertBluetoothPowerAndDuration( + getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID), + 0.1, 6000); + assertBluetoothPowerAndDuration( + getUidBatteryConsumer(batteryUsageStats, APP_UID), + 0.2, 15000); + assertBluetoothPowerAndDuration( + getBluetoothSystemBatteryConsumer(batteryUsageStats, + SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), + 0.15, 9000); + } + + private void setDurationsAndPower( + BatteryStatsImpl.ControllerActivityCounterImpl controllerActivity, int idleDurationMs, + int rxDurationMs, int txDurationMs, long powerMaMs) { + controllerActivity.getIdleTimeCounter().addCountLocked(idleDurationMs); + controllerActivity.getRxTimeCounter().addCountLocked(rxDurationMs); + controllerActivity.getTxTimeCounters()[0].addCountLocked(txDurationMs); + controllerActivity.getPowerCounter().addCountLocked(powerMaMs); + } + + private BatteryUsageStats buildBatteryUsageStats() { + BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false); + builder.getOrCreateUidBatteryConsumerBuilder( + mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)); + builder.getOrCreateUidBatteryConsumerBuilder( + mMockBatteryStats.getUidStatsLocked(APP_UID)); + + BluetoothPowerCalculator bpc = new BluetoothPowerCalculator(mMockPowerProfile); + bpc.calculate(builder, mMockBatteryStats, 200_000, 200_000, BatteryUsageStatsQuery.DEFAULT, + null); + return builder.build(); + } + + private UidBatteryConsumer getUidBatteryConsumer(BatteryUsageStats batteryUsageStats, int uid) { + for (UidBatteryConsumer ubc : batteryUsageStats.getUidBatteryConsumers()) { + if (ubc.getUid() == uid) { + return ubc; + } + } + return null; + } + + private SystemBatteryConsumer getBluetoothSystemBatteryConsumer( + BatteryUsageStats batteryUsageStats, int drainType) { + for (SystemBatteryConsumer sbc : batteryUsageStats.getSystemBatteryConsumers()) { + if (sbc.getDrainType() == drainType) { + return sbc; + } + } + return null; + } + + private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer, + double powerMah, int durationMs) { + assertThat(batteryConsumer).isNotNull(); + + double consumedPower = batteryConsumer.getConsumedPower( + BatteryConsumer.POWER_COMPONENT_BLUETOOTH); + assertThat(consumedPower).isWithin(PRECISION).of(powerMah); + + long usageDurationMillis = batteryConsumer.getUsageDurationMillis( + BatteryConsumer.TIME_COMPONENT_BLUETOOTH); + + assertThat(usageDurationMillis).isEqualTo(durationMs); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index 1b1590afa7e06..c7751371d557b 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -47,6 +47,7 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null, mOnBatteryTimeBase); mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase); + mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1); setExternalStatsSyncLocked(new DummyExternalStatsSync()); for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {