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

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

Merge "Fix handling of inconsistent PowerStats HAL data" into main

parents a0b52cfd f855a62e
Loading
Loading
Loading
Loading
+11 −14
Original line number Diff line number Diff line
@@ -15430,17 +15430,18 @@ public class BatteryStatsImpl extends BatteryStats {
            mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState;
        }
        final boolean compatibleConfig;
        if (supportedStandardBuckets != null) {
            final EnergyConsumerStats.Config config = new EnergyConsumerStats.Config(
                    supportedStandardBuckets, customBucketNames,
                    SUPPORTED_PER_PROCESS_STATE_STANDARD_ENERGY_BUCKETS,
                    getBatteryConsumerProcessStateNames());
            if (mEnergyConsumerStatsConfig == null) {
                compatibleConfig = true;
            } else {
                compatibleConfig = mEnergyConsumerStatsConfig.isCompatible(config);
            if (mEnergyConsumerStatsConfig != null
                    &&  !mEnergyConsumerStatsConfig.isCompatible(config)) {
                // Supported power buckets changed since last boot.
                // Existing data is no longer reliable.
                resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(),
                        RESET_REASON_ENERGY_CONSUMER_BUCKETS_CHANGE);
            }
            mEnergyConsumerStatsConfig = config;
@@ -15456,18 +15457,14 @@ public class BatteryStatsImpl extends BatteryStats {
                mWifiPowerCalculator = new WifiPowerCalculator(mPowerProfile);
            }
        } else {
            compatibleConfig = (mEnergyConsumerStatsConfig == null);
            if (mEnergyConsumerStatsConfig != null) {
                // EnergyConsumer no longer supported, wipe out the existing data.
            mEnergyConsumerStatsConfig = null;
            mGlobalEnergyConsumerStats = null;
        }
        if (!compatibleConfig) {
            // Supported power buckets changed since last boot.
            // Existing data is no longer reliable.
                resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime(),
                        RESET_REASON_ENERGY_CONSUMER_BUCKETS_CHANGE);
            }
            mEnergyConsumerStatsConfig = null;
            mGlobalEnergyConsumerStats = null;
        }
    }
    @GuardedBy("this")
+57 −0
Original line number Diff line number Diff line
@@ -18,12 +18,17 @@ package com.android.server.power.stats;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.content.Context;
import android.hardware.SensorManager;
import android.os.AggregateBatteryConsumer;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
import android.os.BatteryStats;
@@ -34,6 +39,7 @@ import android.os.Parcel;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.platform.test.ravenwood.RavenwoodRule;
import android.util.SparseLongArray;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -516,6 +522,57 @@ public class BatteryUsageStatsProviderTest {
        mMockClock.realtime = timeMs;
    }

    @Test
    public void saveBatteryUsageStatsOnReset_incompatibleEnergyConsumers() throws Throwable {
        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
        batteryStats.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
        int componentId0 = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
        int componentId1 = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + 1;

        synchronized (batteryStats) {
            batteryStats.getUidStatsLocked(APP_UID);

            SparseLongArray uidEnergies = new SparseLongArray();
            uidEnergies.put(APP_UID, 30_000_000);
            batteryStats.updateCustomEnergyConsumerStatsLocked(0, 100_000_000, uidEnergies);
            batteryStats.updateCustomEnergyConsumerStatsLocked(1, 200_000_000, uidEnergies);
        }

        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext, null,
                mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), null, mMockClock);

        PowerStatsStore powerStatsStore = mock(PowerStatsStore.class);
        doAnswer(invocation -> {
            BatteryUsageStats stats = invocation.getArgument(1);
            AggregateBatteryConsumer device = stats.getAggregateBatteryConsumer(
                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
            assertThat(device.getCustomPowerComponentName(componentId0)).isEqualTo("FOO");
            assertThat(device.getCustomPowerComponentName(componentId1)).isEqualTo("BAR");
            assertThat(device.getConsumedPowerForCustomComponent(componentId0))
                    .isWithin(PRECISION).of(27.77777);
            assertThat(device.getConsumedPowerForCustomComponent(componentId1))
                    .isWithin(PRECISION).of(55.55555);

            UidBatteryConsumer uid = stats.getUidBatteryConsumers().get(0);
            assertThat(uid.getConsumedPowerForCustomComponent(componentId0))
                    .isWithin(PRECISION).of(8.33333);
            assertThat(uid.getConsumedPowerForCustomComponent(componentId1))
                    .isWithin(PRECISION).of(8.33333);
            return null;
        }).when(powerStatsStore).storeBatteryUsageStats(anyLong(), any());

        mStatsRule.getBatteryStats().saveBatteryUsageStatsOnReset(provider, powerStatsStore);

        // Make an incompatible change of supported energy components.  This will trigger
        // a BatteryStats reset, which will generate a snapshot of battery stats.
        mStatsRule.initMeasuredEnergyStatsLocked(
                new String[]{"COMPONENT1"});

        mStatsRule.waitForBackgroundThread();

        verify(powerStatsStore).storeBatteryUsageStats(anyLong(), any());
    }

    @Test
    public void testAggregateBatteryStats_incompatibleSnapshot() {
        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+28 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.power.stats;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -28,6 +30,7 @@ import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.UidBatteryConsumer;
@@ -74,6 +77,7 @@ public class BatteryUsageStatsRule implements TestRule {
    private NetworkStats mNetworkStats;
    private boolean[] mSupportedStandardBuckets;
    private String[] mCustomPowerComponentNames;
    private Throwable mThrowable;

    public BatteryUsageStatsRule() {
        this(0, null);
@@ -270,6 +274,7 @@ public class BatteryUsageStatsRule implements TestRule {
            public void evaluate() throws Throwable {
                before();
                base.evaluate();
                after();
            }
        };
    }
@@ -277,6 +282,9 @@ public class BatteryUsageStatsRule implements TestRule {
    private void before() {
        lateInitBatteryStats();
        HandlerThread bgThread = new HandlerThread("bg thread");
        bgThread.setUncaughtExceptionHandler((thread, throwable)-> {
            mThrowable = throwable;
        });
        bgThread.start();
        mHandler = new Handler(bgThread.getLooper());
        mBatteryStats.setHandler(mHandler);
@@ -285,6 +293,26 @@ public class BatteryUsageStatsRule implements TestRule {
        mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0);
    }

    private void after() throws Throwable {
        if (mHandler != null) {
            waitForBackgroundThread();
        }
    }

    public void waitForBackgroundThread() throws Throwable {
        if (mThrowable != null) {
            throw mThrowable;
        }

        ConditionVariable done = new ConditionVariable();
        mHandler.post(done::open);
        assertThat(done.block(10000)).isTrue();

        if (mThrowable != null) {
            throw mThrowable;
        }
    }

    public PowerProfile getPowerProfile() {
        return mPowerProfile;
    }