1 /* 2 * Copyright (C) 2025 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 package com.android.server.power.stats; 17 18 import static org.junit.Assert.assertNotNull; 19 20 import android.hardware.power.stats.Channel; 21 import android.hardware.power.stats.EnergyConsumer; 22 import android.hardware.power.stats.EnergyConsumerResult; 23 import android.hardware.power.stats.EnergyConsumerType; 24 import android.hardware.power.stats.EnergyMeasurement; 25 import android.hardware.power.stats.PowerEntity; 26 import android.hardware.power.stats.State; 27 import android.hardware.power.stats.StateResidency; 28 import android.hardware.power.stats.StateResidencyResult; 29 import android.power.PowerStatsInternal; 30 import android.util.SparseArray; 31 32 import java.util.Arrays; 33 import java.util.concurrent.CompletableFuture; 34 35 class MockPowerStatsInternal extends PowerStatsInternal { 36 private final SparseArray<PowerEntity> mPowerEntities = new SparseArray<>(); 37 private final SparseArray<StateResidencyResult> mStateResidencyResults = new SparseArray<>(); 38 private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray<>(); 39 private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray<>(); 40 private final int mTimeSinceBoot = 0; 41 42 @Override getEnergyConsumerInfo()43 public EnergyConsumer[] getEnergyConsumerInfo() { 44 final int size = mEnergyConsumers.size(); 45 final EnergyConsumer[] consumers = new EnergyConsumer[size]; 46 for (int i = 0; i < size; i++) { 47 consumers[i] = mEnergyConsumers.valueAt(i); 48 } 49 return consumers; 50 } 51 52 @Override getEnergyConsumedAsync( int[] energyConsumerIds)53 public CompletableFuture<EnergyConsumerResult[]> getEnergyConsumedAsync( 54 int[] energyConsumerIds) { 55 final CompletableFuture<EnergyConsumerResult[]> future = new CompletableFuture(); 56 final EnergyConsumerResult[] results; 57 final int length = energyConsumerIds.length; 58 if (length == 0) { 59 final int size = mEnergyConsumerResults.size(); 60 results = new EnergyConsumerResult[size]; 61 for (int i = 0; i < size; i++) { 62 results[i] = mEnergyConsumerResults.valueAt(i); 63 } 64 } else { 65 results = new EnergyConsumerResult[length]; 66 for (int i = 0; i < length; i++) { 67 results[i] = mEnergyConsumerResults.get(energyConsumerIds[i]); 68 } 69 } 70 future.complete(results); 71 return future; 72 } 73 74 @Override getPowerEntityInfo()75 public PowerEntity[] getPowerEntityInfo() { 76 final int size = mPowerEntities.size(); 77 final PowerEntity[] entities = new PowerEntity[size]; 78 for (int i = 0; i < size; i++) { 79 entities[i] = mPowerEntities.valueAt(i); 80 } 81 return entities; 82 } 83 84 @Override getStateResidencyAsync( int[] powerEntityIds)85 public CompletableFuture<StateResidencyResult[]> getStateResidencyAsync( 86 int[] powerEntityIds) { 87 final CompletableFuture<StateResidencyResult[]> future = new CompletableFuture<>(); 88 final StateResidencyResult[] results; 89 final int length = powerEntityIds.length; 90 if (length == 0) { 91 final int size = mStateResidencyResults.size(); 92 results = new StateResidencyResult[size]; 93 for (int i = 0; i < size; i++) { 94 results[i] = mStateResidencyResults.valueAt(i); 95 } 96 } else { 97 results = new StateResidencyResult[length]; 98 for (int i = 0; i < length; i++) { 99 results[i] = mStateResidencyResults.get(powerEntityIds[i]); 100 } 101 } 102 future.complete(results); 103 return future; 104 } 105 106 @Override getEnergyMeterInfo()107 public Channel[] getEnergyMeterInfo() { 108 return new Channel[0]; 109 } 110 111 @Override readEnergyMeterAsync( int[] channelIds)112 public CompletableFuture<EnergyMeasurement[]> readEnergyMeterAsync( 113 int[] channelIds) { 114 return new CompletableFuture<>(); 115 } 116 reset()117 public void reset() { 118 mStateResidencyResults.clear(); 119 mEnergyConsumerResults.clear(); 120 } 121 addPowerEntity(int id, String name)122 public void addPowerEntity(int id, String name) { 123 PowerEntity powerEntity = new PowerEntity(); 124 powerEntity.id = id; 125 powerEntity.name = name; 126 powerEntity.states = new State[0]; 127 mPowerEntities.put(id, powerEntity); 128 } 129 addPowerEntityState(int powerEntityId, int stateId, String name)130 public void addPowerEntityState(int powerEntityId, int stateId, String name) { 131 State state = new State(); 132 state.id = stateId; 133 state.name = name; 134 135 PowerEntity powerEntity = mPowerEntities.get(powerEntityId); 136 powerEntity.states = Arrays.copyOf(powerEntity.states, powerEntity.states.length + 1); 137 powerEntity.states[powerEntity.states.length - 1] = state; 138 } 139 addStateResidencyResult(int entityId, int stateId, long totalTimeInStateMs, long totalStateEntryCount, long lastEntryTimestampMs)140 public void addStateResidencyResult(int entityId, int stateId, long totalTimeInStateMs, 141 long totalStateEntryCount, long lastEntryTimestampMs) { 142 StateResidencyResult result = mStateResidencyResults.get(entityId); 143 if (result == null) { 144 result = new StateResidencyResult(); 145 result.id = entityId; 146 result.stateResidencyData = new StateResidency[0]; 147 mStateResidencyResults.put(entityId, result); 148 } 149 150 StateResidency residency = new StateResidency(); 151 residency.id = stateId; 152 residency.totalTimeInStateMs = totalTimeInStateMs; 153 residency.totalStateEntryCount = totalStateEntryCount; 154 residency.lastEntryTimestampMs = lastEntryTimestampMs; 155 156 result.stateResidencyData = Arrays.copyOf(result.stateResidencyData, 157 result.stateResidencyData.length + 1); 158 result.stateResidencyData[result.stateResidencyData.length - 1] = residency; 159 } 160 161 /** 162 * Util method to add a new EnergyConsumer for testing 163 * 164 * @return the EnergyConsumer id of the new EnergyConsumer 165 */ addEnergyConsumer(@nergyConsumerType byte type, int ordinal, String name)166 public int addEnergyConsumer(@EnergyConsumerType byte type, int ordinal, String name) { 167 final EnergyConsumer consumer = new EnergyConsumer(); 168 final int id = getNextAvailableId(); 169 consumer.id = id; 170 consumer.type = type; 171 consumer.ordinal = ordinal; 172 consumer.name = name; 173 mEnergyConsumers.put(id, consumer); 174 175 final EnergyConsumerResult result = new EnergyConsumerResult(); 176 result.id = id; 177 result.timestampMs = mTimeSinceBoot; 178 result.energyUWs = 0; 179 mEnergyConsumerResults.put(id, result); 180 return id; 181 } 182 incrementEnergyConsumption(int id, long energyUWs)183 public void incrementEnergyConsumption(int id, long energyUWs) { 184 EnergyConsumerResult result = mEnergyConsumerResults.get(id, null); 185 assertNotNull(result); 186 result.energyUWs += energyUWs; 187 } 188 getNextAvailableId()189 private int getNextAvailableId() { 190 final int size = mEnergyConsumers.size(); 191 // Just return the first index that does not match the key (aka the EnergyConsumer id) 192 for (int i = size - 1; i >= 0; i--) { 193 if (mEnergyConsumers.keyAt(i) == i) return i + 1; 194 } 195 // Otherwise return the lowest id 196 return 0; 197 } 198 } 199