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