Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 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.content.Context; |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 21 | import android.content.res.Resources; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 22 | import android.content.res.XmlResourceParser; |
| 23 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 24 | import com.android.internal.annotations.VisibleForTesting; |
Dianne Hackborn | 2269d157 | 2010-02-24 19:54:22 -0800 | [diff] [blame] | 25 | import com.android.internal.util.XmlUtils; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 26 | |
| 27 | import org.xmlpull.v1.XmlPullParser; |
| 28 | import org.xmlpull.v1.XmlPullParserException; |
| 29 | |
| 30 | import java.io.IOException; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 31 | import java.util.ArrayList; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 32 | import java.util.HashMap; |
| 33 | |
| 34 | /** |
| 35 | * Reports power consumption values for various device activities. Reads values from an XML file. |
| 36 | * Customize the XML file for different devices. |
| 37 | * [hidden] |
| 38 | */ |
| 39 | public class PowerProfile { |
| 40 | |
| 41 | /** |
| 42 | * No power consumption, or accounted for elsewhere. |
| 43 | */ |
| 44 | public static final String POWER_NONE = "none"; |
| 45 | |
| 46 | /** |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 47 | * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. |
| 48 | * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should |
| 49 | * be zero on devices that can go into full CPU power collapse even when a wake |
| 50 | * lock is held. Otherwise, this is the power consumption in addition to |
| 51 | * POWER_CPU_SUSPEND due to a wake lock being held but with no CPU activity. |
| 52 | * POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters |
| 53 | * and cores. |
| 54 | * |
| 55 | * CPU Power Equation (assume two clusters): |
| 56 | * Total power = POWER_CPU_SUSPEND (always added) |
| 57 | * + POWER_CPU_IDLE (skip this and below if in power collapse mode) |
| 58 | * + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock |
| 59 | * is held) |
| 60 | * + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running) |
| 61 | * + core_power.cluster0 * num running cores in cluster 0 |
| 62 | * + core_power.cluster1 * num running cores in cluster 1 |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 63 | */ |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 64 | public static final String POWER_CPU_SUSPEND = "cpu.suspend"; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 65 | public static final String POWER_CPU_IDLE = "cpu.idle"; |
Amith Yamasani | e43530a | 2009-08-21 13:11:37 -0700 | [diff] [blame] | 66 | public static final String POWER_CPU_ACTIVE = "cpu.active"; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 67 | |
| 68 | /** |
| 69 | * Power consumption when WiFi driver is scanning for networks. |
| 70 | */ |
| 71 | public static final String POWER_WIFI_SCAN = "wifi.scan"; |
| 72 | |
| 73 | /** |
| 74 | * Power consumption when WiFi driver is on. |
| 75 | */ |
| 76 | public static final String POWER_WIFI_ON = "wifi.on"; |
| 77 | |
| 78 | /** |
| 79 | * Power consumption when WiFi driver is transmitting/receiving. |
| 80 | */ |
| 81 | public static final String POWER_WIFI_ACTIVE = "wifi.active"; |
| 82 | |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 83 | // |
| 84 | // Updated power constants. These are not estimated, they are real world |
| 85 | // currents and voltages for the underlying bluetooth and wifi controllers. |
| 86 | // |
| 87 | |
| 88 | public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; |
| 89 | public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; |
| 90 | public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; |
Roshan Pius | 2a91e4a | 2016-03-31 16:33:54 -0700 | [diff] [blame] | 91 | public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels"; |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 92 | public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage"; |
| 93 | |
| 94 | public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle"; |
| 95 | public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx"; |
| 96 | public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx"; |
| 97 | public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE = |
| 98 | "bluetooth.controller.voltage"; |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 99 | |
Siddharth Ray | 2038af8 | 2018-01-17 17:40:26 -0800 | [diff] [blame] | 100 | public static final String POWER_MODEM_CONTROLLER_SLEEP = "modem.controller.sleep"; |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 101 | public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle"; |
| 102 | public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx"; |
| 103 | public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx"; |
| 104 | public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE = |
| 105 | "modem.controller.voltage"; |
| 106 | |
Siddharth Ray | 0ed2e95 | 2018-01-22 11:32:14 -0800 | [diff] [blame] | 107 | /** |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 108 | * Power consumption when GPS is on. |
| 109 | */ |
| 110 | public static final String POWER_GPS_ON = "gps.on"; |
| 111 | |
| 112 | /** |
Siddharth Ray | 0ed2e95 | 2018-01-22 11:32:14 -0800 | [diff] [blame] | 113 | * GPS power parameters based on signal quality |
| 114 | */ |
| 115 | public static final String POWER_GPS_SIGNAL_QUALITY_BASED = "gps.signalqualitybased"; |
| 116 | public static final String POWER_GPS_OPERATING_VOLTAGE = "gps.voltage"; |
| 117 | |
| 118 | /** |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 119 | * Power consumption when Bluetooth driver is on. |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 120 | * @deprecated |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 121 | */ |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 122 | @Deprecated |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 123 | public static final String POWER_BLUETOOTH_ON = "bluetooth.on"; |
| 124 | |
| 125 | /** |
| 126 | * Power consumption when Bluetooth driver is transmitting/receiving. |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 127 | * @deprecated |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 128 | */ |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 129 | @Deprecated |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 130 | public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active"; |
| 131 | |
| 132 | /** |
Amith Yamasani | 3f7e35c | 2009-07-13 16:02:45 -0700 | [diff] [blame] | 133 | * Power consumption when Bluetooth driver gets an AT command. |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 134 | * @deprecated |
Amith Yamasani | 3f7e35c | 2009-07-13 16:02:45 -0700 | [diff] [blame] | 135 | */ |
Adam Lesinski | 21f76aa | 2016-01-25 12:27:06 -0800 | [diff] [blame] | 136 | @Deprecated |
Amith Yamasani | 3f7e35c | 2009-07-13 16:02:45 -0700 | [diff] [blame] | 137 | public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; |
| 138 | |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 139 | |
| 140 | /** |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 141 | * Power consumption when screen is on, not including the backlight power. |
| 142 | */ |
| 143 | public static final String POWER_SCREEN_ON = "screen.on"; |
| 144 | |
| 145 | /** |
| 146 | * Power consumption when cell radio is on but not on a call. |
| 147 | */ |
| 148 | public static final String POWER_RADIO_ON = "radio.on"; |
| 149 | |
| 150 | /** |
Amith Yamasani | f37447b | 2009-10-08 18:28:01 -0700 | [diff] [blame] | 151 | * Power consumption when cell radio is hunting for a signal. |
| 152 | */ |
| 153 | public static final String POWER_RADIO_SCANNING = "radio.scanning"; |
| 154 | |
| 155 | /** |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 156 | * Power consumption when talking on the phone. |
| 157 | */ |
| 158 | public static final String POWER_RADIO_ACTIVE = "radio.active"; |
| 159 | |
| 160 | /** |
| 161 | * Power consumption at full backlight brightness. If the backlight is at |
| 162 | * 50% brightness, then this should be multiplied by 0.5 |
| 163 | */ |
| 164 | public static final String POWER_SCREEN_FULL = "screen.full"; |
| 165 | |
| 166 | /** |
| 167 | * Power consumed by the audio hardware when playing back audio content. This is in addition |
| 168 | * to the CPU power, probably due to a DSP and / or amplifier. |
| 169 | */ |
| 170 | public static final String POWER_AUDIO = "dsp.audio"; |
| 171 | |
| 172 | /** |
| 173 | * Power consumed by any media hardware when playing back video content. This is in addition |
| 174 | * to the CPU power, probably due to a DSP. |
| 175 | */ |
| 176 | public static final String POWER_VIDEO = "dsp.video"; |
| 177 | |
Dianne Hackborn | abc7c49 | 2014-06-30 16:57:46 -0700 | [diff] [blame] | 178 | /** |
Ruben Brunk | 5b1308f | 2015-06-03 18:49:27 -0700 | [diff] [blame] | 179 | * Average power consumption when camera flashlight is on. |
Dianne Hackborn | abc7c49 | 2014-06-30 16:57:46 -0700 | [diff] [blame] | 180 | */ |
| 181 | public static final String POWER_FLASHLIGHT = "camera.flashlight"; |
| 182 | |
Ruben Brunk | 5b1308f | 2015-06-03 18:49:27 -0700 | [diff] [blame] | 183 | /** |
James Carr | 2dd7e5e | 2016-07-20 18:48:39 -0700 | [diff] [blame] | 184 | * Power consumption when DDR is being used. |
| 185 | */ |
| 186 | public static final String POWER_MEMORY = "memory.bandwidths"; |
| 187 | |
| 188 | /** |
Ruben Brunk | 5b1308f | 2015-06-03 18:49:27 -0700 | [diff] [blame] | 189 | * Average power consumption when the camera is on over all standard use cases. |
| 190 | * |
| 191 | * TODO: Add more fine-grained camera power metrics. |
| 192 | */ |
| 193 | public static final String POWER_CAMERA = "camera.avg"; |
| 194 | |
Amith Yamasani | 169741b | 2010-05-27 10:37:54 -0700 | [diff] [blame] | 195 | /** |
Robert Greenwalt | a029ea1 | 2013-09-25 16:38:12 -0700 | [diff] [blame] | 196 | * Power consumed by wif batched scaning. Broken down into bins by |
| 197 | * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels |
| 198 | * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)! |
| 199 | */ |
| 200 | public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan"; |
| 201 | |
| 202 | /** |
Amith Yamasani | 169741b | 2010-05-27 10:37:54 -0700 | [diff] [blame] | 203 | * Battery capacity in milliAmpHour (mAh). |
| 204 | */ |
| 205 | public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; |
| 206 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 207 | /** |
| 208 | * A map from Power Use Item to its power consumption. |
| 209 | */ |
| 210 | static final HashMap<String, Double> sPowerItemMap = new HashMap<>(); |
| 211 | /** |
| 212 | * A map from Power Use Item to an array of its power consumption |
| 213 | * (for items with variable power e.g. CPU). |
| 214 | */ |
| 215 | static final HashMap<String, Double[]> sPowerArrayMap = new HashMap<>(); |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 216 | |
| 217 | private static final String TAG_DEVICE = "device"; |
| 218 | private static final String TAG_ITEM = "item"; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 219 | private static final String TAG_ARRAY = "array"; |
| 220 | private static final String TAG_ARRAYITEM = "value"; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 221 | private static final String ATTR_NAME = "name"; |
| 222 | |
jackqdyulei | 0e3504c | 2017-08-03 15:46:52 -0700 | [diff] [blame] | 223 | private static final Object sLock = new Object(); |
| 224 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 225 | @VisibleForTesting |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 226 | public PowerProfile(Context context) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 227 | this(context, false); |
| 228 | } |
| 229 | |
| 230 | /** |
| 231 | * For PowerProfileTest |
| 232 | */ |
| 233 | @VisibleForTesting |
| 234 | public PowerProfile(Context context, boolean forTest) { |
| 235 | // Read the XML file for the given profile (normally only one per device) |
jackqdyulei | 0e3504c | 2017-08-03 15:46:52 -0700 | [diff] [blame] | 236 | synchronized (sLock) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 237 | if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { |
| 238 | readPowerValuesFromXml(context, forTest); |
jackqdyulei | 0e3504c | 2017-08-03 15:46:52 -0700 | [diff] [blame] | 239 | } |
| 240 | initCpuClusters(); |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 241 | } |
| 242 | } |
| 243 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 244 | private void readPowerValuesFromXml(Context context, boolean forTest) { |
| 245 | final int id = forTest ? com.android.internal.R.xml.power_profile_test : |
| 246 | com.android.internal.R.xml.power_profile; |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 247 | final Resources resources = context.getResources(); |
| 248 | XmlResourceParser parser = resources.getXml(id); |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 249 | boolean parsingArray = false; |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 250 | ArrayList<Double> array = new ArrayList<>(); |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 251 | String arrayName = null; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 252 | |
| 253 | try { |
| 254 | XmlUtils.beginDocument(parser, TAG_DEVICE); |
| 255 | |
| 256 | while (true) { |
| 257 | XmlUtils.nextElement(parser); |
| 258 | |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 259 | String element = parser.getName(); |
| 260 | if (element == null) break; |
Robert Greenwalt | a029ea1 | 2013-09-25 16:38:12 -0700 | [diff] [blame] | 261 | |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 262 | if (parsingArray && !element.equals(TAG_ARRAYITEM)) { |
| 263 | // Finish array |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 264 | sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()])); |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 265 | parsingArray = false; |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 266 | } |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 267 | if (element.equals(TAG_ARRAY)) { |
| 268 | parsingArray = true; |
| 269 | array.clear(); |
| 270 | arrayName = parser.getAttributeValue(null, ATTR_NAME); |
| 271 | } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) { |
| 272 | String name = null; |
| 273 | if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME); |
| 274 | if (parser.next() == XmlPullParser.TEXT) { |
| 275 | String power = parser.getText(); |
| 276 | double value = 0; |
| 277 | try { |
| 278 | value = Double.valueOf(power); |
| 279 | } catch (NumberFormatException nfe) { |
| 280 | } |
| 281 | if (element.equals(TAG_ITEM)) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 282 | sPowerItemMap.put(name, value); |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 283 | } else if (parsingArray) { |
| 284 | array.add(value); |
| 285 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 286 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 287 | } |
| 288 | } |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 289 | if (parsingArray) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 290 | sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()])); |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 291 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 292 | } catch (XmlPullParserException e) { |
| 293 | throw new RuntimeException(e); |
| 294 | } catch (IOException e) { |
| 295 | throw new RuntimeException(e); |
| 296 | } finally { |
| 297 | parser.close(); |
| 298 | } |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 299 | |
| 300 | // Now collect other config variables. |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 301 | int[] configResIds = new int[]{ |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 302 | com.android.internal.R.integer.config_bluetooth_idle_cur_ma, |
| 303 | com.android.internal.R.integer.config_bluetooth_rx_cur_ma, |
| 304 | com.android.internal.R.integer.config_bluetooth_tx_cur_ma, |
| 305 | com.android.internal.R.integer.config_bluetooth_operating_voltage_mv, |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 306 | }; |
| 307 | |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 308 | String[] configResIdKeys = new String[]{ |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 309 | POWER_BLUETOOTH_CONTROLLER_IDLE, |
| 310 | POWER_BLUETOOTH_CONTROLLER_RX, |
| 311 | POWER_BLUETOOTH_CONTROLLER_TX, |
| 312 | POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 313 | }; |
| 314 | |
| 315 | for (int i = 0; i < configResIds.length; i++) { |
Roshan Pius | 2a91e4a | 2016-03-31 16:33:54 -0700 | [diff] [blame] | 316 | String key = configResIdKeys[i]; |
| 317 | // if we already have some of these parameters in power_profile.xml, ignore the |
| 318 | // value in config.xml |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 319 | if ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) { |
Roshan Pius | 2a91e4a | 2016-03-31 16:33:54 -0700 | [diff] [blame] | 320 | continue; |
| 321 | } |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 322 | int value = resources.getInteger(configResIds[i]); |
| 323 | if (value > 0) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 324 | sPowerItemMap.put(key, (double) value); |
Adam Lesinski | e08af19 | 2015-03-25 16:42:59 -0700 | [diff] [blame] | 325 | } |
| 326 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 327 | } |
| 328 | |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 329 | private CpuClusterKey[] mCpuClusters; |
| 330 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 331 | private static final String CPU_PER_CLUSTER_CORE_COUNT = "cpu.clusters.cores"; |
| 332 | private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster"; |
| 333 | private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster"; |
| 334 | private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster"; |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 335 | |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 336 | private void initCpuClusters() { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 337 | if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) { |
| 338 | final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT); |
| 339 | mCpuClusters = new CpuClusterKey[data.length]; |
| 340 | for (int cluster = 0; cluster < data.length; cluster++) { |
| 341 | int numCpusInCluster = (int) Math.round(data[cluster]); |
| 342 | mCpuClusters[cluster] = new CpuClusterKey( |
| 343 | CPU_CORE_SPEED_PREFIX + cluster, CPU_CLUSTER_POWER_COUNT + cluster, |
| 344 | CPU_CORE_POWER_PREFIX + cluster, numCpusInCluster); |
| 345 | } |
| 346 | } else { |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 347 | // Default to single. |
| 348 | mCpuClusters = new CpuClusterKey[1]; |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 349 | int numCpus = 1; |
| 350 | if (sPowerItemMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) { |
| 351 | numCpus = (int) Math.round(sPowerItemMap.get(CPU_PER_CLUSTER_CORE_COUNT)); |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 352 | } |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 353 | mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0, |
| 354 | CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus); |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 355 | } |
| 356 | } |
| 357 | |
| 358 | public static class CpuClusterKey { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 359 | private final String freqKey; |
| 360 | private final String clusterPowerKey; |
| 361 | private final String corePowerKey; |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 362 | private final int numCpus; |
| 363 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 364 | private CpuClusterKey(String freqKey, String clusterPowerKey, |
| 365 | String corePowerKey, int numCpus) { |
| 366 | this.freqKey = freqKey; |
| 367 | this.clusterPowerKey = clusterPowerKey; |
| 368 | this.corePowerKey = corePowerKey; |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 369 | this.numCpus = numCpus; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | public int getNumCpuClusters() { |
| 374 | return mCpuClusters.length; |
| 375 | } |
| 376 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 377 | public int getNumCoresInCpuCluster(int cluster) { |
| 378 | return mCpuClusters[cluster].numCpus; |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 379 | } |
| 380 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 381 | public int getNumSpeedStepsInCpuCluster(int cluster) { |
| 382 | if (cluster < 0 || cluster >= mCpuClusters.length) { |
| 383 | return 0; // index out of bound |
| 384 | } |
| 385 | if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) { |
| 386 | return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length; |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 387 | } |
| 388 | return 1; // Only one speed |
| 389 | } |
| 390 | |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 391 | public double getAveragePowerForCpuCluster(int cluster) { |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 392 | if (cluster >= 0 && cluster < mCpuClusters.length) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 393 | return getAveragePower(mCpuClusters[cluster].clusterPowerKey); |
| 394 | } |
| 395 | return 0; |
| 396 | } |
| 397 | |
| 398 | public double getAveragePowerForCpuCore(int cluster, int step) { |
| 399 | if (cluster >= 0 && cluster < mCpuClusters.length) { |
| 400 | return getAveragePower(mCpuClusters[cluster].corePowerKey, step); |
Adam Lesinski | 6832f39 | 2015-09-05 18:05:40 -0700 | [diff] [blame] | 401 | } |
| 402 | return 0; |
| 403 | } |
| 404 | |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 405 | /** |
James Carr | 2dd7e5e | 2016-07-20 18:48:39 -0700 | [diff] [blame] | 406 | * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a |
| 407 | * default value if the subsystem has no recorded value. |
| 408 | * @return the number of memory bandwidth buckets. |
| 409 | */ |
| 410 | public int getNumElements(String key) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 411 | if (sPowerItemMap.containsKey(key)) { |
| 412 | return 1; |
| 413 | } else if (sPowerArrayMap.containsKey(key)) { |
| 414 | return sPowerArrayMap.get(key).length; |
James Carr | 2dd7e5e | 2016-07-20 18:48:39 -0700 | [diff] [blame] | 415 | } |
| 416 | return 0; |
| 417 | } |
| 418 | |
| 419 | /** |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 420 | * Returns the average current in mA consumed by the subsystem, or the given |
| 421 | * default value if the subsystem has no recorded value. |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 422 | * @param type the subsystem type |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 423 | * @param defaultValue the value to return if the subsystem has no recorded value. |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 424 | * @return the average current in milliAmps. |
| 425 | */ |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 426 | public double getAveragePowerOrDefault(String type, double defaultValue) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 427 | if (sPowerItemMap.containsKey(type)) { |
| 428 | return sPowerItemMap.get(type); |
| 429 | } else if (sPowerArrayMap.containsKey(type)) { |
| 430 | return sPowerArrayMap.get(type)[0]; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 431 | } else { |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 432 | return defaultValue; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 433 | } |
| 434 | } |
Adam Lesinski | 33dac55 | 2015-03-09 15:24:48 -0700 | [diff] [blame] | 435 | |
| 436 | /** |
| 437 | * Returns the average current in mA consumed by the subsystem |
| 438 | * @param type the subsystem type |
| 439 | * @return the average current in milliAmps. |
| 440 | */ |
| 441 | public double getAveragePower(String type) { |
| 442 | return getAveragePowerOrDefault(type, 0); |
| 443 | } |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 444 | |
| 445 | /** |
Amith Yamasani | e43530a | 2009-08-21 13:11:37 -0700 | [diff] [blame] | 446 | * Returns the average current in mA consumed by the subsystem for the given level. |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 447 | * @param type the subsystem type |
| 448 | * @param level the level of power at which the subsystem is running. For instance, the |
Amith Yamasani | e43530a | 2009-08-21 13:11:37 -0700 | [diff] [blame] | 449 | * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 450 | * If there is no data for multiple levels, the level is ignored. |
| 451 | * @return the average current in milliAmps. |
| 452 | */ |
| 453 | public double getAveragePower(String type, int level) { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 454 | if (sPowerItemMap.containsKey(type)) { |
| 455 | return sPowerItemMap.get(type); |
| 456 | } else if (sPowerArrayMap.containsKey(type)) { |
| 457 | final Double[] values = sPowerArrayMap.get(type); |
| 458 | if (values.length > level && level >= 0) { |
| 459 | return values[level]; |
| 460 | } else if (level < 0 || values.length == 0) { |
| 461 | return 0; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 462 | } else { |
Mike Ma | 3d422c3 | 2017-10-25 11:08:57 -0700 | [diff] [blame] | 463 | return values[values.length - 1]; |
Amith Yamasani | 3718aaa | 2009-06-09 06:32:35 -0700 | [diff] [blame] | 464 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 465 | } else { |
| 466 | return 0; |
| 467 | } |
| 468 | } |
Amith Yamasani | e43530a | 2009-08-21 13:11:37 -0700 | [diff] [blame] | 469 | |
Amith Yamasani | 169741b | 2010-05-27 10:37:54 -0700 | [diff] [blame] | 470 | /** |
| 471 | * Returns the battery capacity, if available, in milli Amp Hours. If not available, |
| 472 | * it returns zero. |
| 473 | * @return the battery capacity in mAh |
| 474 | */ |
| 475 | public double getBatteryCapacity() { |
| 476 | return getAveragePower(POWER_BATTERY_CAPACITY); |
| 477 | } |
Amith Yamasani | 244fa5c | 2009-05-22 14:36:07 -0700 | [diff] [blame] | 478 | } |