Home | History | Annotate | Download | only in os
      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