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