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