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; 21 import android.content.res.Resources; 22 import android.content.res.XmlResourceParser; 23 24 import com.android.internal.util.XmlUtils; 25 26 import org.xmlpull.v1.XmlPullParser; 27 import org.xmlpull.v1.XmlPullParserException; 28 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 33 /** 34 * Reports power consumption values for various device activities. Reads values from an XML file. 35 * Customize the XML file for different devices. 36 * [hidden] 37 */ 38 public class PowerProfile { 39 40 /** 41 * No power consumption, or accounted for elsewhere. 42 */ 43 public static final String POWER_NONE = "none"; 44 45 /** 46 * Power consumption when CPU is in power collapse mode. 47 */ 48 public static final String POWER_CPU_IDLE = "cpu.idle"; 49 50 /** 51 * Power consumption when CPU is awake (when a wake lock is held). This 52 * should be 0 on devices that can go into full CPU power collapse even 53 * when a wake lock is held. Otherwise, this is the power consumption in 54 * addition to POWERR_CPU_IDLE due to a wake lock being held but with no 55 * CPU activity. 56 */ 57 public static final String POWER_CPU_AWAKE = "cpu.awake"; 58 59 /** 60 * Power consumption when CPU is in power collapse mode. 61 */ 62 public static final String POWER_CPU_ACTIVE = "cpu.active"; 63 64 /** 65 * Power consumption when WiFi driver is scanning for networks. 66 */ 67 public static final String POWER_WIFI_SCAN = "wifi.scan"; 68 69 /** 70 * Power consumption when WiFi driver is on. 71 */ 72 public static final String POWER_WIFI_ON = "wifi.on"; 73 74 /** 75 * Power consumption when WiFi driver is transmitting/receiving. 76 */ 77 public static final String POWER_WIFI_ACTIVE = "wifi.active"; 78 79 // 80 // Updated power constants. These are not estimated, they are real world 81 // currents and voltages for the underlying bluetooth and wifi controllers. 82 // 83 84 public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; 85 public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; 86 public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; 87 public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage"; 88 89 public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle"; 90 public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx"; 91 public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx"; 92 public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE = 93 "bluetooth.controller.voltage"; 94 95 /** 96 * Power consumption when GPS is on. 97 */ 98 public static final String POWER_GPS_ON = "gps.on"; 99 100 /** 101 * Power consumption when Bluetooth driver is on. 102 */ 103 public static final String POWER_BLUETOOTH_ON = "bluetooth.on"; 104 105 /** 106 * Power consumption when Bluetooth driver is transmitting/receiving. 107 */ 108 public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active"; 109 110 /** 111 * Power consumption when Bluetooth driver gets an AT command. 112 */ 113 public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; 114 115 116 /** 117 * Power consumption when screen is on, not including the backlight power. 118 */ 119 public static final String POWER_SCREEN_ON = "screen.on"; 120 121 /** 122 * Power consumption when cell radio is on but not on a call. 123 */ 124 public static final String POWER_RADIO_ON = "radio.on"; 125 126 /** 127 * Power consumption when cell radio is hunting for a signal. 128 */ 129 public static final String POWER_RADIO_SCANNING = "radio.scanning"; 130 131 /** 132 * Power consumption when talking on the phone. 133 */ 134 public static final String POWER_RADIO_ACTIVE = "radio.active"; 135 136 /** 137 * Power consumption at full backlight brightness. If the backlight is at 138 * 50% brightness, then this should be multiplied by 0.5 139 */ 140 public static final String POWER_SCREEN_FULL = "screen.full"; 141 142 /** 143 * Power consumed by the audio hardware when playing back audio content. This is in addition 144 * to the CPU power, probably due to a DSP and / or amplifier. 145 */ 146 public static final String POWER_AUDIO = "dsp.audio"; 147 148 /** 149 * Power consumed by any media hardware when playing back video content. This is in addition 150 * to the CPU power, probably due to a DSP. 151 */ 152 public static final String POWER_VIDEO = "dsp.video"; 153 154 /** 155 * Average power consumption when camera flashlight is on. 156 */ 157 public static final String POWER_FLASHLIGHT = "camera.flashlight"; 158 159 /** 160 * Average power consumption when the camera is on over all standard use cases. 161 * 162 * TODO: Add more fine-grained camera power metrics. 163 */ 164 public static final String POWER_CAMERA = "camera.avg"; 165 166 public static final String POWER_CPU_SPEEDS = "cpu.speeds"; 167 168 /** 169 * Power consumed by wif batched scaning. Broken down into bins by 170 * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels 171 * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)! 172 */ 173 public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan"; 174 175 /** 176 * Battery capacity in milliAmpHour (mAh). 177 */ 178 public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; 179 180 static final HashMap<String, Object> sPowerMap = new HashMap<>(); 181 182 private static final String TAG_DEVICE = "device"; 183 private static final String TAG_ITEM = "item"; 184 private static final String TAG_ARRAY = "array"; 185 private static final String TAG_ARRAYITEM = "value"; 186 private static final String ATTR_NAME = "name"; 187 188 public PowerProfile(Context context) { 189 // Read the XML file for the given profile (normally only one per 190 // device) 191 if (sPowerMap.size() == 0) { 192 readPowerValuesFromXml(context); 193 } 194 } 195 196 private void readPowerValuesFromXml(Context context) { 197 int id = com.android.internal.R.xml.power_profile; 198 final Resources resources = context.getResources(); 199 XmlResourceParser parser = resources.getXml(id); 200 boolean parsingArray = false; 201 ArrayList<Double> array = new ArrayList<Double>(); 202 String arrayName = null; 203 204 try { 205 XmlUtils.beginDocument(parser, TAG_DEVICE); 206 207 while (true) { 208 XmlUtils.nextElement(parser); 209 210 String element = parser.getName(); 211 if (element == null) break; 212 213 if (parsingArray && !element.equals(TAG_ARRAYITEM)) { 214 // Finish array 215 sPowerMap.put(arrayName, array.toArray(new Double[array.size()])); 216 parsingArray = false; 217 } 218 if (element.equals(TAG_ARRAY)) { 219 parsingArray = true; 220 array.clear(); 221 arrayName = parser.getAttributeValue(null, ATTR_NAME); 222 } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) { 223 String name = null; 224 if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME); 225 if (parser.next() == XmlPullParser.TEXT) { 226 String power = parser.getText(); 227 double value = 0; 228 try { 229 value = Double.valueOf(power); 230 } catch (NumberFormatException nfe) { 231 } 232 if (element.equals(TAG_ITEM)) { 233 sPowerMap.put(name, value); 234 } else if (parsingArray) { 235 array.add(value); 236 } 237 } 238 } 239 } 240 if (parsingArray) { 241 sPowerMap.put(arrayName, array.toArray(new Double[array.size()])); 242 } 243 } catch (XmlPullParserException e) { 244 throw new RuntimeException(e); 245 } catch (IOException e) { 246 throw new RuntimeException(e); 247 } finally { 248 parser.close(); 249 } 250 251 // Now collect other config variables. 252 int[] configResIds = new int[] { 253 com.android.internal.R.integer.config_bluetooth_idle_cur_ma, 254 com.android.internal.R.integer.config_bluetooth_rx_cur_ma, 255 com.android.internal.R.integer.config_bluetooth_tx_cur_ma, 256 com.android.internal.R.integer.config_bluetooth_operating_voltage_mv, 257 com.android.internal.R.integer.config_wifi_idle_receive_cur_ma, 258 com.android.internal.R.integer.config_wifi_active_rx_cur_ma, 259 com.android.internal.R.integer.config_wifi_tx_cur_ma, 260 com.android.internal.R.integer.config_wifi_operating_voltage_mv, 261 }; 262 263 String[] configResIdKeys = new String[] { 264 POWER_BLUETOOTH_CONTROLLER_IDLE, 265 POWER_BLUETOOTH_CONTROLLER_RX, 266 POWER_BLUETOOTH_CONTROLLER_TX, 267 POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, 268 POWER_WIFI_CONTROLLER_IDLE, 269 POWER_WIFI_CONTROLLER_RX, 270 POWER_WIFI_CONTROLLER_TX, 271 POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE, 272 }; 273 274 for (int i = 0; i < configResIds.length; i++) { 275 int value = resources.getInteger(configResIds[i]); 276 if (value > 0) { 277 sPowerMap.put(configResIdKeys[i], (double) value); 278 } 279 } 280 } 281 282 /** 283 * Returns the average current in mA consumed by the subsystem, or the given 284 * default value if the subsystem has no recorded value. 285 * @param type the subsystem type 286 * @param defaultValue the value to return if the subsystem has no recorded value. 287 * @return the average current in milliAmps. 288 */ 289 public double getAveragePowerOrDefault(String type, double defaultValue) { 290 if (sPowerMap.containsKey(type)) { 291 Object data = sPowerMap.get(type); 292 if (data instanceof Double[]) { 293 return ((Double[])data)[0]; 294 } else { 295 return (Double) sPowerMap.get(type); 296 } 297 } else { 298 return defaultValue; 299 } 300 } 301 302 /** 303 * Returns the average current in mA consumed by the subsystem 304 * @param type the subsystem type 305 * @return the average current in milliAmps. 306 */ 307 public double getAveragePower(String type) { 308 return getAveragePowerOrDefault(type, 0); 309 } 310 311 /** 312 * Returns the average current in mA consumed by the subsystem for the given level. 313 * @param type the subsystem type 314 * @param level the level of power at which the subsystem is running. For instance, the 315 * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) 316 * If there is no data for multiple levels, the level is ignored. 317 * @return the average current in milliAmps. 318 */ 319 public double getAveragePower(String type, int level) { 320 if (sPowerMap.containsKey(type)) { 321 Object data = sPowerMap.get(type); 322 if (data instanceof Double[]) { 323 final Double[] values = (Double[]) data; 324 if (values.length > level && level >= 0) { 325 return values[level]; 326 } else if (level < 0 || values.length == 0) { 327 return 0; 328 } else { 329 return values[values.length - 1]; 330 } 331 } else { 332 return (Double) data; 333 } 334 } else { 335 return 0; 336 } 337 } 338 339 /** 340 * Returns the battery capacity, if available, in milli Amp Hours. If not available, 341 * it returns zero. 342 * @return the battery capacity in mAh 343 */ 344 public double getBatteryCapacity() { 345 return getAveragePower(POWER_BATTERY_CAPACITY); 346 } 347 348 /** 349 * Returns the number of speeds that the CPU can be run at. 350 * @return 351 */ 352 public int getNumSpeedSteps() { 353 Object value = sPowerMap.get(POWER_CPU_SPEEDS); 354 if (value != null && value instanceof Double[]) { 355 return ((Double[])value).length; 356 } 357 return 1; // Only one speed 358 } 359 } 360