blob: 14ebe227f3b42ed9daaa4179e274382dac8cda5f [file] [log] [blame]
Amith Yamasani244fa5c2009-05-22 14:36:07 -07001/*
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
17package com.android.internal.os;
18
19
20import android.content.Context;
Adam Lesinskie08af192015-03-25 16:42:59 -070021import android.content.res.Resources;
Amith Yamasani244fa5c2009-05-22 14:36:07 -070022import android.content.res.XmlResourceParser;
23
Dianne Hackborn2269d1572010-02-24 19:54:22 -080024import com.android.internal.util.XmlUtils;
Amith Yamasani244fa5c2009-05-22 14:36:07 -070025
26import org.xmlpull.v1.XmlPullParser;
27import org.xmlpull.v1.XmlPullParserException;
28
29import java.io.IOException;
Amith Yamasani3718aaa2009-06-09 06:32:35 -070030import java.util.ArrayList;
Amith Yamasani244fa5c2009-05-22 14:36:07 -070031import 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 */
38public 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 /**
Dianne Hackborn0c8b4d32010-11-08 19:10:58 -080051 * 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 /**
Amith Yamasanie43530a2009-08-21 13:11:37 -070060 * Power consumption when CPU is in power collapse mode.
Amith Yamasani244fa5c2009-05-22 14:36:07 -070061 */
Adam Lesinski6832f392015-09-05 18:05:40 -070062 @Deprecated
Amith Yamasanie43530a2009-08-21 13:11:37 -070063 public static final String POWER_CPU_ACTIVE = "cpu.active";
Amith Yamasani244fa5c2009-05-22 14:36:07 -070064
65 /**
66 * Power consumption when WiFi driver is scanning for networks.
67 */
68 public static final String POWER_WIFI_SCAN = "wifi.scan";
69
70 /**
71 * Power consumption when WiFi driver is on.
72 */
73 public static final String POWER_WIFI_ON = "wifi.on";
74
75 /**
76 * Power consumption when WiFi driver is transmitting/receiving.
77 */
78 public static final String POWER_WIFI_ACTIVE = "wifi.active";
79
Adam Lesinskie08af192015-03-25 16:42:59 -070080 //
81 // Updated power constants. These are not estimated, they are real world
82 // currents and voltages for the underlying bluetooth and wifi controllers.
83 //
84
85 public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
86 public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
87 public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
88 public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
89
90 public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
91 public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx";
92 public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx";
93 public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
94 "bluetooth.controller.voltage";
Adam Lesinski33dac552015-03-09 15:24:48 -070095
Adam Lesinski21f76aa2016-01-25 12:27:06 -080096 public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle";
97 public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx";
98 public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx";
99 public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE =
100 "modem.controller.voltage";
101
Adam Lesinski33dac552015-03-09 15:24:48 -0700102 /**
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700103 * Power consumption when GPS is on.
104 */
105 public static final String POWER_GPS_ON = "gps.on";
106
107 /**
108 * Power consumption when Bluetooth driver is on.
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800109 * @deprecated
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700110 */
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800111 @Deprecated
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700112 public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
113
114 /**
115 * Power consumption when Bluetooth driver is transmitting/receiving.
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800116 * @deprecated
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700117 */
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800118 @Deprecated
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700119 public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
120
121 /**
Amith Yamasani3f7e35c2009-07-13 16:02:45 -0700122 * Power consumption when Bluetooth driver gets an AT command.
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800123 * @deprecated
Amith Yamasani3f7e35c2009-07-13 16:02:45 -0700124 */
Adam Lesinski21f76aa2016-01-25 12:27:06 -0800125 @Deprecated
Amith Yamasani3f7e35c2009-07-13 16:02:45 -0700126 public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
127
Adam Lesinski33dac552015-03-09 15:24:48 -0700128
129 /**
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700130 * Power consumption when screen is on, not including the backlight power.
131 */
132 public static final String POWER_SCREEN_ON = "screen.on";
133
134 /**
135 * Power consumption when cell radio is on but not on a call.
136 */
137 public static final String POWER_RADIO_ON = "radio.on";
138
139 /**
Amith Yamasanif37447b2009-10-08 18:28:01 -0700140 * Power consumption when cell radio is hunting for a signal.
141 */
142 public static final String POWER_RADIO_SCANNING = "radio.scanning";
143
144 /**
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700145 * Power consumption when talking on the phone.
146 */
147 public static final String POWER_RADIO_ACTIVE = "radio.active";
148
149 /**
150 * Power consumption at full backlight brightness. If the backlight is at
151 * 50% brightness, then this should be multiplied by 0.5
152 */
153 public static final String POWER_SCREEN_FULL = "screen.full";
154
155 /**
156 * Power consumed by the audio hardware when playing back audio content. This is in addition
157 * to the CPU power, probably due to a DSP and / or amplifier.
158 */
159 public static final String POWER_AUDIO = "dsp.audio";
160
161 /**
162 * Power consumed by any media hardware when playing back video content. This is in addition
163 * to the CPU power, probably due to a DSP.
164 */
165 public static final String POWER_VIDEO = "dsp.video";
166
Dianne Hackbornabc7c492014-06-30 16:57:46 -0700167 /**
Ruben Brunk5b1308f2015-06-03 18:49:27 -0700168 * Average power consumption when camera flashlight is on.
Dianne Hackbornabc7c492014-06-30 16:57:46 -0700169 */
170 public static final String POWER_FLASHLIGHT = "camera.flashlight";
171
Ruben Brunk5b1308f2015-06-03 18:49:27 -0700172 /**
173 * Average power consumption when the camera is on over all standard use cases.
174 *
175 * TODO: Add more fine-grained camera power metrics.
176 */
177 public static final String POWER_CAMERA = "camera.avg";
178
Adam Lesinski6832f392015-09-05 18:05:40 -0700179 @Deprecated
Amith Yamasanie43530a2009-08-21 13:11:37 -0700180 public static final String POWER_CPU_SPEEDS = "cpu.speeds";
181
Amith Yamasani169741b2010-05-27 10:37:54 -0700182 /**
Robert Greenwalta029ea12013-09-25 16:38:12 -0700183 * Power consumed by wif batched scaning. Broken down into bins by
184 * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels
185 * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)!
186 */
187 public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
188
189 /**
Amith Yamasani169741b2010-05-27 10:37:54 -0700190 * Battery capacity in milliAmpHour (mAh).
191 */
192 public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
193
Adam Lesinskie08af192015-03-25 16:42:59 -0700194 static final HashMap<String, Object> sPowerMap = new HashMap<>();
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700195
196 private static final String TAG_DEVICE = "device";
197 private static final String TAG_ITEM = "item";
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700198 private static final String TAG_ARRAY = "array";
199 private static final String TAG_ARRAYITEM = "value";
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700200 private static final String ATTR_NAME = "name";
201
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700202 public PowerProfile(Context context) {
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700203 // Read the XML file for the given profile (normally only one per
204 // device)
205 if (sPowerMap.size() == 0) {
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700206 readPowerValuesFromXml(context);
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700207 }
Adam Lesinski6832f392015-09-05 18:05:40 -0700208 initCpuClusters();
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700209 }
210
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700211 private void readPowerValuesFromXml(Context context) {
212 int id = com.android.internal.R.xml.power_profile;
Adam Lesinskie08af192015-03-25 16:42:59 -0700213 final Resources resources = context.getResources();
214 XmlResourceParser parser = resources.getXml(id);
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700215 boolean parsingArray = false;
216 ArrayList<Double> array = new ArrayList<Double>();
217 String arrayName = null;
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700218
219 try {
220 XmlUtils.beginDocument(parser, TAG_DEVICE);
221
222 while (true) {
223 XmlUtils.nextElement(parser);
224
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700225 String element = parser.getName();
226 if (element == null) break;
Robert Greenwalta029ea12013-09-25 16:38:12 -0700227
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700228 if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
229 // Finish array
230 sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
231 parsingArray = false;
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700232 }
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700233 if (element.equals(TAG_ARRAY)) {
234 parsingArray = true;
235 array.clear();
236 arrayName = parser.getAttributeValue(null, ATTR_NAME);
237 } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) {
238 String name = null;
239 if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME);
240 if (parser.next() == XmlPullParser.TEXT) {
241 String power = parser.getText();
242 double value = 0;
243 try {
244 value = Double.valueOf(power);
245 } catch (NumberFormatException nfe) {
246 }
247 if (element.equals(TAG_ITEM)) {
248 sPowerMap.put(name, value);
249 } else if (parsingArray) {
250 array.add(value);
251 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700252 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700253 }
254 }
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700255 if (parsingArray) {
256 sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
257 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700258 } catch (XmlPullParserException e) {
259 throw new RuntimeException(e);
260 } catch (IOException e) {
261 throw new RuntimeException(e);
262 } finally {
263 parser.close();
264 }
Adam Lesinskie08af192015-03-25 16:42:59 -0700265
266 // Now collect other config variables.
Adam Lesinski6832f392015-09-05 18:05:40 -0700267 int[] configResIds = new int[]{
Adam Lesinskie08af192015-03-25 16:42:59 -0700268 com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
269 com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
270 com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
271 com.android.internal.R.integer.config_bluetooth_operating_voltage_mv,
272 com.android.internal.R.integer.config_wifi_idle_receive_cur_ma,
273 com.android.internal.R.integer.config_wifi_active_rx_cur_ma,
274 com.android.internal.R.integer.config_wifi_tx_cur_ma,
275 com.android.internal.R.integer.config_wifi_operating_voltage_mv,
276 };
277
Adam Lesinski6832f392015-09-05 18:05:40 -0700278 String[] configResIdKeys = new String[]{
Adam Lesinskie08af192015-03-25 16:42:59 -0700279 POWER_BLUETOOTH_CONTROLLER_IDLE,
280 POWER_BLUETOOTH_CONTROLLER_RX,
281 POWER_BLUETOOTH_CONTROLLER_TX,
282 POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
283 POWER_WIFI_CONTROLLER_IDLE,
284 POWER_WIFI_CONTROLLER_RX,
285 POWER_WIFI_CONTROLLER_TX,
286 POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
287 };
288
289 for (int i = 0; i < configResIds.length; i++) {
290 int value = resources.getInteger(configResIds[i]);
291 if (value > 0) {
292 sPowerMap.put(configResIdKeys[i], (double) value);
293 }
294 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700295 }
296
Adam Lesinski6832f392015-09-05 18:05:40 -0700297 private CpuClusterKey[] mCpuClusters;
298
299 private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
300 private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster";
301 private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster";
302
303 @SuppressWarnings("deprecated")
304 private void initCpuClusters() {
305 // Figure out how many CPU clusters we're dealing with
306 final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT);
307 if (obj == null || !(obj instanceof Double[])) {
308 // Default to single.
309 mCpuClusters = new CpuClusterKey[1];
310 mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1);
311
312 } else {
313 final Double[] array = (Double[]) obj;
314 mCpuClusters = new CpuClusterKey[array.length];
315 for (int cluster = 0; cluster < array.length; cluster++) {
316 int numCpusInCluster = (int) Math.round(array[cluster]);
317 mCpuClusters[cluster] = new CpuClusterKey(
318 POWER_CPU_CLUSTER_SPEED_PREFIX + cluster,
319 POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster,
320 numCpusInCluster);
321 }
322 }
323 }
324
325 public static class CpuClusterKey {
326 private final String timeKey;
327 private final String powerKey;
328 private final int numCpus;
329
330 private CpuClusterKey(String timeKey, String powerKey, int numCpus) {
331 this.timeKey = timeKey;
332 this.powerKey = powerKey;
333 this.numCpus = numCpus;
334 }
335 }
336
337 public int getNumCpuClusters() {
338 return mCpuClusters.length;
339 }
340
341 public int getNumCoresInCpuCluster(int index) {
342 return mCpuClusters[index].numCpus;
343 }
344
345 public int getNumSpeedStepsInCpuCluster(int index) {
346 Object value = sPowerMap.get(mCpuClusters[index].timeKey);
347 if (value != null && value instanceof Double[]) {
348 return ((Double[])value).length;
349 }
350 return 1; // Only one speed
351 }
352
353 public double getAveragePowerForCpu(int cluster, int step) {
354 if (cluster >= 0 && cluster < mCpuClusters.length) {
355 return getAveragePower(mCpuClusters[cluster].powerKey, step);
356 }
357 return 0;
358 }
359
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700360 /**
Adam Lesinski33dac552015-03-09 15:24:48 -0700361 * Returns the average current in mA consumed by the subsystem, or the given
362 * default value if the subsystem has no recorded value.
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700363 * @param type the subsystem type
Adam Lesinski33dac552015-03-09 15:24:48 -0700364 * @param defaultValue the value to return if the subsystem has no recorded value.
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700365 * @return the average current in milliAmps.
366 */
Adam Lesinski33dac552015-03-09 15:24:48 -0700367 public double getAveragePowerOrDefault(String type, double defaultValue) {
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700368 if (sPowerMap.containsKey(type)) {
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700369 Object data = sPowerMap.get(type);
370 if (data instanceof Double[]) {
371 return ((Double[])data)[0];
372 } else {
373 return (Double) sPowerMap.get(type);
374 }
375 } else {
Adam Lesinski33dac552015-03-09 15:24:48 -0700376 return defaultValue;
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700377 }
378 }
Adam Lesinski33dac552015-03-09 15:24:48 -0700379
380 /**
381 * Returns the average current in mA consumed by the subsystem
382 * @param type the subsystem type
383 * @return the average current in milliAmps.
384 */
385 public double getAveragePower(String type) {
386 return getAveragePowerOrDefault(type, 0);
387 }
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700388
389 /**
Amith Yamasanie43530a2009-08-21 13:11:37 -0700390 * Returns the average current in mA consumed by the subsystem for the given level.
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700391 * @param type the subsystem type
392 * @param level the level of power at which the subsystem is running. For instance, the
Amith Yamasanie43530a2009-08-21 13:11:37 -0700393 * signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700394 * If there is no data for multiple levels, the level is ignored.
395 * @return the average current in milliAmps.
396 */
397 public double getAveragePower(String type, int level) {
398 if (sPowerMap.containsKey(type)) {
399 Object data = sPowerMap.get(type);
Amith Yamasani32dbefd2009-06-19 09:21:17 -0700400 if (data instanceof Double[]) {
401 final Double[] values = (Double[]) data;
402 if (values.length > level && level >= 0) {
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700403 return values[level];
Ruchi Kandoibe9cbb12014-07-02 17:47:40 -0700404 } else if (level < 0 || values.length == 0) {
Amith Yamasani32dbefd2009-06-19 09:21:17 -0700405 return 0;
Amith Yamasani3718aaa2009-06-09 06:32:35 -0700406 } else {
407 return values[values.length - 1];
408 }
409 } else {
410 return (Double) data;
411 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700412 } else {
413 return 0;
414 }
415 }
Amith Yamasanie43530a2009-08-21 13:11:37 -0700416
Amith Yamasani169741b2010-05-27 10:37:54 -0700417 /**
418 * Returns the battery capacity, if available, in milli Amp Hours. If not available,
419 * it returns zero.
420 * @return the battery capacity in mAh
421 */
422 public double getBatteryCapacity() {
423 return getAveragePower(POWER_BATTERY_CAPACITY);
424 }
Amith Yamasani244fa5c2009-05-22 14:36:07 -0700425}