PowerProfile.java解析power_profile.xml的資料
阿新 • • 發佈:2018-12-17
1. PowerProfile.java
這個檔案主要目的是為了power_profile.xml的配置資訊,尤其是配置的電流資訊
frameworks/base/core/java/com/android/internal/os/PowerProfile.java
/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.os; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import android.util.Log; /** * Reports power consumption values for various device activities. Reads values from an XML file. * Customize the XML file for different devices. * [hidden] */ public class PowerProfile { /** * No power consumption, or accounted for elsewhere. */ public static final String POWER_NONE = "none"; /** * Power consumption when CPU is in power collapse mode. */ public static final String POWER_CPU_IDLE = "cpu.idle"; /** * Power consumption when CPU is awake (when a wake lock is held). This * should be 0 on devices that can go into full CPU power collapse even * when a wake lock is held. Otherwise, this is the power consumption in * addition to POWER_CPU_IDLE due to a wake lock being held but with no * CPU activity. */ public static final String POWER_CPU_AWAKE = "cpu.awake"; /** * Power consumption when CPU is in power collapse mode. */ @Deprecated public static final String POWER_CPU_ACTIVE = "cpu.active"; /** * Power consumption when WiFi driver is scanning for networks. */ public static final String POWER_WIFI_SCAN = "wifi.scan"; /** * Power consumption when WiFi driver is on. */ public static final String POWER_WIFI_ON = "wifi.on"; /** * Power consumption when WiFi driver is transmitting/receiving. */ public static final String POWER_WIFI_ACTIVE = "wifi.active"; // // Updated power constants. These are not estimated, they are real world // currents and voltages for the underlying bluetooth and wifi controllers. // public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle"; public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx"; public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx"; public static final String POWER_WIFI_CONTROLLER_TX_LEVELS = "wifi.controller.tx_levels"; public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage"; public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle"; public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx"; public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx"; public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE = "bluetooth.controller.voltage"; public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle"; public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx"; public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx"; public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE = "modem.controller.voltage"; /** * Power consumption when GPS is on. */ public static final String POWER_GPS_ON = "gps.on"; /** * Power consumption when Bluetooth driver is on. * @deprecated */ @Deprecated public static final String POWER_BLUETOOTH_ON = "bluetooth.on"; /** * Power consumption when Bluetooth driver is transmitting/receiving. * @deprecated */ @Deprecated public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active"; /** * Power consumption when Bluetooth driver gets an AT command. * @deprecated */ @Deprecated public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at"; /** * Power consumption when screen is on, not including the backlight power. */ public static final String POWER_SCREEN_ON = "screen.on"; /** * Power consumption when cell radio is on but not on a call. */ public static final String POWER_RADIO_ON = "radio.on"; /** * Power consumption when cell radio is hunting for a signal. */ public static final String POWER_RADIO_SCANNING = "radio.scanning"; /** * Power consumption when talking on the phone. */ public static final String POWER_RADIO_ACTIVE = "radio.active"; /** * Power consumption at full backlight brightness. If the backlight is at * 50% brightness, then this should be multiplied by 0.5 */ public static final String POWER_SCREEN_FULL = "screen.full"; /** * Power consumed by the audio hardware when playing back audio content. This is in addition * to the CPU power, probably due to a DSP and / or amplifier. */ public static final String POWER_AUDIO = "dsp.audio"; /** * Power consumed by any media hardware when playing back video content. This is in addition * to the CPU power, probably due to a DSP. */ public static final String POWER_VIDEO = "dsp.video"; /** * Average power consumption when camera flashlight is on. */ public static final String POWER_FLASHLIGHT = "camera.flashlight"; /** * Average power consumption when the camera is on over all standard use cases. * * TODO: Add more fine-grained camera power metrics. */ public static final String POWER_CAMERA = "camera.avg"; @Deprecated public static final String POWER_CPU_SPEEDS = "cpu.speeds"; /** * Power consumed by wif batched scaning. Broken down into bins by * Channels Scanned per Hour. May do 1-720 scans per hour of 1-100 channels * for a range of 1-72,000. Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)! */ public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan"; /** * Battery capacity in milliAmpHour (mAh). */ public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; static final HashMap<String, Object> sPowerMap = new HashMap<>(); private static final String TAG_DEVICE = "device"; private static final String TAG_ITEM = "item"; private static final String TAG_ARRAY = "array"; private static final String TAG_ARRAYITEM = "value"; private static final String ATTR_NAME = "name"; public PowerProfile(Context context) { // Read the XML file for the given profile (normally only one per // device) if (sPowerMap.size() == 0) { readPowerValuesFromXml(context); } initCpuClusters(); } /** * 解析 power_profile.xml檔案 */ private void readPowerValuesFromXml(Context context) { int id = com.android.internal.R.xml.power_profile; final Resources resources = context.getResources(); XmlResourceParser parser = resources.getXml(id); boolean parsingArray = false; ArrayList<Double> array = new ArrayList<Double>(); String arrayName = null; try { XmlUtils.beginDocument(parser, TAG_DEVICE); while (true) { XmlUtils.nextElement(parser); String element = parser.getName(); if (element == null) break; if (parsingArray && !element.equals(TAG_ARRAYITEM)) { // Finish array sPowerMap.put(arrayName, array.toArray(new Double[array.size()])); parsingArray = false; } if (element.equals(TAG_ARRAY)) { parsingArray = true; array.clear(); arrayName = parser.getAttributeValue(null, ATTR_NAME); } else if (element.equals(TAG_ITEM) || element.equals(TAG_ARRAYITEM)) { String name = null; if (!parsingArray) name = parser.getAttributeValue(null, ATTR_NAME); if (parser.next() == XmlPullParser.TEXT) { String power = parser.getText(); double value = 0; try { value = Double.valueOf(power); } catch (NumberFormatException nfe) { } if (element.equals(TAG_ITEM)) { sPowerMap.put(name, value); } else if (parsingArray) { array.add(value); } } } } if (parsingArray) { sPowerMap.put(arrayName, array.toArray(new Double[array.size()])); } } catch (XmlPullParserException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } finally { parser.close(); } // Now collect other config variables. int[] configResIds = new int[]{ com.android.internal.R.integer.config_bluetooth_idle_cur_ma, com.android.internal.R.integer.config_bluetooth_rx_cur_ma, com.android.internal.R.integer.config_bluetooth_tx_cur_ma, com.android.internal.R.integer.config_bluetooth_operating_voltage_mv, com.android.internal.R.integer.config_wifi_idle_receive_cur_ma, com.android.internal.R.integer.config_wifi_active_rx_cur_ma, com.android.internal.R.integer.config_wifi_tx_cur_ma, com.android.internal.R.integer.config_wifi_operating_voltage_mv, }; String[] configResIdKeys = new String[]{ POWER_BLUETOOTH_CONTROLLER_IDLE, POWER_BLUETOOTH_CONTROLLER_RX, POWER_BLUETOOTH_CONTROLLER_TX, POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE, POWER_WIFI_CONTROLLER_IDLE, POWER_WIFI_CONTROLLER_RX, POWER_WIFI_CONTROLLER_TX, POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE, }; for (int i = 0; i < configResIds.length; i++) { String key = configResIdKeys[i]; // if we already have some of these parameters in power_profile.xml, ignore the // value in config.xml if ((sPowerMap.containsKey(key) && (Double) sPowerMap.get(key) > 0)) { continue; } int value = resources.getInteger(configResIds[i]); if (value > 0) { sPowerMap.put(key, (double) value); } } for (Entry<String, Object> item : sPowerMap.entrySet()) { Log.d("CpuPowerCalculator", "sPowerMap key = " + item.getKey() + ", value = " + item.getValue()); } } // CPU 群簇資訊 private CpuClusterKey[] mCpuClusters; private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores"; private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster"; private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster"; @SuppressWarnings("deprecated") private void initCpuClusters() { // Figure out how many CPU clusters we're dealing with /* <array name="cpu.clusters.cores"> <value>4</value> <value>4</value> </array> */ final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT); // 獲取CPU核數資訊 if (obj == null || !(obj instanceof Double[])) { // Default to single. mCpuClusters = new CpuClusterKey[1]; mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1); } else { // 例如 定義了 2 組 Double[]的資料,每組Double[]為4 final Double[] array = (Double[]) obj; // 對 CPU 群簇資訊 進行分組 mCpuClusters = new CpuClusterKey[array.length]; for (int cluster = 0/* 從CPU 群簇 0 開始*/; cluster < array.length/* array.length = 2 */; cluster++) { // 計算每個CPU 群簇資訊的核數,實際中可以得到分為2個CPU 群簇,每個群簇有4和CPU核數 // Math.round(array[cluster]) = Math.round(array[0]) = Math.round(4) = 4 // Math.round(array[cluster]) = Math.round(array[1]) = Math.round(4) = 4 int numCpusInCluster = (int) Math.round(array[cluster]); mCpuClusters[cluster] = new CpuClusterKey( POWER_CPU_CLUSTER_SPEED_PREFIX + cluster, POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster, numCpusInCluster); } } } public static class CpuClusterKey { private final String timeKey; private final String powerKey; private final int numCpus; // timeKey CPU 群簇的頻率檔位 cpu.speeds.cluster[0或1] // powerKey CPU 群簇的頻率單位對應的耗電資訊 cpu.active.cluster[0或1] // numCpus CPU 群簇的核數資訊 private CpuClusterKey(String timeKey, String powerKey, int numCpus) { this.timeKey = timeKey; this.powerKey = powerKey; this.numCpus = numCpus; } } /** * 獲取CPU 群簇的長度大小 */ public int getNumCpuClusters() { return mCpuClusters.length; } /** * 獲取CPU 群簇[下標].核數數量長度大小 * 例如 cluster 0 has cpu0, cpu1, cpu2, cpu3 */ public int getNumCoresInCpuCluster(int index) { return mCpuClusters[index].numCpus; } /** * 獲取CPU 群簇[下標].可用頻率檔位數量長度大小 * 例如 cluster 0 has 156 、400、MHz CPU speed */ public int getNumSpeedStepsInCpuCluster(int index) { Object value = sPowerMap.get(mCpuClusters[index].timeKey); if (value != null && value instanceof Double[]) { return ((Double[])value).length; } return 1; // Only one speed } /** * 獲取cpu.active.cluster[cluster].[step] 對應下標的CPU耗電資訊 * 例如cpu.active.cluster0下第0下標的電流為100 mA */ public double getAveragePowerForCpu(int cluster, int step) { if (cluster >= 0 && cluster < mCpuClusters.length) { return getAveragePower(mCpuClusters[cluster].powerKey, step); } return 0; } /** * Returns the average current in mA consumed by the subsystem, or the given * default value if the subsystem has no recorded value. * @param type the subsystem type * @param defaultValue the value to return if the subsystem has no recorded value. * @return the average current in milliAmps. */ /** * 獲取key值為type下對應的電流,非平均電流誤導 */ public double getAveragePowerOrDefault(String type, double defaultValue) { if (sPowerMap.containsKey(type)) { Object data = sPowerMap.get(type); if (data instanceof Double[]) { // 這個介面實際獲取的是cpu.active.cluster[type]下第0下標的電流 return ((Double[])data)[0]; } else { // 獲取對應type下配置的電流 return (Double) sPowerMap.get(type); } } else { return defaultValue; } } /** * Returns the average current in mA consumed by the subsystem * @param type the subsystem type * @return the average current in milliAmps. */ /** * 獲取key值為type下對應的電流,非平均電流誤導 */ public double getAveragePower(String type) { return getAveragePowerOrDefault(type, 0); } /** * Returns the average current in mA consumed by the subsystem for the given level. * @param type the subsystem type * @param level the level of power at which the subsystem is running. For instance, the * signal strength of the cell network between 0 and 4 (if there are 4 bars max.) * If there is no data for multiple levels, the level is ignored. * @return the average current in milliAmps. */ /** * 獲取平均電流 * 如果type型別是陣列,則獲取對應陣列下標level的對應電流,記錄 * 例如<array name="cpu.active.cluster0"> <value>100</value> * 如果type類是普通子項,直接返回電流即可 * 例如<item name="cpu.idle">6</item> * */ public double getAveragePower(String type, int level) { if (sPowerMap.containsKey(type)) { Object data = sPowerMap.get(type); if (data instanceof Double[]) { final Double[] values = (Double[]) data; if (values.length > level && level >= 0) { return values[level]; } else if (level < 0 || values.length == 0) { return 0; } else { return values[values.length - 1]; } } else { return (Double) data; } } else { return 0; } } /** * Returns the battery capacity, if available, in milli Amp Hours. If not available, * it returns zero. * @return the battery capacity in mAh */ /** * 獲取電池容量 */ public double getBatteryCapacity() { return getAveragePower(POWER_BATTERY_CAPACITY); } }
解析物件-power_profile.xml
原始碼路徑
frameworks/base/core/res/res/xml/power_profile.xml
<?xml version="1.0" encoding="utf-8"?> <!-- ** ** Copyright 2009, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License") ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ --> <device name="Android"> <!-- Most values are the incremental current used by a feature, in mA (measured at nominal voltage). The default values are deliberately incorrect dummy values. OEM's must measure and provide actual values before shipping a device. Example real-world values are given in comments, but they are totally dependent on the platform and can vary significantly, so should be measured on the shipping platform with a power meter. --> <item name="none">0</item> <item name="screen.on">223</item> <!-- ~200mA --> <item name="screen.full">350</item> <!-- ~300mA --> <item name="bluetooth.active">66</item> <!-- Bluetooth data transfer, ~10mA --> <item name="bluetooth.on">1</item> <!-- Bluetooth on & connectable, but not connected, ~0.1mA --> <item name="wifi.on">2.1</item> <!-- ~3mA --> <item name="wifi.active">200</item> <!-- WIFI data transfer, ~200mA --> <item name="wifi.scan">100</item> <!-- WIFI network scanning, ~100mA --> <item name="dsp.audio">100</item> <!-- ~10mA --> <item name="dsp.video">50</item> <!-- ~50mA --> <item name="camera.flashlight">142</item> <!-- Avg. power for camera flash, ~160mA --> <item name="camera.avg">599</item> <!-- Avg. power use of camera in standard usecases, ~550mA --> <!-- Radio related values. For modems without energy reporting support in firmware, use radio.active, radio.scanning, and radio.on. --> <item name="radio.active">200</item> <!-- ~200mA --> <item name="radio.scanning">10</item> <!-- cellular radio scanning for signal, ~10mA --> <item name="gps.on">50</item> <!-- ~50mA --> <!-- Current consumed by the radio at different signal strengths, when paging --> <array name="radio.on"> <!-- Strength 0 to BINS-1 --> <value>2</value> <!-- ~2mA --> <value>1</value> <!-- ~1mA --> </array> <!-- Radio related values. For modems WITH energy reporting support in firmware, use modem.controller.idle, modem.controller.tx, modem.controller.rx, modem.controller.voltage. --> <item name="modem.controller.idle">0</item> <item name="modem.controller.rx">0</item> <item name="modem.controller.tx">0</item> <item name="modem.controller.voltage">0</item> <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the number of CPU cores for that cluster. Ex: <array name="cpu.clusters.cores"> <value>4</value> // cluster 0 has cpu0, cpu1, cpu2, cpu3 <value>2</value> // cluster 1 has cpu4, cpu5 </array> --> <array name="cpu.clusters.cores"> <value>4</value> <value>4</value> </array> <!-- Different CPU speeds for cluster 0 as reported in /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state. There must be one of these for each cluster, labeled: cpu.speeds.cluster0, cpu.speeds.cluster1, etc...--> <array name="cpu.speeds.cluster0"> <value>156000</value> <!-- 156 MHz CPU speed --> <value>286000</value> <!-- 286 MHz CPU speed --> <value>338000</value> <!-- 338 MHz CPU speed --> <value>494000</value> <!-- 494 MHz CPU speed --> <value>598000</value> <!-- 598 MHz CPU speed --> <value>663000</value> <!-- 663 MHz CPU speed --> <value>689000</value> <!-- 689 MHz CPU speed --> <value>819000</value> <!-- 819 MHz CPU speed --> <value>871000</value> <!-- 871 MHz CPU speed --> <value>910000</value> <!-- 910 MHz CPU speed --> <value>1001000</value> <!-- 1001 MHz CPU speed --> <value>1027000</value> <!-- 1027 MHz CPU speed --> <value>1196000</value> <!-- 1196 MHz CPU speed --> <value>1352000</value> <!-- 1352 MHz CPU speed --> <value>1430000</value> <!-- 1430 MHz CPU speed --> <value>1508000</value> <!-- 1508 MHz CPU speed --> </array> <array name="cpu.speeds.cluster1"> <value>156000</value> <!-- 156 MHz CPU speed --> <value>286000</value> <!-- 286 MHz CPU speed --> <value>338000</value> <!-- 338 MHz CPU speed --> <value>494000</value> <!-- 494 MHz CPU speed --> <value>598000</value> <!-- 598 MHz CPU speed --> <value>663000</value> <!-- 663 MHz CPU speed --> <value>689000</value> <!-- 689 MHz CPU speed --> <value>819000</value> <!-- 819 MHz CPU speed --> <value>871000</value> <!-- 871 MHz CPU speed --> <value>910000</value> <!-- 910 MHz CPU speed --> <value>1001000</value> <!-- 1001 MHz CPU speed --> <value>1027000</value> <!-- 1027 MHz CPU speed --> <value>1196000</value> <!-- 1196 MHz CPU speed --> <value>1352000</value> <!-- 1352 MHz CPU speed --> <value>1430000</value> <!-- 1430 MHz CPU speed --> <value>1508000</value> <!-- 1508 MHz CPU speed --> </array> <!-- Current when CPU is idle --> <item name="cpu.idle">6</item> <!-- Current at each CPU speed, as per 'cpu.speeds' --> <array name="cpu.active"> <value>100</value> </array> <!-- Current at each CPU speed for cluster 0, as per 'cpu.speeds.cluster0'. Like cpu.speeds.cluster0, there must be one of these present for each heterogeneous CPU cluster. --> <array name="cpu.active.cluster0"> <value>100</value> <value>113</value> <value>124</value> <value>135</value> <value>146</value> <value>151</value> <value>162</value> <value>171</value> <value>182</value> <value>193</value> <value>201</value> <value>213</value> <value>222</value> <value>231</value> <value>241</value> <value>250</value> </array> <array name="cpu.active.cluster1"> <value>100</value> <value>113</value> <value>124</value> <value>135</value> <value>146</value> <value>151</value> <value>162</value> <value>171</value> <value>182</value> <value>193</value> <value>201</value> <value>213</value> <value>222</value> <value>231</value> <value>241</value> <value>250</value> </array> <!-- This is the battery capacity in mAh (measured at nominal voltage) --> <item name="battery.capacity">3500</item> <!-- Wifi related values. --> <!-- Idle Receive current for wifi radio in mA. 0 by default--> <item name="wifi.controller.idle">0</item> <!-- Rx current for wifi radio in mA. 0 by default--> <item name="wifi.controller.rx">0</item> <!-- Tx current for wifi radio in mA. 0 by default--> <item name="wifi.controller.tx">0</item> <!-- Current at each of the wifi Tx levels in mA. The number of tx levels varies per device and is available only of wifi chipsets which support the tx level reporting. Use wifi.tx for other chipsets. none by default --> <array name="wifi.controller.tx_levels"> <!-- mA --> </array> <!-- Operating volatage for wifi radio in mV. 0 by default--> <item name="wifi.controller.voltage">0</item> <array name="wifi.batchedscan"> <!-- mA --> <value>.2</value> <!-- 1-8/hr --> <value>2</value> <!-- 9-64/hr --> <value>20</value> <!-- 65-512/hr --> <value>200</value> <!-- 513-4,096/hr --> <value>500</value> <!-- 4097-/hr --> </array> </device>