PowerProfile.java revision d4a4729c0cac582a2dcec7c8cfb316b81885a0f0
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
17package com.android.internal.os;
18
19
20import android.content.Context;
21import android.content.res.XmlResourceParser;
22
23import com.android.common.XmlUtils;
24
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlPullParserException;
27
28import java.io.IOException;
29import java.util.ArrayList;
30import 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 */
37public 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 in power collapse mode.
51     */
52    public static final String POWER_CPU_ACTIVE = "cpu.active";
53
54    /**
55     * Power consumption when WiFi driver is scanning for networks.
56     */
57    public static final String POWER_WIFI_SCAN = "wifi.scan";
58
59    /**
60     * Power consumption when WiFi driver is on.
61     */
62    public static final String POWER_WIFI_ON = "wifi.on";
63
64    /**
65     * Power consumption when WiFi driver is transmitting/receiving.
66     */
67    public static final String POWER_WIFI_ACTIVE = "wifi.active";
68
69    /**
70     * Power consumption when GPS is on.
71     */
72    public static final String POWER_GPS_ON = "gps.on";
73
74    /**
75     * Power consumption when Bluetooth driver is on.
76     */
77    public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
78
79    /**
80     * Power consumption when Bluetooth driver is transmitting/receiving.
81     */
82    public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
83
84    /**
85     * Power consumption when Bluetooth driver gets an AT command.
86     */
87    public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
88
89    /**
90     * Power consumption when screen is on, not including the backlight power.
91     */
92    public static final String POWER_SCREEN_ON = "screen.on";
93
94    /**
95     * Power consumption when cell radio is on but not on a call.
96     */
97    public static final String POWER_RADIO_ON = "radio.on";
98
99    /**
100     * Power consumption when cell radio is hunting for a signal.
101     */
102    public static final String POWER_RADIO_SCANNING = "radio.scanning";
103
104    /**
105     * Power consumption when talking on the phone.
106     */
107    public static final String POWER_RADIO_ACTIVE = "radio.active";
108
109    /**
110     * Power consumption at full backlight brightness. If the backlight is at
111     * 50% brightness, then this should be multiplied by 0.5
112     */
113    public static final String POWER_SCREEN_FULL = "screen.full";
114
115    /**
116     * Power consumed by the audio hardware when playing back audio content. This is in addition
117     * to the CPU power, probably due to a DSP and / or amplifier.
118     */
119    public static final String POWER_AUDIO = "dsp.audio";
120
121    /**
122     * Power consumed by any media hardware when playing back video content. This is in addition
123     * to the CPU power, probably due to a DSP.
124     */
125    public static final String POWER_VIDEO = "dsp.video";
126
127    public static final String POWER_CPU_SPEEDS = "cpu.speeds";
128
129    static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
130
131    private static final String TAG_DEVICE = "device";
132    private static final String TAG_ITEM = "item";
133    private static final String TAG_ARRAY = "array";
134    private static final String TAG_ARRAYITEM = "value";
135    private static final String ATTR_NAME = "name";
136
137    public PowerProfile(Context context) {
138        // Read the XML file for the given profile (normally only one per
139        // device)
140        if (sPowerMap.size() == 0) {
141            readPowerValuesFromXml(context);
142        }
143    }
144
145    private void readPowerValuesFromXml(Context context) {
146        int id = com.android.internal.R.xml.power_profile;
147        XmlResourceParser parser = context.getResources().getXml(id);
148        boolean parsingArray = false;
149        ArrayList<Double> array = new ArrayList<Double>();
150        String arrayName = null;
151
152        try {
153            XmlUtils.beginDocument(parser, TAG_DEVICE);
154
155            while (true) {
156                XmlUtils.nextElement(parser);
157
158                String element = parser.getName();
159                if (element == null) break;
160
161                if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
162                    // Finish array
163                    sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
164                    parsingArray = false;
165                }
166                if (element.equals(TAG_ARRAY)) {
167                    parsingArray = true;
168                    array.clear();
169                    arrayName = parser.getAttributeValue(null, ATTR_NAME);
170                } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) {
171                    String name = null;
172                    if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME);
173                    if (parser.next() == XmlPullParser.TEXT) {
174                        String power = parser.getText();
175                        double value = 0;
176                        try {
177                            value = Double.valueOf(power);
178                        } catch (NumberFormatException nfe) {
179                        }
180                        if (element.equals(TAG_ITEM)) {
181                            sPowerMap.put(name, value);
182                        } else if (parsingArray) {
183                            array.add(value);
184                        }
185                    }
186                }
187            }
188            if (parsingArray) {
189                sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
190            }
191        } catch (XmlPullParserException e) {
192            throw new RuntimeException(e);
193        } catch (IOException e) {
194            throw new RuntimeException(e);
195        } finally {
196            parser.close();
197        }
198    }
199
200    /**
201     * Returns the average current in mA consumed by the subsystem
202     * @param type the subsystem type
203     * @return the average current in milliAmps.
204     */
205    public double getAveragePower(String type) {
206        if (sPowerMap.containsKey(type)) {
207            Object data = sPowerMap.get(type);
208            if (data instanceof Double[]) {
209                return ((Double[])data)[0];
210            } else {
211                return (Double) sPowerMap.get(type);
212            }
213        } else {
214            return 0;
215        }
216    }
217
218    /**
219     * Returns the average current in mA consumed by the subsystem for the given level.
220     * @param type the subsystem type
221     * @param level the level of power at which the subsystem is running. For instance, the
222     *  signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
223     *  If there is no data for multiple levels, the level is ignored.
224     * @return the average current in milliAmps.
225     */
226    public double getAveragePower(String type, int level) {
227        if (sPowerMap.containsKey(type)) {
228            Object data = sPowerMap.get(type);
229            if (data instanceof Double[]) {
230                final Double[] values = (Double[]) data;
231                if (values.length > level && level >= 0) {
232                    return values[level];
233                } else if (level < 0) {
234                    return 0;
235                } else {
236                    return values[values.length - 1];
237                }
238            } else {
239                return (Double) data;
240            }
241        } else {
242            return 0;
243        }
244    }
245
246    public int getNumSpeedSteps() {
247        Object value = sPowerMap.get(POWER_CPU_SPEEDS);
248        if (value != null && value instanceof Double[]) {
249            return ((Double[])value).length;
250        }
251        return 1; // Only one speed
252    }
253}
254