1 /* 2 * Copyright (C) 2020 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.frameworks.core.batterystatsviewer; 18 19 import android.content.Context; 20 import android.os.BatteryConsumer; 21 import android.os.BatteryUsageStats; 22 import android.os.UidBatteryConsumer; 23 import android.os.UserHandle; 24 import android.util.DebugUtils; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 29 public class BatteryConsumerData { 30 31 public static final String UID_BATTERY_CONSUMER_ID_PREFIX = "APP|"; 32 public static final String AGGREGATE_BATTERY_CONSUMER_ID = "SYS|"; 33 34 enum EntryType { 35 UID_TOTAL_POWER, 36 UID_POWER_PROFILE, 37 UID_POWER_PROFILE_PROCESS_STATE, 38 UID_POWER_ENERGY_CONSUMPTION, 39 UID_POWER_ENERGY_PROCESS_STATE, 40 UID_POWER_CUSTOM, 41 UID_DURATION, 42 DEVICE_TOTAL_POWER, 43 DEVICE_POWER_MODELED, 44 DEVICE_POWER_ENERGY_CONSUMPTION, 45 DEVICE_POWER_CUSTOM, 46 DEVICE_DURATION, 47 } 48 49 enum ConsumerType { 50 UID_BATTERY_CONSUMER, 51 DEVICE_POWER_COMPONENT, 52 } 53 54 public static class Entry { 55 public EntryType entryType; 56 public String title; 57 public double value1; 58 public double value2; 59 } 60 61 private BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo; 62 private final List<Entry> mEntries = new ArrayList<>(); 63 BatteryConsumerData(Context context, List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId)64 public BatteryConsumerData(Context context, 65 List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId) { 66 switch (getConsumerType(batteryConsumerId)) { 67 case UID_BATTERY_CONSUMER: 68 populateForUidBatteryConsumer(context, batteryUsageStatsList, batteryConsumerId); 69 break; 70 case DEVICE_POWER_COMPONENT: 71 populateForAggregateBatteryConsumer(context, batteryUsageStatsList); 72 break; 73 } 74 } 75 populateForUidBatteryConsumer( Context context, List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId)76 private void populateForUidBatteryConsumer( 77 Context context, List<BatteryUsageStats> batteryUsageStatsList, 78 String batteryConsumerId) { 79 BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0); 80 BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1); 81 BatteryConsumer requestedBatteryConsumer = getRequestedBatteryConsumer(batteryUsageStats, 82 batteryConsumerId); 83 BatteryConsumer requestedModeledBatteryConsumer = getRequestedBatteryConsumer( 84 modeledBatteryUsageStats, batteryConsumerId); 85 86 if (requestedBatteryConsumer == null || requestedModeledBatteryConsumer == null) { 87 mBatteryConsumerInfo = null; 88 return; 89 } 90 91 mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo( 92 batteryUsageStats, batteryConsumerId, context.getPackageManager()); 93 94 double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT]; 95 double[] totalModeledPowerByComponentMah = 96 new double[BatteryConsumer.POWER_COMPONENT_COUNT]; 97 long[] totalDurationByComponentMs = new long[BatteryConsumer.POWER_COMPONENT_COUNT]; 98 final int customComponentCount = 99 requestedBatteryConsumer.getCustomPowerComponentCount(); 100 double[] totalCustomPowerByComponentMah = new double[customComponentCount]; 101 102 computeTotalPower(batteryUsageStats, totalPowerByComponentMah); 103 computeTotalPower(modeledBatteryUsageStats, totalModeledPowerByComponentMah); 104 computeTotalPowerForCustomComponent(batteryUsageStats, totalCustomPowerByComponentMah); 105 computeTotalDuration(batteryUsageStats, totalDurationByComponentMs); 106 107 if (isPowerProfileModelsOnly(requestedBatteryConsumer)) { 108 addEntry("Consumed", EntryType.UID_TOTAL_POWER, 109 requestedBatteryConsumer.getConsumedPower(), 110 batteryUsageStats.getAggregateBatteryConsumer( 111 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 112 .getConsumedPower()); 113 } else { 114 addEntry("Consumed (PowerStats)", EntryType.UID_TOTAL_POWER, 115 requestedBatteryConsumer.getConsumedPower(), 116 batteryUsageStats.getAggregateBatteryConsumer( 117 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 118 .getConsumedPower()); 119 addEntry("Consumed (PowerProfile)", EntryType.UID_TOTAL_POWER, 120 requestedModeledBatteryConsumer.getConsumedPower(), 121 modeledBatteryUsageStats.getAggregateBatteryConsumer( 122 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 123 .getConsumedPower()); 124 } 125 126 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 127 final String metricTitle = getPowerMetricTitle(component); 128 final int powerModel = requestedBatteryConsumer.getPowerModel(component); 129 if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE 130 || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) { 131 addEntry(metricTitle, EntryType.UID_POWER_PROFILE, 132 requestedBatteryConsumer.getConsumedPower(component), 133 totalPowerByComponentMah[component]); 134 addProcessStateEntries(metricTitle, EntryType.UID_POWER_PROFILE_PROCESS_STATE, 135 requestedBatteryConsumer, component); 136 } else { 137 addEntry(metricTitle + " (PowerStats)", EntryType.UID_POWER_ENERGY_CONSUMPTION, 138 requestedBatteryConsumer.getConsumedPower(component), 139 totalPowerByComponentMah[component]); 140 addProcessStateEntries(metricTitle, EntryType.UID_POWER_ENERGY_PROCESS_STATE, 141 requestedBatteryConsumer, component); 142 addEntry(metricTitle + " (PowerProfile)", EntryType.UID_POWER_PROFILE, 143 requestedModeledBatteryConsumer.getConsumedPower(component), 144 totalModeledPowerByComponentMah[component]); 145 addProcessStateEntries(metricTitle, EntryType.UID_POWER_PROFILE_PROCESS_STATE, 146 requestedModeledBatteryConsumer, component); 147 } 148 } 149 150 for (int component = 0; component < customComponentCount; component++) { 151 final String name = requestedBatteryConsumer.getCustomPowerComponentName( 152 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component); 153 addEntry(name + " (PowerStats)", EntryType.UID_POWER_CUSTOM, 154 requestedBatteryConsumer.getConsumedPowerForCustomComponent( 155 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component), 156 totalCustomPowerByComponentMah[component] 157 ); 158 } 159 160 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 161 final String metricTitle = getTimeMetricTitle(component); 162 addEntry(metricTitle, EntryType.UID_DURATION, 163 requestedBatteryConsumer.getUsageDurationMillis(component), 164 totalDurationByComponentMs[component] 165 ); 166 } 167 168 mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats, 169 batteryConsumerId, context.getPackageManager()); 170 } 171 addProcessStateEntries(String metricTitle, EntryType entryType, BatteryConsumer batteryConsumer, int component)172 private void addProcessStateEntries(String metricTitle, EntryType entryType, 173 BatteryConsumer batteryConsumer, int component) { 174 final BatteryConsumer.Key[] keys = batteryConsumer.getKeys(component); 175 if (keys == null || keys.length <= 1) { 176 return; 177 } 178 179 for (BatteryConsumer.Key key : keys) { 180 String label; 181 switch (key.processState) { 182 case BatteryConsumer.PROCESS_STATE_FOREGROUND: 183 label = "foreground"; 184 break; 185 case BatteryConsumer.PROCESS_STATE_BACKGROUND: 186 label = "background"; 187 break; 188 case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE: 189 label = "FGS"; 190 break; 191 case BatteryConsumer.PROCESS_STATE_CACHED: 192 label = "cached"; 193 break; 194 default: 195 continue; 196 } 197 addEntry(metricTitle + " \u2022 " + label, entryType, 198 batteryConsumer.getConsumedPower(key), 0); 199 } 200 } 201 populateForAggregateBatteryConsumer(Context context, List<BatteryUsageStats> batteryUsageStatsList)202 private void populateForAggregateBatteryConsumer(Context context, 203 List<BatteryUsageStats> batteryUsageStatsList) { 204 BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0); 205 BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1); 206 207 final BatteryConsumer deviceBatteryConsumer = 208 batteryUsageStats.getAggregateBatteryConsumer( 209 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 210 BatteryConsumer appsBatteryConsumer = 211 batteryUsageStats.getAggregateBatteryConsumer( 212 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); 213 214 BatteryConsumer modeledDeviceBatteryConsumer = 215 modeledBatteryUsageStats.getAggregateBatteryConsumer( 216 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 217 BatteryConsumer modeledAppsBatteryConsumer = 218 modeledBatteryUsageStats.getAggregateBatteryConsumer( 219 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS); 220 221 if (isPowerProfileModelsOnly(deviceBatteryConsumer)) { 222 addEntry("Consumed", EntryType.DEVICE_TOTAL_POWER, 223 deviceBatteryConsumer.getConsumedPower(), 224 appsBatteryConsumer.getConsumedPower()); 225 } else { 226 addEntry("Consumed (PowerStats)", EntryType.DEVICE_TOTAL_POWER, 227 deviceBatteryConsumer.getConsumedPower(), 228 appsBatteryConsumer.getConsumedPower()); 229 addEntry("Consumed (PowerProfile)", EntryType.DEVICE_TOTAL_POWER, 230 modeledDeviceBatteryConsumer.getConsumedPower(), 231 modeledAppsBatteryConsumer.getConsumedPower()); 232 } 233 234 mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats, 235 AGGREGATE_BATTERY_CONSUMER_ID, context.getPackageManager()); 236 237 238 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 239 final String metricTitle = getPowerMetricTitle(component); 240 final int powerModel = deviceBatteryConsumer.getPowerModel(component); 241 if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE 242 || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) { 243 addEntry(metricTitle, EntryType.DEVICE_POWER_MODELED, 244 deviceBatteryConsumer.getConsumedPower(component), 245 appsBatteryConsumer.getConsumedPower(component)); 246 } else { 247 addEntry(metricTitle + " (PowerStats)", EntryType.DEVICE_POWER_ENERGY_CONSUMPTION, 248 deviceBatteryConsumer.getConsumedPower(component), 249 appsBatteryConsumer.getConsumedPower(component)); 250 addEntry(metricTitle + " (PowerProfile)", EntryType.DEVICE_POWER_MODELED, 251 modeledDeviceBatteryConsumer.getConsumedPower(component), 252 modeledAppsBatteryConsumer.getConsumedPower(component)); 253 } 254 } 255 256 final int customComponentCount = 257 deviceBatteryConsumer.getCustomPowerComponentCount(); 258 for (int component = 0; component < customComponentCount; component++) { 259 final String name = deviceBatteryConsumer.getCustomPowerComponentName( 260 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component); 261 addEntry(name + " (PowerStats)", EntryType.DEVICE_POWER_CUSTOM, 262 deviceBatteryConsumer.getConsumedPowerForCustomComponent( 263 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component), 264 appsBatteryConsumer.getConsumedPowerForCustomComponent( 265 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component)); 266 } 267 268 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 269 final String metricTitle = getTimeMetricTitle(component); 270 addEntry(metricTitle, EntryType.DEVICE_DURATION, 271 deviceBatteryConsumer.getUsageDurationMillis(component), 0); 272 } 273 } 274 isPowerProfileModelsOnly(BatteryConsumer batteryConsumer)275 private boolean isPowerProfileModelsOnly(BatteryConsumer batteryConsumer) { 276 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 277 final int powerModel = batteryConsumer.getPowerModel(component); 278 if (powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE 279 && powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED) { 280 return false; 281 } 282 } 283 return true; 284 } 285 getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats, String batteryConsumerId)286 private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats, 287 String batteryConsumerId) { 288 for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { 289 if (batteryConsumerId(consumer).equals(batteryConsumerId)) { 290 return consumer; 291 } 292 } 293 294 return null; 295 } 296 getPowerMetricTitle(int componentId)297 static String getPowerMetricTitle(int componentId) { 298 return getPowerComponentName(componentId); 299 } 300 getTimeMetricTitle(int componentId)301 static String getTimeMetricTitle(int componentId) { 302 return getPowerComponentName(componentId) + " time"; 303 } 304 getPowerComponentName(int componentId)305 private static String getPowerComponentName(int componentId) { 306 switch (componentId) { 307 case BatteryConsumer.POWER_COMPONENT_CPU: 308 return "CPU"; 309 case BatteryConsumer.POWER_COMPONENT_GNSS: 310 return "GNSS"; 311 case BatteryConsumer.POWER_COMPONENT_WIFI: 312 return "Wi-Fi"; 313 default: 314 String componentName = DebugUtils.constantToString(BatteryConsumer.class, 315 "POWER_COMPONENT_", componentId); 316 return componentName.charAt(0) + componentName.substring(1).toLowerCase() 317 .replace('_', ' '); 318 } 319 } 320 computeTotalPower(BatteryUsageStats batteryUsageStats, double[] powerByComponentMah)321 private void computeTotalPower(BatteryUsageStats batteryUsageStats, 322 double[] powerByComponentMah) { 323 final BatteryConsumer consumer = 324 batteryUsageStats.getAggregateBatteryConsumer( 325 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 326 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) { 327 powerByComponentMah[component] += consumer.getConsumedPower(component); 328 } 329 } 330 computeTotalPowerForCustomComponent( BatteryUsageStats batteryUsageStats, double[] powerByComponentMah)331 private void computeTotalPowerForCustomComponent( 332 BatteryUsageStats batteryUsageStats, double[] powerByComponentMah) { 333 final BatteryConsumer consumer = 334 batteryUsageStats.getAggregateBatteryConsumer( 335 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); 336 final int customComponentCount = consumer.getCustomPowerComponentCount(); 337 for (int component = 0; 338 component < Math.min(customComponentCount, powerByComponentMah.length); 339 component++) { 340 powerByComponentMah[component] += consumer.getConsumedPowerForCustomComponent( 341 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component); 342 } 343 } 344 computeTotalDuration(BatteryUsageStats batteryUsageStats, long[] durationByComponentMs)345 private void computeTotalDuration(BatteryUsageStats batteryUsageStats, 346 long[] durationByComponentMs) { 347 for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) { 348 for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; 349 component++) { 350 durationByComponentMs[component] += consumer.getUsageDurationMillis(component); 351 } 352 } 353 } 354 addEntry(String title, EntryType entryType, double value1, double value2)355 private void addEntry(String title, EntryType entryType, double value1, double value2) { 356 Entry entry = new Entry(); 357 entry.title = title; 358 entry.entryType = entryType; 359 entry.value1 = value1; 360 entry.value2 = value2; 361 mEntries.add(entry); 362 } 363 getBatteryConsumerInfo()364 public BatteryConsumerInfoHelper.BatteryConsumerInfo getBatteryConsumerInfo() { 365 return mBatteryConsumerInfo; 366 } 367 getEntries()368 public List<Entry> getEntries() { 369 return mEntries; 370 } 371 getConsumerType(String batteryConsumerId)372 public static ConsumerType getConsumerType(String batteryConsumerId) { 373 if (batteryConsumerId.startsWith(UID_BATTERY_CONSUMER_ID_PREFIX)) { 374 return ConsumerType.UID_BATTERY_CONSUMER; 375 } 376 return ConsumerType.DEVICE_POWER_COMPONENT; 377 } 378 batteryConsumerId(UidBatteryConsumer consumer)379 public static String batteryConsumerId(UidBatteryConsumer consumer) { 380 return UID_BATTERY_CONSUMER_ID_PREFIX + UserHandle.getUserId(consumer.getUid()) + "|" 381 + consumer.getUid(); 382 } 383 }