Merge "Fix MeasureEnergyArray impl array size" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
98d8a3a9cf
@@ -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;
|
||||
|
||||
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) {
|
||||
mContext = context;
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user