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

Commit d643b331 authored by Michael Wachenschwanz's avatar Michael Wachenschwanz Committed by Automerger Merge Worker
Browse files

Merge "Fix MeasureEnergyArray impl array size" into sc-dev am: 98d8a3a9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13435067

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I52e2cf28c62bd64319f80b9d1e4ab2c10417ed64
parents 353e744d 98d8a3a9
Loading
Loading
Loading
Loading
+47 −10
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.SparseIntArray;
import android.util.SparseLongArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.power.MeasuredEnergyArray;
import com.android.internal.power.MeasuredEnergyStats;
@@ -96,8 +97,6 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
                        return t;
                    });

    private final Context mContext;

    @GuardedBy("mStats")
    private final BatteryStatsImpl mStats;

@@ -168,15 +167,39 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
    @GuardedBy("this")
    private long mLastCollectionTimeStamp;

    BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats) {
    final Injector mInjector;

    @VisibleForTesting
    public static class Injector {
        private final Context mContext;

        Injector(Context context) {
            mContext = context;
        }

        public <T> T getSystemService(Class<T> serviceClass) {
            return mContext.getSystemService(serviceClass);
        }

        public <T> T getLocalService(Class<T> serviceClass) {
            return LocalServices.getService(serviceClass);
        }
    }

    BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats) {
        this(new Injector(context), stats);
    }

    @VisibleForTesting
    BatteryExternalStatsWorker(Injector injector, BatteryStatsImpl stats) {
        mInjector = injector;
        mStats = stats;
    }

    public void systemServicesReady() {
        final WifiManager wm = mContext.getSystemService(WifiManager.class);
        final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
        final PowerStatsInternal psi = LocalServices.getService(PowerStatsInternal.class);
        final WifiManager wm = mInjector.getSystemService(WifiManager.class);
        final TelephonyManager tm = mInjector.getSystemService(TelephonyManager.class);
        final PowerStatsInternal psi = mInjector.getLocalService(PowerStatsInternal.class);
        synchronized (mWorkerLock) {
            mWifiManager = wm;
            mTelephony = tm;
@@ -747,7 +770,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
     * EnergyConsumerResult}[]
     */
    @GuardedBy("mWorkerLock")
    private @Nullable MeasuredEnergyArray getEnergyConsumptionData() {
    @VisibleForTesting
    public @Nullable MeasuredEnergyArray getEnergyConsumptionData() {
        final EnergyConsumerResult[] results;
        try {
            results = mPowerStatsInternal.getEnergyConsumedAsync(new int[0])
@@ -761,28 +785,41 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
        final int[] subsystems = new int[size];
        final long[] energyUJ = new long[size];

        int count = 0;
        for (int i = 0; i < size; i++) {
            final EnergyConsumerResult consumer = results[i];
            final int subsystem = mEnergyConsumerToSubsystemMap.get(consumer.id,
                    MeasuredEnergyArray.SUBSYSTEM_UNKNOWN);
            if (subsystem == MeasuredEnergyArray.SUBSYSTEM_UNKNOWN) continue;
            subsystems[i] = subsystem;
            energyUJ[i] = consumer.energyUWs;
            subsystems[count] = subsystem;
            energyUJ[count] = consumer.energyUWs;
            count++;
        }
        final int arraySize = count;
        return new MeasuredEnergyArray() {
            @Override
            public int getSubsystem(int index) {
                if (index >= size()) {
                    throw new IllegalArgumentException(
                            "Out of bounds subsystem index! index : " + index + ", size : "
                                    + size());
                }
                return subsystems[index];
            }

            @Override
            public long getEnergy(int index) {
                if (index >= size()) {
                    throw new IllegalArgumentException(
                            "Out of bounds subsystem index! index : " + index + ", size : "
                                    + size());
                }
                return energyUJ[index];
            }

            @Override
            public int size() {
                return size;
                return arraySize;
            }
        };
    }
+187 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.server.am;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;

import android.content.Context;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
import android.power.PowerStatsInternal;
import android.util.SparseArray;
import android.util.SparseLongArray;

import androidx.test.InstrumentationRegistry;

import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.power.MeasuredEnergyArray;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.CompletableFuture;

/**
 * Tests for {@link BatteryExternalStatsWorker}.
 *
 * Build/Install/Run:
 * atest FrameworksServicesTests:BatteryExternalStatsWorkerTest
 */
public class BatteryExternalStatsWorkerTest {
    private BatteryExternalStatsWorker mBatteryExternalStatsWorker;
    private TestBatteryStatsImpl mBatteryStatsImpl;
    private TestPowerStatsInternal mPowerStatsInternal;

    @Before
    public void setUp() {
        final Context context = InstrumentationRegistry.getContext();

        mBatteryStatsImpl = new TestBatteryStatsImpl();
        mPowerStatsInternal = new TestPowerStatsInternal();
        mBatteryExternalStatsWorker = new BatteryExternalStatsWorker(new TestInjector(context),
                mBatteryStatsImpl);
    }

    @Test
    public void getEnergyConsumptionData() {
        SparseLongArray expectSubsystems = new SparseLongArray();
        // Add some energy consumers used by BatteryExternalStatsWorker.
        final int displayId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.DISPLAY, 0,
                "display");
        mPowerStatsInternal.incrementEnergyConsumption(displayId, 12345);
        expectSubsystems.put(MeasuredEnergyArray.SUBSYSTEM_DISPLAY, 12345);

        // Add an arbitrary energy consumer unused by BatteryExternalStatsWorker.
        // Must be changed if '154' ever becomes an EnergyConsumerType used by BESW.
        final int someId = mPowerStatsInternal.addEnergyConsumer((byte) 154, 0, "some_consumer");
        mPowerStatsInternal.incrementEnergyConsumption(someId, 34567);

        // Inform BESW that PowerStatsInternal is ready to query
        mBatteryExternalStatsWorker.systemServicesReady();

        MeasuredEnergyArray energies = mBatteryExternalStatsWorker.getEnergyConsumptionData();

        assertEquals(expectSubsystems.size(), energies.size());
        final int size = expectSubsystems.size();

        for (int i = 0; i < size; i++) {
            int subsystem = expectSubsystems.keyAt(i);
            // find the subsystem in the returned MeasuredEnergyArray
            int subsystemIndex = -1;
            for (int j = 0; j < size; j++) {
                if (subsystem == energies.getSubsystem(i)) {
                    subsystemIndex = i;
                    break;
                }
            }
            assertNotEquals("Subsystem " + subsystem + " not found in MeasuredEnergyArray", -1,
                    subsystemIndex);
            assertEquals(expectSubsystems.valueAt(i), energies.getEnergy(subsystemIndex));
        }
    }

    public class TestInjector extends BatteryExternalStatsWorker.Injector {
        public TestInjector(Context context) {
            super(context);
        }

        public <T> T getSystemService(Class<T> serviceClass) {
            return null;
        }

        public <T> T getLocalService(Class<T> serviceClass) {
            if (serviceClass == PowerStatsInternal.class) {
                return (T) mPowerStatsInternal;
            }
            return null;
        }
    }

    public class TestBatteryStatsImpl extends BatteryStatsImpl {
    }

    public class TestPowerStatsInternal extends PowerStatsInternal {
        private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray<>();
        private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults =
                new SparseArray<>();
        private final int mTimeSinceBoot = 0;

        @Override
        public EnergyConsumer[] getEnergyConsumerInfo() {
            final int size = mEnergyConsumers.size();
            final EnergyConsumer[] consumers = new EnergyConsumer[size];
            for (int i = 0; i < size; i++) {
                consumers[i] = mEnergyConsumers.valueAt(i);
            }
            return consumers;
        }

        @Override
        public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync(
                int[] energyConsumerIds) {
            final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture();
            final int size = mEnergyConsumerResults.size();
            final EnergyConsumerResult[] results = new EnergyConsumerResult[size];
            for (int i = 0; i < size; i++) {
                results[i] = mEnergyConsumerResults.valueAt(i);
            }
            future.complete(results);
            return future;
        }

        /**
         * Util method to add a new EnergyConsumer for testing
         *
         * @return the EnergyConsumer id of the new EnergyConsumer
         */
        public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) {
            final EnergyConsumer consumer = new EnergyConsumer();
            final int id = getNextAvailableId();
            consumer.id = id;
            consumer.type = type;
            consumer.ordinal = ordinal;
            consumer.name = name;
            mEnergyConsumers.put(id, consumer);

            final EnergyConsumerResult result = new EnergyConsumerResult();
            result.id = id;
            result.timestampMs = mTimeSinceBoot;
            result.energyUWs = 0;
            mEnergyConsumerResults.put(id, result);
            return id;
        }

        public void incrementEnergyConsumption(int id, long energyUWs) {
            EnergyConsumerResult result = mEnergyConsumerResults.get(id, null);
            assertNotNull(result);
            result.energyUWs += energyUWs;
        }

        private int getNextAvailableId() {
            final int size = mEnergyConsumers.size();
            // Just return the first index that does not match the key (aka the EnergyConsumer id)
            for (int i = size - 1; i >= 0; i--) {
                if (mEnergyConsumers.keyAt(i) == i) return i + 1;
            }
            // Otherwise return the lowest id
            return 0;
        }
    }
}