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