1 /* 2 * Copyright (C) 2023 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.processor; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.BatteryConsumer; 22 23 import java.lang.annotation.Retention; 24 import java.lang.annotation.RetentionPolicy; 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.function.Supplier; 28 29 /** 30 * Configuration that controls how power stats are aggregated. It determines which state changes 31 * are to be considered as essential dimensions ("tracked states") for each power component (CPU, 32 * WiFi, etc). Also, it determines which states are tracked globally and which ones on a per-UID 33 * basis. 34 */ 35 class AggregatedPowerStatsConfig { 36 public static final int STATE_POWER = 0; 37 public static final int STATE_SCREEN = 1; 38 public static final int STATE_PROCESS_STATE = 2; 39 40 @IntDef({ 41 STATE_POWER, 42 STATE_SCREEN, 43 STATE_PROCESS_STATE, 44 }) 45 @Retention(RetentionPolicy.SOURCE) 46 public @interface TrackedState { 47 } 48 49 static final String STATE_NAME_POWER = "pwr"; 50 static final int POWER_STATE_BATTERY = 0; 51 static final int POWER_STATE_OTHER = 1; // Plugged in, or on wireless charger, etc. 52 static final String[] STATE_LABELS_POWER = {"pwr-battery", "pwr-other"}; 53 54 static final String STATE_NAME_SCREEN = "scr"; 55 static final int SCREEN_STATE_ON = 0; 56 static final int SCREEN_STATE_OTHER = 1; // Off, doze etc 57 static final String[] STATE_LABELS_SCREEN = {"scr-on", "scr-other"}; 58 59 static final String STATE_NAME_PROCESS_STATE = "ps"; 60 static final String[] STATE_LABELS_PROCESS_STATE; 61 62 static { 63 String[] procStateLabels = new String[BatteryConsumer.PROCESS_STATE_COUNT]; 64 for (int i = 0; i < BatteryConsumer.PROCESS_STATE_COUNT; i++) { 65 procStateLabels[i] = BatteryConsumer.processStateToString(i); 66 } 67 STATE_LABELS_PROCESS_STATE = procStateLabels; 68 } 69 70 /** 71 * Configuration for a give power component (CPU, WiFi, etc) 72 */ 73 static class PowerComponent { 74 private final int mPowerComponentId; 75 private @TrackedState int[] mTrackedDeviceStates; 76 private @TrackedState int[] mTrackedUidStates; 77 private Supplier<PowerStatsProcessor> mProcessorSupplier; 78 PowerComponent(int powerComponentId)79 PowerComponent(int powerComponentId) { 80 this.mPowerComponentId = powerComponentId; 81 } 82 83 /** 84 * Configures which states should be tracked as separate dimensions for the entire device. 85 */ trackDeviceStates(@rackedState int... states)86 public PowerComponent trackDeviceStates(@TrackedState int... states) { 87 if (mTrackedDeviceStates != null) { 88 throw new IllegalStateException("Component is already configured"); 89 } 90 mTrackedDeviceStates = states; 91 return this; 92 } 93 94 /** 95 * Configures which states should be tracked as separate dimensions on a per-UID basis. 96 */ trackUidStates(@rackedState int... states)97 public PowerComponent trackUidStates(@TrackedState int... states) { 98 if (mTrackedUidStates != null) { 99 throw new IllegalStateException("Component is already configured"); 100 } 101 mTrackedUidStates = states; 102 return this; 103 } 104 105 /** 106 * A PowerStatsProcessor takes an object that should be invoked for every aggregated 107 * stats span before giving the aggregates stats to consumers. The processor can complete 108 * the aggregation process, for example by computing estimated power usage. 109 */ setProcessorSupplier( @onNull Supplier<PowerStatsProcessor> processorSupplier)110 public PowerComponent setProcessorSupplier( 111 @NonNull Supplier<PowerStatsProcessor> processorSupplier) { 112 mProcessorSupplier = processorSupplier; 113 return this; 114 } 115 getPowerComponentId()116 public int getPowerComponentId() { 117 return mPowerComponentId; 118 } 119 getDeviceStateConfig()120 public MultiStateStats.States[] getDeviceStateConfig() { 121 return new MultiStateStats.States[]{ 122 new MultiStateStats.States(STATE_NAME_POWER, 123 isTracked(mTrackedDeviceStates, STATE_POWER), 124 STATE_LABELS_POWER), 125 new MultiStateStats.States(STATE_NAME_SCREEN, 126 isTracked(mTrackedDeviceStates, STATE_SCREEN), 127 STATE_LABELS_SCREEN), 128 }; 129 } 130 getUidStateConfig()131 public MultiStateStats.States[] getUidStateConfig() { 132 return new MultiStateStats.States[]{ 133 new MultiStateStats.States(STATE_NAME_POWER, 134 isTracked(mTrackedUidStates, STATE_POWER), 135 AggregatedPowerStatsConfig.STATE_LABELS_POWER), 136 new MultiStateStats.States(STATE_NAME_SCREEN, 137 isTracked(mTrackedUidStates, STATE_SCREEN), 138 AggregatedPowerStatsConfig.STATE_LABELS_SCREEN), 139 new MultiStateStats.States(STATE_NAME_PROCESS_STATE, 140 isTracked(mTrackedUidStates, STATE_PROCESS_STATE), 141 AggregatedPowerStatsConfig.STATE_LABELS_PROCESS_STATE), 142 }; 143 } 144 145 @NonNull createProcessor()146 PowerStatsProcessor createProcessor() { 147 if (mProcessorSupplier == null) { 148 return NO_OP_PROCESSOR; 149 } 150 return mProcessorSupplier.get(); 151 } 152 isTracked(int[] trackedStates, int state)153 private boolean isTracked(int[] trackedStates, int state) { 154 if (trackedStates == null) { 155 return false; 156 } 157 158 for (int trackedState : trackedStates) { 159 if (trackedState == state) { 160 return true; 161 } 162 } 163 return false; 164 } 165 166 } 167 168 private final List<PowerComponent> mPowerComponents = new ArrayList<>(); 169 private PowerComponent mCustomPowerComponent; 170 private Supplier<PowerStatsProcessor> mCustomPowerStatsProcessorFactory; 171 172 /** 173 * Creates a configuration for the specified power component, which may be one of the 174 * standard power component IDs, e.g. {@link BatteryConsumer#POWER_COMPONENT_CPU}, or 175 * a custom power component. 176 */ trackPowerComponent(@atteryConsumer.PowerComponentId int powerComponentId)177 PowerComponent trackPowerComponent(@BatteryConsumer.PowerComponentId int powerComponentId) { 178 PowerComponent builder = new PowerComponent(powerComponentId); 179 mPowerComponents.add(builder); 180 return builder; 181 } 182 183 /** 184 * Creates a configuration for the specified power component, whose attribution calculation 185 * depends on a different power component. The tracked states will be the same as the 186 * "dependsOn" component's. 187 */ trackPowerComponent(@atteryConsumer.PowerComponentId int powerComponentId, @BatteryConsumer.PowerComponentId int dependsOnPowerComponentId)188 PowerComponent trackPowerComponent(@BatteryConsumer.PowerComponentId int powerComponentId, 189 @BatteryConsumer.PowerComponentId int dependsOnPowerComponentId) { 190 PowerComponent dependsOnPowerComponent = null; 191 for (int i = 0; i < mPowerComponents.size(); i++) { 192 PowerComponent powerComponent = mPowerComponents.get(i); 193 if (powerComponent.getPowerComponentId() == dependsOnPowerComponentId) { 194 dependsOnPowerComponent = powerComponent; 195 break; 196 } 197 } 198 199 if (dependsOnPowerComponent == null) { 200 throw new IllegalArgumentException( 201 "Required component " + dependsOnPowerComponentId + " is not configured"); 202 } 203 204 PowerComponent powerComponent = trackPowerComponent(powerComponentId); 205 powerComponent.mTrackedDeviceStates = dependsOnPowerComponent.mTrackedDeviceStates; 206 powerComponent.mTrackedUidStates = dependsOnPowerComponent.mTrackedUidStates; 207 return powerComponent; 208 } 209 210 /** 211 * Creates a configuration for custom power components, which are yet to be discovered 212 * dynamically through the integration with PowerStatsService. 213 */ trackCustomPowerComponents( Supplier<PowerStatsProcessor> processorFactory)214 PowerComponent trackCustomPowerComponents( 215 Supplier<PowerStatsProcessor> processorFactory) { 216 mCustomPowerStatsProcessorFactory = processorFactory; 217 mCustomPowerComponent = new PowerComponent(BatteryConsumer.POWER_COMPONENT_ANY); 218 return mCustomPowerComponent; 219 } 220 221 /** 222 * Returns configurations for all registered or dynamically discovered power components. 223 */ getPowerComponentsAggregatedStatsConfigs()224 List<PowerComponent> getPowerComponentsAggregatedStatsConfigs() { 225 return mPowerComponents; 226 } 227 228 /** 229 * Creates a configuration for a custom power component discovered dynamically through the 230 * integration with PowerStatsService. 231 */ 232 @Nullable createPowerComponent(int powerComponentId)233 PowerComponent createPowerComponent(int powerComponentId) { 234 if (mCustomPowerComponent == null) { 235 return null; 236 } 237 238 PowerComponent powerComponent = new PowerComponent(powerComponentId); 239 powerComponent.trackDeviceStates(mCustomPowerComponent.mTrackedDeviceStates); 240 powerComponent.trackUidStates(mCustomPowerComponent.mTrackedUidStates); 241 242 if (mCustomPowerStatsProcessorFactory != null) { 243 powerComponent.setProcessorSupplier(mCustomPowerStatsProcessorFactory); 244 } 245 246 return powerComponent; 247 } 248 249 private static final PowerStatsProcessor NO_OP_PROCESSOR = new PowerStatsProcessor() { 250 @Override 251 void finish(PowerComponentAggregatedPowerStats stats, long timestampMs) { 252 } 253 }; 254 } 255