1 /* 2 * Copyright (C) 2009 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.internal.os; 18 19 20 import android.annotation.LongDef; 21 import android.annotation.StringDef; 22 import android.annotation.XmlRes; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.content.Context; 25 import android.content.res.Resources; 26 import android.content.res.XmlResourceParser; 27 import android.util.IndentingPrintWriter; 28 import android.util.Slog; 29 import android.util.proto.ProtoOutputStream; 30 31 import com.android.internal.annotations.GuardedBy; 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.internal.power.ModemPowerProfile; 34 import com.android.internal.util.XmlUtils; 35 36 import org.xmlpull.v1.XmlPullParser; 37 import org.xmlpull.v1.XmlPullParserException; 38 39 import java.io.IOException; 40 import java.io.PrintWriter; 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.HashMap; 46 47 /** 48 * Reports power consumption values for various device activities. Reads values from an XML file. 49 * Customize the XML file for different devices. 50 * [hidden] 51 */ 52 public class PowerProfile { 53 54 public static final String TAG = "PowerProfile"; 55 56 /* 57 * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. 58 * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should 59 * be zero on devices that can go into full CPU power collapse even when a wake 60 * lock is held. Otherwise, this is the power consumption in addition to 61 * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. 62 * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters 63 * and cores. 64 * 65 * CPU Power Equation (assume two clusters): 66 * Total power = POWER_CPU_SUSPEND (always added) 67 * + POWER_CPU_IDLE (skip this and below if in power collapse mode) 68 * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock 69 * is held) 70 * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running) 71 * + core_power.cluster0 * num running cores in cluster 0 72 * + core_power.cluster1 * num running cores in cluster 1 73 */ 74 public static final String POWER_CPU_SUSPEND = "cpu.suspend"; 75 @UnsupportedAppUsage 76 public static final String POWER_CPU_IDLE = "cpu.idle"; 77 @UnsupportedAppUsage 78 public static final String POWER_CPU_ACTIVE = "cpu.active"; 79 80 /** 81 * Power consumption when WiFi driver is scanning for networks. 82 */ 83 @UnsupportedAppUsage 84 public static final String POWER_WIFI_SCAN = "wifi.scan"; 85 86 /** 87 * Power consumption when WiFi driver is on. 88 */ 89 @UnsupportedAppUsage 90 public static final String POWER_WIFI_ON = "wifi.on"; 91 92 /** 93 * Power consumption when WiFi driver is transmitting/receiving. 94 */ 95 @UnsupportedAppUsage 96 public static final String POWER_WIFI_ACTIVE = "wifi.active"; 97 98 // 99 // Updated power constants. These are not estimated, they are real world 100 // currents and voltages for the underlying bluetooth and wifi controllers. 101 // 102 public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; 103 public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; 104 public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; 105 public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels"; 106 public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage"; 107 108 public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle"; 109 public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx"; 110 public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx"; 111 public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE = 112 "bluetooth.controller.voltage"; 113 114 public static final String POWER_MODEM_CONTROLLER_SLEEP = "modem.controller.sleep"; 115 public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle"; 116 public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx"; 117 public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx"; 118 public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE = 119 "modem.controller.voltage"; 120 121 /** 122 * Power consumption when GPS is on. 123 */ 124 @UnsupportedAppUsage 125 public static final String POWER_GPS_ON = "gps.on"; 126 127 /** 128 * GPS power parameters based on signal quality 129 */ 130 public static final String POWER_GPS_SIGNAL_QUALITY_BASED = "gps.signalqualitybased"; 131 public static final String POWER_GPS_OPERATING_VOLTAGE = "gps.voltage"; 132 133 /** 134 * Power consumption when Bluetooth driver is on. 135 * 136 * @deprecated 137 */ 138 @Deprecated 139 @UnsupportedAppUsage 140 public static final String POWER_BLUETOOTH_ON = "bluetooth.on"; 141 142 /** 143 * Power consumption when Bluetooth driver is transmitting/receiving. 144 * 145 * @deprecated 146 */ 147 @Deprecated 148 public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active"; 149 150 /** 151 * Power consumption when Bluetooth driver gets an AT command. 152 * 153 * @deprecated 154 */ 155 @Deprecated 156 @UnsupportedAppUsage 157 public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; 158 159 /** 160 * Power consumption when screen is in doze/ambient/always-on mode, including backlight power. 161 * 162 * @deprecated Use {@link #POWER_GROUP_DISPLAY_AMBIENT} instead. 163 */ 164 @Deprecated 165 public static final String POWER_AMBIENT_DISPLAY = "ambient.on"; 166 167 /** 168 * Power consumption when screen is on, not including the backlight power. 169 * 170 * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_ON} instead. 171 */ 172 @Deprecated 173 @UnsupportedAppUsage 174 public static final String POWER_SCREEN_ON = "screen.on"; 175 176 /** 177 * Power consumption when cell radio is on but not on a call. 178 */ 179 @UnsupportedAppUsage 180 public static final String POWER_RADIO_ON = "radio.on"; 181 182 /** 183 * Power consumption when cell radio is hunting for a signal. 184 */ 185 @UnsupportedAppUsage 186 public static final String POWER_RADIO_SCANNING = "radio.scanning"; 187 188 /** 189 * Power consumption when talking on the phone. 190 */ 191 @UnsupportedAppUsage 192 public static final String POWER_RADIO_ACTIVE = "radio.active"; 193 194 /** 195 * Power consumption at full backlight brightness. If the backlight is at 196 * 50% brightness, then this should be multiplied by 0.5 197 * 198 * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_FULL} instead. 199 */ 200 @Deprecated 201 @UnsupportedAppUsage 202 public static final String POWER_SCREEN_FULL = "screen.full"; 203 204 /** 205 * Power consumed by the audio hardware when playing back audio content. This is in addition 206 * to the CPU power, probably due to a DSP and / or amplifier. 207 */ 208 public static final String POWER_AUDIO = "audio"; 209 210 /** 211 * Power consumed by any media hardware when playing back video content. This is in addition 212 * to the CPU power, probably due to a DSP. 213 */ 214 public static final String POWER_VIDEO = "video"; 215 216 /** 217 * Average power consumption when camera flashlight is on. 218 */ 219 public static final String POWER_FLASHLIGHT = "camera.flashlight"; 220 221 /** 222 * Power consumption when DDR is being used. 223 */ 224 public static final String POWER_MEMORY = "memory.bandwidths"; 225 226 /** 227 * Average power consumption when the camera is on over all standard use cases. 228 * 229 * TODO: Add more fine-grained camera power metrics. 230 */ 231 public static final String POWER_CAMERA = "camera.avg"; 232 233 /** 234 * Power consumed by wif batched scaning. Broken down into bins by 235 * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels 236 * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)! 237 */ 238 public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan"; 239 240 /** 241 * Battery capacity in milliAmpHour (mAh). 242 */ 243 public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; 244 245 /** 246 * Power consumption when a screen is in doze/ambient/always-on mode, including backlight power. 247 */ 248 public static final String POWER_GROUP_DISPLAY_AMBIENT = "ambient.on.display"; 249 250 /** 251 * Power consumption when a screen is on, not including the backlight power. 252 */ 253 public static final String POWER_GROUP_DISPLAY_SCREEN_ON = "screen.on.display"; 254 255 /** 256 * Power consumption of a screen at full backlight brightness. 257 */ 258 public static final String POWER_GROUP_DISPLAY_SCREEN_FULL = "screen.full.display"; 259 260 @StringDef(prefix = { "POWER_GROUP_" }, value = { 261 POWER_GROUP_DISPLAY_AMBIENT, 262 POWER_GROUP_DISPLAY_SCREEN_ON, 263 POWER_GROUP_DISPLAY_SCREEN_FULL, 264 }) 265 @Retention(RetentionPolicy.SOURCE) 266 public @interface PowerGroup {} 267 268 /** 269 * Constants for generating a 64bit power constant key. 270 * 271 * The bitfields of a key describes what its corresponding power constant represents: 272 * [63:40] - RESERVED 273 * [39:32] - {@link Subsystem} (max count = 16). 274 * [31:0] - per Subsystem fields, see {@link ModemPowerProfile}. 275 * 276 */ 277 private static final long SUBSYSTEM_MASK = 0xF_0000_0000L; 278 /** 279 * Power constant not associated with a subsystem. 280 */ 281 public static final long SUBSYSTEM_NONE = 0x0_0000_0000L; 282 /** 283 * Modem power constant. 284 */ 285 public static final long SUBSYSTEM_MODEM = 0x1_0000_0000L; 286 287 @LongDef(prefix = { "SUBSYSTEM_" }, value = { 288 SUBSYSTEM_NONE, 289 SUBSYSTEM_MODEM, 290 }) 291 @Retention(RetentionPolicy.SOURCE) 292 public @interface Subsystem {} 293 294 private static final long SUBSYSTEM_FIELDS_MASK = 0xFFFF_FFFF; 295 296 /** 297 * A map from Power Use Item to its power consumption. 298 */ 299 static final HashMap<String, Double> sPowerItemMap = new HashMap<>(); 300 /** 301 * A map from Power Use Item to an array of its power consumption 302 * (for items with variable power e.g. CPU). 303 */ 304 static final HashMap<String, Double[]> sPowerArrayMap = new HashMap<>(); 305 306 static final ModemPowerProfile sModemPowerProfile = new ModemPowerProfile(); 307 308 private static final String TAG_DEVICE = "device"; 309 private static final String TAG_ITEM = "item"; 310 private static final String TAG_ARRAY = "array"; 311 private static final String TAG_ARRAYITEM = "value"; 312 private static final String ATTR_NAME = "name"; 313 314 private static final String TAG_MODEM = "modem"; 315 316 private static final Object sLock = new Object(); 317 318 @VisibleForTesting 319 @UnsupportedAppUsage PowerProfile(Context context)320 public PowerProfile(Context context) { 321 this(context, false); 322 } 323 324 /** 325 * For PowerProfileTest 326 */ 327 @VisibleForTesting PowerProfile(Context context, boolean forTest)328 public PowerProfile(Context context, boolean forTest) { 329 // Read the XML file for the given profile (normally only one per device) 330 synchronized (sLock) { 331 final int xmlId = forTest ? com.android.internal.R.xml.power_profile_test 332 : com.android.internal.R.xml.power_profile; 333 initLocked(context, xmlId); 334 } 335 } 336 337 /** 338 * Reinitialize the PowerProfile with the provided XML. 339 * WARNING: use only for testing! 340 */ 341 @VisibleForTesting forceInitForTesting(Context context, @XmlRes int xmlId)342 public void forceInitForTesting(Context context, @XmlRes int xmlId) { 343 synchronized (sLock) { 344 sPowerItemMap.clear(); 345 sPowerArrayMap.clear(); 346 sModemPowerProfile.clear(); 347 initLocked(context, xmlId); 348 } 349 350 } 351 352 @GuardedBy("sLock") initLocked(Context context, @XmlRes int xmlId)353 private void initLocked(Context context, @XmlRes int xmlId) { 354 if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { 355 readPowerValuesFromXml(context, xmlId); 356 } 357 initCpuClusters(); 358 initDisplays(); 359 initModem(); 360 } 361 readPowerValuesFromXml(Context context, @XmlRes int xmlId)362 private void readPowerValuesFromXml(Context context, @XmlRes int xmlId) { 363 final Resources resources = context.getResources(); 364 XmlResourceParser parser = resources.getXml(xmlId); 365 boolean parsingArray = false; 366 ArrayList<Double> array = new ArrayList<>(); 367 String arrayName = null; 368 369 try { 370 XmlUtils.beginDocument(parser, TAG_DEVICE); 371 372 while (true) { 373 XmlUtils.nextElement(parser); 374 375 String element = parser.getName(); 376 if (element == null) break; 377 378 if (parsingArray && !element.equals(TAG_ARRAYITEM)) { 379 // Finish array 380 sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()])); 381 parsingArray = false; 382 } 383 if (element.equals(TAG_ARRAY)) { 384 parsingArray = true; 385 array.clear(); 386 arrayName = parser.getAttributeValue(null, ATTR_NAME); 387 } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) { 388 String name = null; 389 if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME); 390 if (parser.next() == XmlPullParser.TEXT) { 391 String power = parser.getText(); 392 double value = 0; 393 try { 394 value = Double.valueOf(power); 395 } catch (NumberFormatException nfe) { 396 } 397 if (element.equals(TAG_ITEM)) { 398 sPowerItemMap.put(name, value); 399 } else if (parsingArray) { 400 array.add(value); 401 } 402 } 403 } else if (element.equals(TAG_MODEM)) { 404 sModemPowerProfile.parseFromXml(parser); 405 } 406 } 407 if (parsingArray) { 408 sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()])); 409 } 410 } catch (XmlPullParserException e) { 411 throw new RuntimeException(e); 412 } catch (IOException e) { 413 throw new RuntimeException(e); 414 } finally { 415 parser.close(); 416 } 417 418 // Now collect other config variables. 419 int[] configResIds = new int[]{ 420 com.android.internal.R.integer.config_bluetooth_idle_cur_ma, 421 com.android.internal.R.integer.config_bluetooth_rx_cur_ma, 422 com.android.internal.R.integer.config_bluetooth_tx_cur_ma, 423 com.android.internal.R.integer.config_bluetooth_operating_voltage_mv, 424 }; 425 426 String[] configResIdKeys = new String[]{ 427 POWER_BLUETOOTH_CONTROLLER_IDLE, 428 POWER_BLUETOOTH_CONTROLLER_RX, 429 POWER_BLUETOOTH_CONTROLLER_TX, 430 POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, 431 }; 432 433 for (int i = 0; i < configResIds.length; i++) { 434 String key = configResIdKeys[i]; 435 // if we already have some of these parameters in power_profile.xml, ignore the 436 // value in config.xml 437 if ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) { 438 continue; 439 } 440 int value = resources.getInteger(configResIds[i]); 441 if (value > 0) { 442 sPowerItemMap.put(key, (double) value); 443 } 444 } 445 } 446 447 private CpuClusterKey[] mCpuClusters; 448 449 private static final String CPU_PER_CLUSTER_CORE_COUNT = "cpu.clusters.cores"; 450 private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster"; 451 private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster"; 452 private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster"; 453 initCpuClusters()454 private void initCpuClusters() { 455 if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) { 456 final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT); 457 mCpuClusters = new CpuClusterKey[data.length]; 458 for (int cluster = 0; cluster < data.length; cluster++) { 459 int numCpusInCluster = (int) Math.round(data[cluster]); 460 mCpuClusters[cluster] = new CpuClusterKey( 461 CPU_CORE_SPEED_PREFIX + cluster, CPU_CLUSTER_POWER_COUNT + cluster, 462 CPU_CORE_POWER_PREFIX + cluster, numCpusInCluster); 463 } 464 } else { 465 // Default to single. 466 mCpuClusters = new CpuClusterKey[1]; 467 int numCpus = 1; 468 if (sPowerItemMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) { 469 numCpus = (int) Math.round(sPowerItemMap.get(CPU_PER_CLUSTER_CORE_COUNT)); 470 } 471 mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0, 472 CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus); 473 } 474 } 475 476 public static class CpuClusterKey { 477 private final String freqKey; 478 private final String clusterPowerKey; 479 private final String corePowerKey; 480 private final int numCpus; 481 CpuClusterKey(String freqKey, String clusterPowerKey, String corePowerKey, int numCpus)482 private CpuClusterKey(String freqKey, String clusterPowerKey, 483 String corePowerKey, int numCpus) { 484 this.freqKey = freqKey; 485 this.clusterPowerKey = clusterPowerKey; 486 this.corePowerKey = corePowerKey; 487 this.numCpus = numCpus; 488 } 489 } 490 491 @UnsupportedAppUsage getNumCpuClusters()492 public int getNumCpuClusters() { 493 return mCpuClusters.length; 494 } 495 getNumCoresInCpuCluster(int cluster)496 public int getNumCoresInCpuCluster(int cluster) { 497 if (cluster < 0 || cluster >= mCpuClusters.length) { 498 return 0; // index out of bound 499 } 500 return mCpuClusters[cluster].numCpus; 501 } 502 503 @UnsupportedAppUsage getNumSpeedStepsInCpuCluster(int cluster)504 public int getNumSpeedStepsInCpuCluster(int cluster) { 505 if (cluster < 0 || cluster >= mCpuClusters.length) { 506 return 0; // index out of bound 507 } 508 if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) { 509 return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length; 510 } 511 return 1; // Only one speed 512 } 513 getAveragePowerForCpuCluster(int cluster)514 public double getAveragePowerForCpuCluster(int cluster) { 515 if (cluster >= 0 && cluster < mCpuClusters.length) { 516 return getAveragePower(mCpuClusters[cluster].clusterPowerKey); 517 } 518 return 0; 519 } 520 getAveragePowerForCpuCore(int cluster, int step)521 public double getAveragePowerForCpuCore(int cluster, int step) { 522 if (cluster >= 0 && cluster < mCpuClusters.length) { 523 return getAveragePower(mCpuClusters[cluster].corePowerKey, step); 524 } 525 return 0; 526 } 527 528 private int mNumDisplays; 529 initDisplays()530 private void initDisplays() { 531 // Figure out how many displays are listed in the power profile. 532 mNumDisplays = 0; 533 while (!Double.isNaN( 534 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, mNumDisplays, Double.NaN)) 535 || !Double.isNaN( 536 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, mNumDisplays, Double.NaN)) 537 || !Double.isNaN( 538 getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, mNumDisplays, 539 Double.NaN))) { 540 mNumDisplays++; 541 } 542 543 // Handle legacy display power constants. 544 final Double deprecatedAmbientDisplay = sPowerItemMap.get(POWER_AMBIENT_DISPLAY); 545 boolean legacy = false; 546 if (deprecatedAmbientDisplay != null && mNumDisplays == 0) { 547 final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_AMBIENT, 0); 548 Slog.w(TAG, POWER_AMBIENT_DISPLAY + " is deprecated! Use " + key + " instead."); 549 sPowerItemMap.put(key, deprecatedAmbientDisplay); 550 legacy = true; 551 } 552 553 final Double deprecatedScreenOn = sPowerItemMap.get(POWER_SCREEN_ON); 554 if (deprecatedScreenOn != null && mNumDisplays == 0) { 555 final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_ON, 0); 556 Slog.w(TAG, POWER_SCREEN_ON + " is deprecated! Use " + key + " instead."); 557 sPowerItemMap.put(key, deprecatedScreenOn); 558 legacy = true; 559 } 560 561 final Double deprecatedScreenFull = sPowerItemMap.get(POWER_SCREEN_FULL); 562 if (deprecatedScreenFull != null && mNumDisplays == 0) { 563 final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_FULL, 0); 564 Slog.w(TAG, POWER_SCREEN_FULL + " is deprecated! Use " + key + " instead."); 565 sPowerItemMap.put(key, deprecatedScreenFull); 566 legacy = true; 567 } 568 if (legacy) { 569 mNumDisplays = 1; 570 } 571 } 572 573 /** 574 * Returns the number built in displays on the device as defined in the power_profile.xml. 575 */ getNumDisplays()576 public int getNumDisplays() { 577 return mNumDisplays; 578 } 579 initModem()580 private void initModem() { 581 handleDeprecatedModemConstant(ModemPowerProfile.MODEM_DRAIN_TYPE_SLEEP, 582 POWER_MODEM_CONTROLLER_SLEEP, 0); 583 handleDeprecatedModemConstant(ModemPowerProfile.MODEM_DRAIN_TYPE_IDLE, 584 POWER_MODEM_CONTROLLER_IDLE, 0); 585 handleDeprecatedModemConstant( 586 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_RX, 587 POWER_MODEM_CONTROLLER_RX, 0); 588 handleDeprecatedModemConstant( 589 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX 590 | ModemPowerProfile.MODEM_TX_LEVEL_0, POWER_MODEM_CONTROLLER_TX, 0); 591 handleDeprecatedModemConstant( 592 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX 593 | ModemPowerProfile.MODEM_TX_LEVEL_1, POWER_MODEM_CONTROLLER_TX, 1); 594 handleDeprecatedModemConstant( 595 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX 596 | ModemPowerProfile.MODEM_TX_LEVEL_2, POWER_MODEM_CONTROLLER_TX, 2); 597 handleDeprecatedModemConstant( 598 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX 599 | ModemPowerProfile.MODEM_TX_LEVEL_3, POWER_MODEM_CONTROLLER_TX, 3); 600 handleDeprecatedModemConstant( 601 ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX 602 | ModemPowerProfile.MODEM_TX_LEVEL_4, POWER_MODEM_CONTROLLER_TX, 4); 603 } 604 handleDeprecatedModemConstant(int key, String deprecatedKey, int level)605 private void handleDeprecatedModemConstant(int key, String deprecatedKey, int level) { 606 final double drain = sModemPowerProfile.getAverageBatteryDrainMa(key); 607 if (!Double.isNaN(drain)) return; // Value already set, don't overwrite it. 608 609 final double deprecatedDrain = getAveragePower(deprecatedKey, level); 610 sModemPowerProfile.setPowerConstant(key, Double.toString(deprecatedDrain)); 611 } 612 613 /** 614 * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a 615 * default value if the subsystem has no recorded value. 616 * 617 * @return the number of memory bandwidth buckets. 618 */ getNumElements(String key)619 public int getNumElements(String key) { 620 if (sPowerItemMap.containsKey(key)) { 621 return 1; 622 } else if (sPowerArrayMap.containsKey(key)) { 623 return sPowerArrayMap.get(key).length; 624 } 625 return 0; 626 } 627 628 /** 629 * Returns the average current in mA consumed by the subsystem, or the given 630 * default value if the subsystem has no recorded value. 631 * 632 * @param type the subsystem type 633 * @param defaultValue the value to return if the subsystem has no recorded value. 634 * @return the average current in milliAmps. 635 */ getAveragePowerOrDefault(String type, double defaultValue)636 public double getAveragePowerOrDefault(String type, double defaultValue) { 637 if (sPowerItemMap.containsKey(type)) { 638 return sPowerItemMap.get(type); 639 } else if (sPowerArrayMap.containsKey(type)) { 640 return sPowerArrayMap.get(type)[0]; 641 } else { 642 return defaultValue; 643 } 644 } 645 646 /** 647 * Returns the average current in mA consumed by the subsystem 648 * 649 * @param type the subsystem type 650 * @return the average current in milliAmps. 651 */ 652 @UnsupportedAppUsage getAveragePower(String type)653 public double getAveragePower(String type) { 654 return getAveragePowerOrDefault(type, 0); 655 } 656 657 /** 658 * Returns the average current in mA consumed by a subsystem's specified operation, or the given 659 * default value if the subsystem has no recorded value. 660 * 661 * @param key that describes a subsystem's battery draining operation 662 * The key is built from multiple constant, see {@link Subsystem} and 663 * {@link ModemPowerProfile}. 664 * @param defaultValue the value to return if the subsystem has no recorded value. 665 * @return the average current in milliAmps. 666 */ getAverageBatteryDrainOrDefaultMa(long key, double defaultValue)667 public double getAverageBatteryDrainOrDefaultMa(long key, double defaultValue) { 668 final long subsystemType = key & SUBSYSTEM_MASK; 669 final int subsystemFields = (int) (key & SUBSYSTEM_FIELDS_MASK); 670 671 final double value; 672 if (subsystemType == SUBSYSTEM_MODEM) { 673 value = sModemPowerProfile.getAverageBatteryDrainMa(subsystemFields); 674 } else { 675 value = Double.NaN; 676 } 677 678 if (Double.isNaN(value)) return defaultValue; 679 return value; 680 } 681 682 /** 683 * Returns the average current in mA consumed by a subsystem's specified operation. 684 * 685 * @param key that describes a subsystem's battery draining operation 686 * The key is built from multiple constant, see {@link Subsystem} and 687 * {@link ModemPowerProfile}. 688 * @return the average current in milliAmps. 689 */ getAverageBatteryDrainMa(long key)690 public double getAverageBatteryDrainMa(long key) { 691 return getAverageBatteryDrainOrDefaultMa(key, 0); 692 } 693 694 /** 695 * Returns the average current in mA consumed by the subsystem for the given level. 696 * 697 * @param type the subsystem type 698 * @param level the level of power at which the subsystem is running. For instance, the 699 * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) 700 * If there is no data for multiple levels, the level is ignored. 701 * @return the average current in milliAmps. 702 */ 703 @UnsupportedAppUsage getAveragePower(String type, int level)704 public double getAveragePower(String type, int level) { 705 if (sPowerItemMap.containsKey(type)) { 706 return sPowerItemMap.get(type); 707 } else if (sPowerArrayMap.containsKey(type)) { 708 final Double[] values = sPowerArrayMap.get(type); 709 if (values.length > level && level >= 0) { 710 return values[level]; 711 } else if (level < 0 || values.length == 0) { 712 return 0; 713 } else { 714 return values[values.length - 1]; 715 } 716 } else { 717 return 0; 718 } 719 } 720 721 /** 722 * Returns the average current in mA consumed by an ordinaled subsystem, or the given 723 * default value if the subsystem has no recorded value. 724 * 725 * @param group the subsystem {@link PowerGroup}. 726 * @param ordinal which entity in the {@link PowerGroup}. 727 * @param defaultValue the value to return if the subsystem has no recorded value. 728 * @return the average current in milliAmps. 729 */ getAveragePowerForOrdinal(@owerGroup String group, int ordinal, double defaultValue)730 public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal, 731 double defaultValue) { 732 final String type = getOrdinalPowerType(group, ordinal); 733 return getAveragePowerOrDefault(type, defaultValue); 734 } 735 736 /** 737 * Returns the average current in mA consumed by an ordinaled subsystem. 738 * 739 * @param group the subsystem {@link PowerGroup}. 740 * @param ordinal which entity in the {@link PowerGroup}. 741 * @return the average current in milliAmps. 742 */ getAveragePowerForOrdinal(@owerGroup String group, int ordinal)743 public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal) { 744 return getAveragePowerForOrdinal(group, ordinal, 0); 745 } 746 747 /** 748 * Returns the battery capacity, if available, in milli Amp Hours. If not available, 749 * it returns zero. 750 * 751 * @return the battery capacity in mAh 752 */ 753 @UnsupportedAppUsage getBatteryCapacity()754 public double getBatteryCapacity() { 755 return getAveragePower(POWER_BATTERY_CAPACITY); 756 } 757 758 /** 759 * Dump power constants into PowerProfileProto 760 */ dumpDebug(ProtoOutputStream proto)761 public void dumpDebug(ProtoOutputStream proto) { 762 // cpu.suspend 763 writePowerConstantToProto(proto, POWER_CPU_SUSPEND, PowerProfileProto.CPU_SUSPEND); 764 765 // cpu.idle 766 writePowerConstantToProto(proto, POWER_CPU_IDLE, PowerProfileProto.CPU_IDLE); 767 768 // cpu.active 769 writePowerConstantToProto(proto, POWER_CPU_ACTIVE, PowerProfileProto.CPU_ACTIVE); 770 771 // cpu.clusters.cores 772 // cpu.cluster_power.cluster 773 // cpu.core_speeds.cluster 774 // cpu.core_power.cluster 775 for (int cluster = 0; cluster < mCpuClusters.length; cluster++) { 776 final long token = proto.start(PowerProfileProto.CPU_CLUSTER); 777 proto.write(PowerProfileProto.CpuCluster.ID, cluster); 778 proto.write(PowerProfileProto.CpuCluster.CLUSTER_POWER, 779 sPowerItemMap.get(mCpuClusters[cluster].clusterPowerKey)); 780 proto.write(PowerProfileProto.CpuCluster.CORES, mCpuClusters[cluster].numCpus); 781 for (Double speed : sPowerArrayMap.get(mCpuClusters[cluster].freqKey)) { 782 proto.write(PowerProfileProto.CpuCluster.SPEED, speed); 783 } 784 for (Double corePower : sPowerArrayMap.get(mCpuClusters[cluster].corePowerKey)) { 785 proto.write(PowerProfileProto.CpuCluster.CORE_POWER, corePower); 786 } 787 proto.end(token); 788 } 789 790 // wifi.scan 791 writePowerConstantToProto(proto, POWER_WIFI_SCAN, PowerProfileProto.WIFI_SCAN); 792 793 // wifi.on 794 writePowerConstantToProto(proto, POWER_WIFI_ON, PowerProfileProto.WIFI_ON); 795 796 // wifi.active 797 writePowerConstantToProto(proto, POWER_WIFI_ACTIVE, PowerProfileProto.WIFI_ACTIVE); 798 799 // wifi.controller.idle 800 writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_IDLE, 801 PowerProfileProto.WIFI_CONTROLLER_IDLE); 802 803 // wifi.controller.rx 804 writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_RX, 805 PowerProfileProto.WIFI_CONTROLLER_RX); 806 807 // wifi.controller.tx 808 writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_TX, 809 PowerProfileProto.WIFI_CONTROLLER_TX); 810 811 // wifi.controller.tx_levels 812 writePowerConstantArrayToProto(proto, POWER_WIFI_CONTROLLER_TX_LEVELS, 813 PowerProfileProto.WIFI_CONTROLLER_TX_LEVELS); 814 815 // wifi.controller.voltage 816 writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE, 817 PowerProfileProto.WIFI_CONTROLLER_OPERATING_VOLTAGE); 818 819 // bluetooth.controller.idle 820 writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_IDLE, 821 PowerProfileProto.BLUETOOTH_CONTROLLER_IDLE); 822 823 // bluetooth.controller.rx 824 writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_RX, 825 PowerProfileProto.BLUETOOTH_CONTROLLER_RX); 826 827 // bluetooth.controller.tx 828 writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_TX, 829 PowerProfileProto.BLUETOOTH_CONTROLLER_TX); 830 831 // bluetooth.controller.voltage 832 writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, 833 PowerProfileProto.BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE); 834 835 // modem.controller.sleep 836 writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_SLEEP, 837 PowerProfileProto.MODEM_CONTROLLER_SLEEP); 838 839 // modem.controller.idle 840 writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_IDLE, 841 PowerProfileProto.MODEM_CONTROLLER_IDLE); 842 843 // modem.controller.rx 844 writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_RX, 845 PowerProfileProto.MODEM_CONTROLLER_RX); 846 847 // modem.controller.tx 848 writePowerConstantArrayToProto(proto, POWER_MODEM_CONTROLLER_TX, 849 PowerProfileProto.MODEM_CONTROLLER_TX); 850 851 // modem.controller.voltage 852 writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE, 853 PowerProfileProto.MODEM_CONTROLLER_OPERATING_VOLTAGE); 854 855 // gps.on 856 writePowerConstantToProto(proto, POWER_GPS_ON, PowerProfileProto.GPS_ON); 857 858 // gps.signalqualitybased 859 writePowerConstantArrayToProto(proto, POWER_GPS_SIGNAL_QUALITY_BASED, 860 PowerProfileProto.GPS_SIGNAL_QUALITY_BASED); 861 862 // gps.voltage 863 writePowerConstantToProto(proto, POWER_GPS_OPERATING_VOLTAGE, 864 PowerProfileProto.GPS_OPERATING_VOLTAGE); 865 866 // bluetooth.on 867 writePowerConstantToProto(proto, POWER_BLUETOOTH_ON, PowerProfileProto.BLUETOOTH_ON); 868 869 // bluetooth.active 870 writePowerConstantToProto(proto, POWER_BLUETOOTH_ACTIVE, 871 PowerProfileProto.BLUETOOTH_ACTIVE); 872 873 // bluetooth.at 874 writePowerConstantToProto(proto, POWER_BLUETOOTH_AT_CMD, 875 PowerProfileProto.BLUETOOTH_AT_CMD); 876 877 // ambient.on 878 writePowerConstantToProto(proto, POWER_AMBIENT_DISPLAY, PowerProfileProto.AMBIENT_DISPLAY); 879 880 // screen.on 881 writePowerConstantToProto(proto, POWER_SCREEN_ON, PowerProfileProto.SCREEN_ON); 882 883 // radio.on 884 writePowerConstantToProto(proto, POWER_RADIO_ON, PowerProfileProto.RADIO_ON); 885 886 // radio.scanning 887 writePowerConstantToProto(proto, POWER_RADIO_SCANNING, PowerProfileProto.RADIO_SCANNING); 888 889 // radio.active 890 writePowerConstantToProto(proto, POWER_RADIO_ACTIVE, PowerProfileProto.RADIO_ACTIVE); 891 892 // screen.full 893 writePowerConstantToProto(proto, POWER_SCREEN_FULL, PowerProfileProto.SCREEN_FULL); 894 895 // audio 896 writePowerConstantToProto(proto, POWER_AUDIO, PowerProfileProto.AUDIO); 897 898 // video 899 writePowerConstantToProto(proto, POWER_VIDEO, PowerProfileProto.VIDEO); 900 901 // camera.flashlight 902 writePowerConstantToProto(proto, POWER_FLASHLIGHT, PowerProfileProto.FLASHLIGHT); 903 904 // memory.bandwidths 905 writePowerConstantToProto(proto, POWER_MEMORY, PowerProfileProto.MEMORY); 906 907 // camera.avg 908 writePowerConstantToProto(proto, POWER_CAMERA, PowerProfileProto.CAMERA); 909 910 // wifi.batchedscan 911 writePowerConstantToProto(proto, POWER_WIFI_BATCHED_SCAN, 912 PowerProfileProto.WIFI_BATCHED_SCAN); 913 914 // battery.capacity 915 writePowerConstantToProto(proto, POWER_BATTERY_CAPACITY, 916 PowerProfileProto.BATTERY_CAPACITY); 917 } 918 919 /** 920 * Dump the PowerProfile values. 921 */ dump(PrintWriter pw)922 public void dump(PrintWriter pw) { 923 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw); 924 sPowerItemMap.forEach((key, value) -> { 925 ipw.print(key, value); 926 ipw.println(); 927 }); 928 sPowerArrayMap.forEach((key, value) -> { 929 ipw.print(key, Arrays.toString(value)); 930 ipw.println(); 931 }); 932 ipw.println("Modem values:"); 933 ipw.increaseIndent(); 934 sModemPowerProfile.dump(ipw); 935 ipw.decreaseIndent(); 936 } 937 938 // Writes items in sPowerItemMap to proto if exists. writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId)939 private void writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId) { 940 if (sPowerItemMap.containsKey(key)) { 941 proto.write(fieldId, sPowerItemMap.get(key)); 942 } 943 } 944 945 // Writes items in sPowerArrayMap to proto if exists. writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId)946 private void writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId) { 947 if (sPowerArrayMap.containsKey(key)) { 948 for (Double d : sPowerArrayMap.get(key)) { 949 proto.write(fieldId, d); 950 } 951 } 952 } 953 954 // Creates the key for an ordinaled power constant from the group and ordinal. getOrdinalPowerType(@owerGroup String group, int ordinal)955 private static String getOrdinalPowerType(@PowerGroup String group, int ordinal) { 956 return group + ordinal; 957 } 958 } 959