1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.power.stats; 18 19 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL; 20 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_BT; 21 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CAMERA; 22 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU; 23 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY; 24 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO; 25 import static com.android.server.power.stats.BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI; 26 27 import static org.junit.Assert.assertArrayEquals; 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertNotNull; 30 31 import android.content.Context; 32 import android.hardware.power.stats.Channel; 33 import android.hardware.power.stats.EnergyConsumer; 34 import android.hardware.power.stats.EnergyConsumerResult; 35 import android.hardware.power.stats.EnergyConsumerType; 36 import android.hardware.power.stats.EnergyMeasurement; 37 import android.hardware.power.stats.PowerEntity; 38 import android.hardware.power.stats.StateResidencyResult; 39 import android.power.PowerStatsInternal; 40 import android.util.IntArray; 41 import android.util.SparseArray; 42 43 import androidx.test.InstrumentationRegistry; 44 45 import com.android.internal.os.PowerProfile; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 50 import java.util.Arrays; 51 import java.util.concurrent.CompletableFuture; 52 53 /** 54 * Tests for {@link BatteryExternalStatsWorker}. 55 * 56 * Build/Install/Run: 57 * atest FrameworksServicesTests:BatteryExternalStatsWorkerTest 58 */ 59 @SuppressWarnings("GuardedBy") 60 public class BatteryExternalStatsWorkerTest { 61 private BatteryExternalStatsWorker mBatteryExternalStatsWorker; 62 private TestBatteryStatsImpl mBatteryStatsImpl; 63 private TestPowerStatsInternal mPowerStatsInternal; 64 65 @Before setUp()66 public void setUp() { 67 final Context context = InstrumentationRegistry.getContext(); 68 69 mBatteryStatsImpl = new TestBatteryStatsImpl(context); 70 mPowerStatsInternal = new TestPowerStatsInternal(); 71 mBatteryExternalStatsWorker = new BatteryExternalStatsWorker(new TestInjector(context), 72 mBatteryStatsImpl); 73 } 74 75 @Test testTargetedEnergyConsumerQuerying()76 public void testTargetedEnergyConsumerQuerying() { 77 final int numCpuClusters = 4; 78 final int numDisplays = 5; 79 final int numOther = 3; 80 81 // Add some energy consumers used by BatteryExternalStatsWorker. 82 final IntArray tempAllIds = new IntArray(); 83 84 final int[] displayIds = new int[numDisplays]; 85 for (int i = 0; i < numDisplays; i++) { 86 displayIds[i] = mPowerStatsInternal.addEnergyConsumer( 87 EnergyConsumerType.DISPLAY, i, "display" + i); 88 tempAllIds.add(displayIds[i]); 89 mPowerStatsInternal.incrementEnergyConsumption(displayIds[i], 12345 + i); 90 } 91 Arrays.sort(displayIds); 92 93 final int wifiId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.WIFI, 0, 94 "wifi"); 95 tempAllIds.add(wifiId); 96 mPowerStatsInternal.incrementEnergyConsumption(wifiId, 23456); 97 98 final int btId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.BLUETOOTH, 0, 99 "bt"); 100 tempAllIds.add(btId); 101 mPowerStatsInternal.incrementEnergyConsumption(btId, 34567); 102 103 final int gnssId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.GNSS, 0, 104 "gnss"); 105 tempAllIds.add(gnssId); 106 mPowerStatsInternal.incrementEnergyConsumption(gnssId, 787878); 107 108 final int cameraId = 109 mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.CAMERA, 0, "camera"); 110 tempAllIds.add(cameraId); 111 mPowerStatsInternal.incrementEnergyConsumption(cameraId, 901234); 112 113 final int mobileRadioId = mPowerStatsInternal.addEnergyConsumer( 114 EnergyConsumerType.MOBILE_RADIO, 0, "mobile_radio"); 115 tempAllIds.add(mobileRadioId); 116 mPowerStatsInternal.incrementEnergyConsumption(mobileRadioId, 62626); 117 118 final int[] cpuClusterIds = new int[numCpuClusters]; 119 for (int i = 0; i < numCpuClusters; i++) { 120 cpuClusterIds[i] = mPowerStatsInternal.addEnergyConsumer( 121 EnergyConsumerType.CPU_CLUSTER, i, "cpu_cluster" + i); 122 tempAllIds.add(cpuClusterIds[i]); 123 mPowerStatsInternal.incrementEnergyConsumption(cpuClusterIds[i], 1111 + i); 124 } 125 Arrays.sort(cpuClusterIds); 126 127 final int[] otherIds = new int[numOther]; 128 for (int i = 0; i < numOther; i++) { 129 otherIds[i] = mPowerStatsInternal.addEnergyConsumer( 130 EnergyConsumerType.OTHER, i, "other" + i); 131 tempAllIds.add(otherIds[i]); 132 mPowerStatsInternal.incrementEnergyConsumption(otherIds[i], 3000 + i); 133 } 134 Arrays.sort(otherIds); 135 136 final int[] allIds = tempAllIds.toArray(); 137 Arrays.sort(allIds); 138 139 // Inform BESW that PowerStatsInternal is ready to query 140 mBatteryExternalStatsWorker.systemServicesReady(); 141 142 final EnergyConsumerResult[] displayResults = 143 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_DISPLAY).getNow(null); 144 // Results should only have the cpu cluster energy consumers 145 final int[] receivedDisplayIds = new int[displayResults.length]; 146 for (int i = 0; i < displayResults.length; i++) { 147 receivedDisplayIds[i] = displayResults[i].id; 148 } 149 Arrays.sort(receivedDisplayIds); 150 assertArrayEquals(displayIds, receivedDisplayIds); 151 152 final EnergyConsumerResult[] wifiResults = 153 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_WIFI).getNow(null); 154 // Results should only have the wifi energy consumer 155 assertEquals(1, wifiResults.length); 156 assertEquals(wifiId, wifiResults[0].id); 157 158 final EnergyConsumerResult[] bluetoothResults = 159 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_BT).getNow(null); 160 // Results should only have the bluetooth energy consumer 161 assertEquals(1, bluetoothResults.length); 162 assertEquals(btId, bluetoothResults[0].id); 163 164 final EnergyConsumerResult[] mobileRadioResults = 165 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_RADIO).getNow(null); 166 // Results should only have the mobile radio energy consumer 167 assertEquals(1, mobileRadioResults.length); 168 assertEquals(mobileRadioId, mobileRadioResults[0].id); 169 170 final EnergyConsumerResult[] cpuResults = 171 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_CPU).getNow(null); 172 // Results should only have the cpu cluster energy consumers 173 final int[] receivedCpuIds = new int[cpuResults.length]; 174 for (int i = 0; i < cpuResults.length; i++) { 175 receivedCpuIds[i] = cpuResults[i].id; 176 } 177 Arrays.sort(receivedCpuIds); 178 assertArrayEquals(cpuClusterIds, receivedCpuIds); 179 180 final EnergyConsumerResult[] cameraResults = 181 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_CAMERA).getNow(null); 182 // Results should only have the camera energy consumer 183 assertEquals(1, cameraResults.length); 184 assertEquals(cameraId, cameraResults[0].id); 185 186 final EnergyConsumerResult[] allResults = 187 mBatteryExternalStatsWorker.getEnergyConsumersLocked(UPDATE_ALL).getNow(null); 188 // All energy consumer results should be available 189 final int[] receivedAllIds = new int[allResults.length]; 190 for (int i = 0; i < allResults.length; i++) { 191 receivedAllIds[i] = allResults[i].id; 192 } 193 Arrays.sort(receivedAllIds); 194 assertArrayEquals(allIds, receivedAllIds); 195 } 196 197 public class TestInjector extends BatteryExternalStatsWorker.Injector { TestInjector(Context context)198 public TestInjector(Context context) { 199 super(context); 200 } 201 getSystemService(Class<T> serviceClass)202 public <T> T getSystemService(Class<T> serviceClass) { 203 return null; 204 } 205 getLocalService(Class<T> serviceClass)206 public <T> T getLocalService(Class<T> serviceClass) { 207 if (serviceClass == PowerStatsInternal.class) { 208 return (T) mPowerStatsInternal; 209 } 210 return null; 211 } 212 } 213 214 public class TestBatteryStatsImpl extends BatteryStatsImpl { TestBatteryStatsImpl(Context context)215 public TestBatteryStatsImpl(Context context) { 216 mPowerProfile = new PowerProfile(context, true /* forTest */); 217 initTimersAndCounters(); 218 } 219 } 220 221 public class TestPowerStatsInternal extends PowerStatsInternal { 222 private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray(); 223 private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray(); 224 private final int mTimeSinceBoot = 0; 225 226 @Override getEnergyConsumerInfo()227 public EnergyConsumer[] getEnergyConsumerInfo() { 228 final int size = mEnergyConsumers.size(); 229 final EnergyConsumer[] consumers = new EnergyConsumer[size]; 230 for (int i = 0; i < size; i++) { 231 consumers[i] = mEnergyConsumers.valueAt(i); 232 } 233 return consumers; 234 } 235 236 @Override getEnergyConsumedAsync( int[] energyConsumerIds)237 public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync( 238 int[] energyConsumerIds) { 239 final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture(); 240 final EnergyConsumerResult[] results; 241 final int length = energyConsumerIds.length; 242 if (length == 0) { 243 final int size = mEnergyConsumerResults.size(); 244 results = new EnergyConsumerResult[size]; 245 for (int i = 0; i < size; i++) { 246 results[i] = mEnergyConsumerResults.valueAt(i); 247 } 248 } else { 249 results = new EnergyConsumerResult[length]; 250 for (int i = 0; i < length; i++) { 251 results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]); 252 } 253 } 254 future.complete(results); 255 return future; 256 } 257 258 @Override getPowerEntityInfo()259 public PowerEntity[] getPowerEntityInfo() { 260 return new PowerEntity[0]; 261 } 262 263 @Override getStateResidencyAsync( int[] powerEntityIds)264 public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync( 265 int[] powerEntityIds) { 266 return new CompletableFuture<>(); 267 } 268 269 @Override getEnergyMeterInfo()270 public Channel[] getEnergyMeterInfo() { 271 return new Channel[0]; 272 } 273 274 @Override readEnergyMeterAsync( int[] channelIds)275 public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync( 276 int[] channelIds) { 277 return new CompletableFuture<>(); 278 } 279 280 /** 281 * Util method to add a new EnergyConsumer for testing 282 * 283 * @return the EnergyConsumer id of the new EnergyConsumer 284 */ addEnergyConsumer(@nergyConsumerType byte type, int ordinal, String name)285 public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) { 286 final EnergyConsumer consumer = new EnergyConsumer(); 287 final int id = getNextAvailableId(); 288 consumer.id = id; 289 consumer.type = type; 290 consumer.ordinal = ordinal; 291 consumer.name = name; 292 mEnergyConsumers.put(id, consumer); 293 294 final EnergyConsumerResult result = new EnergyConsumerResult(); 295 result.id = id; 296 result.timestampMs = mTimeSinceBoot; 297 result.energyUWs = 0; 298 mEnergyConsumerResults.put(id, result); 299 return id; 300 } 301 incrementEnergyConsumption(int id, long energyUWs)302 public void incrementEnergyConsumption(int id, long energyUWs) { 303 EnergyConsumerResult result = mEnergyConsumerResults.get(id, null); 304 assertNotNull(result); 305 result.energyUWs += energyUWs; 306 } 307 getNextAvailableId()308 private int getNextAvailableId() { 309 final int size = mEnergyConsumers.size(); 310 // Just return the first index that does not match the key (aka the EnergyConsumer id) 311 for (int i = size - 1; i >= 0; i--) { 312 if (mEnergyConsumers.keyAt(i) == i) return i + 1; 313 } 314 // Otherwise return the lowest id 315 return 0; 316 } 317 } 318 } 319