1215 lines
46 KiB
Java
1215 lines
46 KiB
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.annotation.LongDef;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.StringDef;
|
|
import android.annotation.XmlRes;
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.content.Context;
|
|
import android.content.res.Resources;
|
|
import android.content.res.XmlResourceParser;
|
|
import android.util.IndentingPrintWriter;
|
|
import android.util.Slog;
|
|
import android.util.SparseArray;
|
|
import android.util.proto.ProtoOutputStream;
|
|
|
|
import com.android.internal.annotations.GuardedBy;
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
import com.android.internal.power.ModemPowerProfile;
|
|
import com.android.internal.util.XmlUtils;
|
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
import org.xmlpull.v1.XmlPullParserException;
|
|
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
|
|
/**
|
|
* Reports power consumption values for various device activities. Reads values from an XML file.
|
|
* Customize the XML file for different devices.
|
|
* [hidden]
|
|
*/
|
|
@android.ravenwood.annotation.RavenwoodKeepWholeClass
|
|
public class PowerProfile {
|
|
|
|
public static final String TAG = "PowerProfile";
|
|
|
|
/*
|
|
* POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode.
|
|
* POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should
|
|
* be zero 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_SUSPEND due to a wake lock being held but with no CPU activity.
|
|
* POWER_CPU_ACTIVE: Power consumption when CPU is running, excluding power consumed by clusters
|
|
* and cores.
|
|
*
|
|
* CPU Power Equation (assume two clusters):
|
|
* Total power = POWER_CPU_SUSPEND (always added)
|
|
* + POWER_CPU_IDLE (skip this and below if in power collapse mode)
|
|
* + POWER_CPU_ACTIVE (skip this and below if CPU is not running, but a wakelock
|
|
* is held)
|
|
* + cluster_power.cluster0 + cluster_power.cluster1 (skip cluster not running)
|
|
* + core_power.cluster0 * num running cores in cluster 0
|
|
* + core_power.cluster1 * num running cores in cluster 1
|
|
*/
|
|
public static final String POWER_CPU_SUSPEND = "cpu.suspend";
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_CPU_IDLE = "cpu.idle";
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_CPU_ACTIVE = "cpu.active";
|
|
|
|
/**
|
|
* Power consumption when WiFi driver is scanning for networks.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_WIFI_SCAN = "wifi.scan";
|
|
|
|
/**
|
|
* Power consumption when WiFi driver is on.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_WIFI_ON = "wifi.on";
|
|
|
|
/**
|
|
* Power consumption when WiFi driver is transmitting/receiving.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
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_SLEEP = "modem.controller.sleep";
|
|
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.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_GPS_ON = "gps.on";
|
|
|
|
/**
|
|
* GPS power parameters based on signal quality
|
|
*/
|
|
public static final String POWER_GPS_SIGNAL_QUALITY_BASED = "gps.signalqualitybased";
|
|
public static final String POWER_GPS_OPERATING_VOLTAGE = "gps.voltage";
|
|
|
|
/**
|
|
* Power consumption when Bluetooth driver is on.
|
|
*
|
|
* @deprecated
|
|
*/
|
|
@Deprecated
|
|
@UnsupportedAppUsage
|
|
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
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
|
|
|
|
/**
|
|
* Power consumption when screen is in doze/ambient/always-on mode, including backlight power.
|
|
*
|
|
* @deprecated Use {@link #POWER_GROUP_DISPLAY_AMBIENT} instead.
|
|
*/
|
|
@Deprecated
|
|
public static final String POWER_AMBIENT_DISPLAY = "ambient.on";
|
|
|
|
/**
|
|
* Power consumption when screen is on, not including the backlight power.
|
|
*
|
|
* @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_ON} instead.
|
|
*/
|
|
@Deprecated
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_SCREEN_ON = "screen.on";
|
|
|
|
/**
|
|
* Power consumption when cell radio is on but not on a call.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_RADIO_ON = "radio.on";
|
|
|
|
/**
|
|
* Power consumption when cell radio is hunting for a signal.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public static final String POWER_RADIO_SCANNING = "radio.scanning";
|
|
|
|
/**
|
|
* Power consumption when talking on the phone.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
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
|
|
*
|
|
* @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_FULL} instead.
|
|
*/
|
|
@Deprecated
|
|
@UnsupportedAppUsage
|
|
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 = "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 = "video";
|
|
|
|
/**
|
|
* Average power consumption when camera flashlight is on.
|
|
*/
|
|
public static final String POWER_FLASHLIGHT = "camera.flashlight";
|
|
|
|
/**
|
|
* Power consumption when DDR is being used.
|
|
*/
|
|
public static final String POWER_MEMORY = "memory.bandwidths";
|
|
|
|
/**
|
|
* 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";
|
|
|
|
/**
|
|
* 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";
|
|
|
|
/**
|
|
* Power consumption when a screen is in doze/ambient/always-on mode, including backlight power.
|
|
*/
|
|
public static final String POWER_GROUP_DISPLAY_AMBIENT = "ambient.on.display";
|
|
|
|
/**
|
|
* Power consumption when a screen is on, not including the backlight power.
|
|
*/
|
|
public static final String POWER_GROUP_DISPLAY_SCREEN_ON = "screen.on.display";
|
|
|
|
/**
|
|
* Power consumption of a screen at full backlight brightness.
|
|
*/
|
|
public static final String POWER_GROUP_DISPLAY_SCREEN_FULL = "screen.full.display";
|
|
|
|
@StringDef(prefix = { "POWER_GROUP_" }, value = {
|
|
POWER_GROUP_DISPLAY_AMBIENT,
|
|
POWER_GROUP_DISPLAY_SCREEN_ON,
|
|
POWER_GROUP_DISPLAY_SCREEN_FULL,
|
|
})
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
public @interface PowerGroup {}
|
|
|
|
/**
|
|
* Constants for generating a 64bit power constant key.
|
|
*
|
|
* The bitfields of a key describes what its corresponding power constant represents:
|
|
* [63:40] - RESERVED
|
|
* [39:32] - {@link Subsystem} (max count = 16).
|
|
* [31:0] - per Subsystem fields, see {@link ModemPowerProfile}.
|
|
*
|
|
*/
|
|
private static final long SUBSYSTEM_MASK = 0xF_0000_0000L;
|
|
/**
|
|
* Power constant not associated with a subsystem.
|
|
*/
|
|
public static final long SUBSYSTEM_NONE = 0x0_0000_0000L;
|
|
/**
|
|
* Modem power constant.
|
|
*/
|
|
public static final long SUBSYSTEM_MODEM = 0x1_0000_0000L;
|
|
|
|
@LongDef(prefix = { "SUBSYSTEM_" }, value = {
|
|
SUBSYSTEM_NONE,
|
|
SUBSYSTEM_MODEM,
|
|
})
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
public @interface Subsystem {}
|
|
|
|
private static final long SUBSYSTEM_FIELDS_MASK = 0xFFFF_FFFF;
|
|
|
|
public static final int POWER_BRACKETS_UNSPECIFIED = -1;
|
|
|
|
/**
|
|
* A map from Power Use Item to its power consumption.
|
|
*/
|
|
static final HashMap<String, Double> sPowerItemMap = new HashMap<>();
|
|
/**
|
|
* A map from Power Use Item to an array of its power consumption
|
|
* (for items with variable power e.g. CPU).
|
|
*/
|
|
static final HashMap<String, Double[]> sPowerArrayMap = new HashMap<>();
|
|
|
|
static final ModemPowerProfile sModemPowerProfile = new ModemPowerProfile();
|
|
|
|
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";
|
|
|
|
private static final String TAG_MODEM = "modem";
|
|
|
|
private static final Object sLock = new Object();
|
|
|
|
private int mCpuPowerBracketCount;
|
|
|
|
@VisibleForTesting
|
|
public PowerProfile() {
|
|
synchronized (sLock) {
|
|
initLocked();
|
|
}
|
|
}
|
|
|
|
@VisibleForTesting
|
|
@UnsupportedAppUsage
|
|
public PowerProfile(Context context) {
|
|
this(context, false);
|
|
}
|
|
|
|
/**
|
|
* For PowerProfileTest
|
|
*/
|
|
@VisibleForTesting
|
|
public PowerProfile(Context context, boolean forTest) {
|
|
// Read the XML file for the given profile (normally only one per device)
|
|
synchronized (sLock) {
|
|
final int xmlId = forTest ? com.android.internal.R.xml.power_profile_test
|
|
: com.android.internal.R.xml.power_profile;
|
|
initLocked(context, xmlId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reinitialize the PowerProfile with the provided XML.
|
|
* WARNING: use only for testing!
|
|
*/
|
|
@VisibleForTesting
|
|
public void initForTesting(XmlPullParser parser) {
|
|
initForTesting(parser, null);
|
|
}
|
|
|
|
/**
|
|
* Reinitialize the PowerProfile with the provided XML, using optional Resources for fallback
|
|
* configuration settings.
|
|
* WARNING: use only for testing!
|
|
*/
|
|
@VisibleForTesting
|
|
public void initForTesting(XmlPullParser parser, @Nullable Resources resources) {
|
|
synchronized (sLock) {
|
|
sPowerItemMap.clear();
|
|
sPowerArrayMap.clear();
|
|
sModemPowerProfile.clear();
|
|
|
|
try {
|
|
readPowerValuesFromXml(parser, resources);
|
|
} finally {
|
|
if (parser instanceof XmlResourceParser) {
|
|
((XmlResourceParser) parser).close();
|
|
}
|
|
}
|
|
initLocked();
|
|
}
|
|
}
|
|
|
|
@GuardedBy("sLock")
|
|
private void initLocked(Context context, @XmlRes int xmlId) {
|
|
if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) {
|
|
final Resources resources = context.getResources();
|
|
XmlResourceParser parser = resources.getXml(xmlId);
|
|
readPowerValuesFromXml(parser, resources);
|
|
}
|
|
initLocked();
|
|
}
|
|
|
|
private void initLocked() {
|
|
initCpuClusters();
|
|
initCpuScalingPolicies();
|
|
initCpuPowerBrackets();
|
|
initDisplays();
|
|
initModem();
|
|
}
|
|
|
|
private static void readPowerValuesFromXml(XmlPullParser parser,
|
|
@Nullable Resources resources) {
|
|
boolean parsingArray = false;
|
|
ArrayList<Double> array = new ArrayList<>();
|
|
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
|
|
sPowerArrayMap.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)) {
|
|
sPowerItemMap.put(name, value);
|
|
} else if (parsingArray) {
|
|
array.add(value);
|
|
}
|
|
}
|
|
} else if (element.equals(TAG_MODEM)) {
|
|
sModemPowerProfile.parseFromXml(parser);
|
|
}
|
|
}
|
|
if (parsingArray) {
|
|
sPowerArrayMap.put(arrayName, array.toArray(new Double[array.size()]));
|
|
}
|
|
} catch (XmlPullParserException e) {
|
|
throw new RuntimeException(e);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
} finally {
|
|
if (parser instanceof XmlResourceParser) {
|
|
((XmlResourceParser) parser).close();
|
|
}
|
|
}
|
|
|
|
if (resources != null) {
|
|
getDefaultValuesFromConfig(resources);
|
|
}
|
|
}
|
|
|
|
private static void getDefaultValuesFromConfig(Resources resources) {
|
|
// 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,
|
|
};
|
|
|
|
String[] configResIdKeys = new String[]{
|
|
POWER_BLUETOOTH_CONTROLLER_IDLE,
|
|
POWER_BLUETOOTH_CONTROLLER_RX,
|
|
POWER_BLUETOOTH_CONTROLLER_TX,
|
|
POWER_BLUETOOTH_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 ((sPowerItemMap.containsKey(key) && sPowerItemMap.get(key) > 0)) {
|
|
continue;
|
|
}
|
|
int value = resources.getInteger(configResIds[i]);
|
|
if (value > 0) {
|
|
sPowerItemMap.put(key, (double) value);
|
|
}
|
|
}
|
|
}
|
|
|
|
private CpuClusterKey[] mCpuClusters;
|
|
|
|
private static final String CPU_PER_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
|
|
private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster";
|
|
private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster";
|
|
private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster";
|
|
private static final String CPU_POWER_BRACKETS_PREFIX = "cpu.power_brackets.policy";
|
|
|
|
private void initCpuClusters() {
|
|
if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
|
|
final Double[] data = sPowerArrayMap.get(CPU_PER_CLUSTER_CORE_COUNT);
|
|
mCpuClusters = new CpuClusterKey[data.length];
|
|
for (int cluster = 0; cluster < data.length; cluster++) {
|
|
int numCpusInCluster = (int) Math.round(data[cluster]);
|
|
mCpuClusters[cluster] = new CpuClusterKey(
|
|
CPU_CORE_SPEED_PREFIX + cluster, CPU_CLUSTER_POWER_COUNT + cluster,
|
|
CPU_CORE_POWER_PREFIX + cluster, numCpusInCluster);
|
|
}
|
|
} else {
|
|
// Default to single.
|
|
mCpuClusters = new CpuClusterKey[1];
|
|
int numCpus = 1;
|
|
if (sPowerItemMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
|
|
numCpus = (int) Math.round(sPowerItemMap.get(CPU_PER_CLUSTER_CORE_COUNT));
|
|
}
|
|
mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0,
|
|
CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus);
|
|
}
|
|
}
|
|
|
|
private SparseArray<CpuScalingPolicyPower> mCpuScalingPolicies;
|
|
private static final String CPU_SCALING_POLICY_POWER_POLICY = "cpu.scaling_policy_power.policy";
|
|
private static final String CPU_SCALING_STEP_POWER_POLICY = "cpu.scaling_step_power.policy";
|
|
|
|
private void initCpuScalingPolicies() {
|
|
int policyCount = 0;
|
|
for (String key : sPowerItemMap.keySet()) {
|
|
if (key.startsWith(CPU_SCALING_POLICY_POWER_POLICY)) {
|
|
int policy =
|
|
Integer.parseInt(key.substring(CPU_SCALING_POLICY_POWER_POLICY.length()));
|
|
policyCount = Math.max(policyCount, policy + 1);
|
|
}
|
|
}
|
|
for (String key : sPowerArrayMap.keySet()) {
|
|
if (key.startsWith(CPU_SCALING_STEP_POWER_POLICY)) {
|
|
int policy =
|
|
Integer.parseInt(key.substring(CPU_SCALING_STEP_POWER_POLICY.length()));
|
|
policyCount = Math.max(policyCount, policy + 1);
|
|
}
|
|
}
|
|
|
|
if (policyCount > 0) {
|
|
mCpuScalingPolicies = new SparseArray<>(policyCount);
|
|
for (int policy = 0; policy < policyCount; policy++) {
|
|
Double policyPower = sPowerItemMap.get(CPU_SCALING_POLICY_POWER_POLICY + policy);
|
|
Double[] stepPower = sPowerArrayMap.get(CPU_SCALING_STEP_POWER_POLICY + policy);
|
|
if (policyPower != null || stepPower != null) {
|
|
double[] primitiveStepPower;
|
|
if (stepPower != null) {
|
|
primitiveStepPower = new double[stepPower.length];
|
|
for (int i = 0; i < stepPower.length; i++) {
|
|
primitiveStepPower[i] = stepPower[i];
|
|
}
|
|
} else {
|
|
primitiveStepPower = new double[0];
|
|
}
|
|
mCpuScalingPolicies.put(policy, new CpuScalingPolicyPower(
|
|
policyPower != null ? policyPower : 0, primitiveStepPower));
|
|
}
|
|
}
|
|
} else {
|
|
// Legacy power_profile.xml
|
|
int cpuId = 0;
|
|
for (CpuClusterKey cpuCluster : mCpuClusters) {
|
|
policyCount = cpuId + 1;
|
|
cpuId += cpuCluster.numCpus;
|
|
}
|
|
|
|
if (policyCount > 0) {
|
|
mCpuScalingPolicies = new SparseArray<>(policyCount);
|
|
cpuId = 0;
|
|
for (CpuClusterKey cpuCluster : mCpuClusters) {
|
|
double clusterPower = getAveragePower(cpuCluster.clusterPowerKey);
|
|
double[] stepPower;
|
|
int numSteps = getNumElements(cpuCluster.corePowerKey);
|
|
if (numSteps != 0) {
|
|
stepPower = new double[numSteps];
|
|
for (int step = 0; step < numSteps; step++) {
|
|
stepPower[step] = getAveragePower(cpuCluster.corePowerKey, step);
|
|
}
|
|
} else {
|
|
stepPower = new double[1];
|
|
}
|
|
mCpuScalingPolicies.put(cpuId,
|
|
new CpuScalingPolicyPower(clusterPower, stepPower));
|
|
cpuId += cpuCluster.numCpus;
|
|
}
|
|
} else {
|
|
mCpuScalingPolicies = new SparseArray<>(1);
|
|
mCpuScalingPolicies.put(0,
|
|
new CpuScalingPolicyPower(getAveragePower(POWER_CPU_ACTIVE),
|
|
new double[]{0}));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses or computes CPU power brackets: groups of states with similar power requirements.
|
|
*/
|
|
private void initCpuPowerBrackets() {
|
|
boolean anyBracketsSpecified = false;
|
|
boolean allBracketsSpecified = true;
|
|
for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
|
|
int policy = mCpuScalingPolicies.keyAt(i);
|
|
CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
|
|
final int steps = cpuScalingPolicyPower.stepPower.length;
|
|
cpuScalingPolicyPower.powerBrackets = new int[steps];
|
|
if (sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + policy) != null) {
|
|
anyBracketsSpecified = true;
|
|
} else {
|
|
allBracketsSpecified = false;
|
|
}
|
|
}
|
|
if (anyBracketsSpecified && !allBracketsSpecified) {
|
|
throw new RuntimeException(
|
|
"Power brackets should be specified for all scaling policies or none");
|
|
}
|
|
|
|
if (!allBracketsSpecified) {
|
|
mCpuPowerBracketCount = POWER_BRACKETS_UNSPECIFIED;
|
|
return;
|
|
}
|
|
|
|
mCpuPowerBracketCount = 0;
|
|
for (int i = mCpuScalingPolicies.size() - 1; i >= 0; i--) {
|
|
int policy = mCpuScalingPolicies.keyAt(i);
|
|
CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.valueAt(i);
|
|
final Double[] data = sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + policy);
|
|
if (data.length != cpuScalingPolicyPower.powerBrackets.length) {
|
|
throw new RuntimeException(
|
|
"Wrong number of items in " + CPU_POWER_BRACKETS_PREFIX + policy
|
|
+ ", expected: "
|
|
+ cpuScalingPolicyPower.powerBrackets.length);
|
|
}
|
|
|
|
for (int j = 0; j < data.length; j++) {
|
|
final int bracket = (int) Math.round(data[j]);
|
|
cpuScalingPolicyPower.powerBrackets[j] = bracket;
|
|
if (bracket > mCpuPowerBracketCount) {
|
|
mCpuPowerBracketCount = bracket;
|
|
}
|
|
}
|
|
}
|
|
mCpuPowerBracketCount++;
|
|
}
|
|
|
|
private static class CpuScalingPolicyPower {
|
|
public final double policyPower;
|
|
public final double[] stepPower;
|
|
public int[] powerBrackets;
|
|
|
|
private CpuScalingPolicyPower(double policyPower, double[] stepPower) {
|
|
this.policyPower = policyPower;
|
|
this.stepPower = stepPower;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the average additional power in (mA) when the CPU scaling policy <code>policy</code>
|
|
* is used.
|
|
*
|
|
* @param policy Policy ID as per <code>ls /sys/devices/system/cpu/cpufreq</code>. Typically,
|
|
* policy ID corresponds to the index of the first related CPU, e.g. for "policy6"
|
|
* <code>/sys/devices/system/cpu/cpufreq/policy6/related_cpus</code> will
|
|
* contain CPU IDs like <code>6, 7</code>
|
|
*/
|
|
public double getAveragePowerForCpuScalingPolicy(int policy) {
|
|
CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.get(policy);
|
|
if (cpuScalingPolicyPower != null) {
|
|
return cpuScalingPolicyPower.policyPower;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the average additional power in (mA) when the CPU scaling policy <code>policy</code>
|
|
* is used at the <code>step</code> frequency step (this is not the frequency itself, but the
|
|
* integer index of the frequency step).
|
|
*/
|
|
public double getAveragePowerForCpuScalingStep(int policy, int step) {
|
|
CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.get(policy);
|
|
if (cpuScalingPolicyPower != null
|
|
&& step >= 0 && step < cpuScalingPolicyPower.stepPower.length) {
|
|
return cpuScalingPolicyPower.stepPower[step];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private static class CpuClusterKey {
|
|
public final String freqKey;
|
|
public final String clusterPowerKey;
|
|
public final String corePowerKey;
|
|
public final int numCpus;
|
|
|
|
private CpuClusterKey(String freqKey, String clusterPowerKey,
|
|
String corePowerKey, int numCpus) {
|
|
this.freqKey = freqKey;
|
|
this.clusterPowerKey = clusterPowerKey;
|
|
this.corePowerKey = corePowerKey;
|
|
this.numCpus = numCpus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use CpuScalingPolicy instead
|
|
*/
|
|
@UnsupportedAppUsage
|
|
@Deprecated
|
|
public int getNumCpuClusters() {
|
|
return mCpuClusters.length;
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use CpuScalingPolicy instead
|
|
*/
|
|
@Deprecated
|
|
public int getNumCoresInCpuCluster(int cluster) {
|
|
if (cluster < 0 || cluster >= mCpuClusters.length) {
|
|
return 0; // index out of bound
|
|
}
|
|
return mCpuClusters[cluster].numCpus;
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use CpuScalingPolicy instead
|
|
*/
|
|
@UnsupportedAppUsage
|
|
@Deprecated
|
|
public int getNumSpeedStepsInCpuCluster(int cluster) {
|
|
if (cluster < 0 || cluster >= mCpuClusters.length) {
|
|
return 0; // index out of bound
|
|
}
|
|
if (sPowerArrayMap.containsKey(mCpuClusters[cluster].freqKey)) {
|
|
return sPowerArrayMap.get(mCpuClusters[cluster].freqKey).length;
|
|
}
|
|
return 1; // Only one speed
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use getAveragePowerForCpuScalingPolicy
|
|
*/
|
|
@Deprecated
|
|
public double getAveragePowerForCpuCluster(int cluster) {
|
|
if (cluster >= 0 && cluster < mCpuClusters.length) {
|
|
return getAveragePower(mCpuClusters[cluster].clusterPowerKey);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use getAveragePowerForCpuScalingStep
|
|
*/
|
|
@Deprecated
|
|
public double getAveragePowerForCpuCore(int cluster, int step) {
|
|
if (cluster >= 0 && cluster < mCpuClusters.length) {
|
|
return getAveragePower(mCpuClusters[cluster].corePowerKey, step);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of CPU power brackets: groups of states with similar power requirements.
|
|
* If power brackets are not specified, returns {@link #POWER_BRACKETS_UNSPECIFIED}
|
|
*/
|
|
public int getCpuPowerBracketCount() {
|
|
return mCpuPowerBracketCount;
|
|
}
|
|
|
|
/**
|
|
* Returns the CPU power bracket corresponding to the specified scaling policy and frequency
|
|
* step
|
|
*/
|
|
public int getCpuPowerBracketForScalingStep(int policy, int step) {
|
|
CpuScalingPolicyPower cpuScalingPolicyPower = mCpuScalingPolicies.get(policy);
|
|
if (cpuScalingPolicyPower != null
|
|
&& step >= 0 && step < cpuScalingPolicyPower.powerBrackets.length) {
|
|
return cpuScalingPolicyPower.powerBrackets[step];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private int mNumDisplays;
|
|
|
|
private void initDisplays() {
|
|
// Figure out how many displays are listed in the power profile.
|
|
mNumDisplays = 0;
|
|
while (!Double.isNaN(
|
|
getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, mNumDisplays, Double.NaN))
|
|
|| !Double.isNaN(
|
|
getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, mNumDisplays, Double.NaN))
|
|
|| !Double.isNaN(
|
|
getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, mNumDisplays,
|
|
Double.NaN))) {
|
|
mNumDisplays++;
|
|
}
|
|
|
|
// Handle legacy display power constants.
|
|
final Double deprecatedAmbientDisplay = sPowerItemMap.get(POWER_AMBIENT_DISPLAY);
|
|
boolean legacy = false;
|
|
if (deprecatedAmbientDisplay != null && mNumDisplays == 0) {
|
|
final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_AMBIENT, 0);
|
|
Slog.w(TAG, POWER_AMBIENT_DISPLAY + " is deprecated! Use " + key + " instead.");
|
|
sPowerItemMap.put(key, deprecatedAmbientDisplay);
|
|
legacy = true;
|
|
}
|
|
|
|
final Double deprecatedScreenOn = sPowerItemMap.get(POWER_SCREEN_ON);
|
|
if (deprecatedScreenOn != null && mNumDisplays == 0) {
|
|
final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_ON, 0);
|
|
Slog.w(TAG, POWER_SCREEN_ON + " is deprecated! Use " + key + " instead.");
|
|
sPowerItemMap.put(key, deprecatedScreenOn);
|
|
legacy = true;
|
|
}
|
|
|
|
final Double deprecatedScreenFull = sPowerItemMap.get(POWER_SCREEN_FULL);
|
|
if (deprecatedScreenFull != null && mNumDisplays == 0) {
|
|
final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_FULL, 0);
|
|
Slog.w(TAG, POWER_SCREEN_FULL + " is deprecated! Use " + key + " instead.");
|
|
sPowerItemMap.put(key, deprecatedScreenFull);
|
|
legacy = true;
|
|
}
|
|
if (legacy) {
|
|
mNumDisplays = 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the number built in displays on the device as defined in the power_profile.xml.
|
|
*/
|
|
public int getNumDisplays() {
|
|
return mNumDisplays;
|
|
}
|
|
|
|
private void initModem() {
|
|
handleDeprecatedModemConstant(ModemPowerProfile.MODEM_DRAIN_TYPE_SLEEP,
|
|
POWER_MODEM_CONTROLLER_SLEEP, 0);
|
|
handleDeprecatedModemConstant(ModemPowerProfile.MODEM_DRAIN_TYPE_IDLE,
|
|
POWER_MODEM_CONTROLLER_IDLE, 0);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_RX,
|
|
POWER_MODEM_CONTROLLER_RX, 0);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX
|
|
| ModemPowerProfile.MODEM_TX_LEVEL_0, POWER_MODEM_CONTROLLER_TX, 0);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX
|
|
| ModemPowerProfile.MODEM_TX_LEVEL_1, POWER_MODEM_CONTROLLER_TX, 1);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX
|
|
| ModemPowerProfile.MODEM_TX_LEVEL_2, POWER_MODEM_CONTROLLER_TX, 2);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX
|
|
| ModemPowerProfile.MODEM_TX_LEVEL_3, POWER_MODEM_CONTROLLER_TX, 3);
|
|
handleDeprecatedModemConstant(
|
|
ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT | ModemPowerProfile.MODEM_DRAIN_TYPE_TX
|
|
| ModemPowerProfile.MODEM_TX_LEVEL_4, POWER_MODEM_CONTROLLER_TX, 4);
|
|
}
|
|
|
|
private void handleDeprecatedModemConstant(int key, String deprecatedKey, int level) {
|
|
final double drain = sModemPowerProfile.getAverageBatteryDrainMa(key);
|
|
if (!Double.isNaN(drain)) return; // Value already set, don't overwrite it.
|
|
|
|
final double deprecatedDrain = getAveragePower(deprecatedKey, level);
|
|
sModemPowerProfile.setPowerConstant(key, Double.toString(deprecatedDrain));
|
|
}
|
|
|
|
/**
|
|
* Returns the number of memory bandwidth buckets defined in power_profile.xml, or a
|
|
* default value if the subsystem has no recorded value.
|
|
*
|
|
* @return the number of memory bandwidth buckets.
|
|
*/
|
|
public int getNumElements(String key) {
|
|
if (sPowerItemMap.containsKey(key)) {
|
|
return 1;
|
|
} else if (sPowerArrayMap.containsKey(key)) {
|
|
return sPowerArrayMap.get(key).length;
|
|
}
|
|
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.
|
|
*/
|
|
public double getAveragePowerOrDefault(String type, double defaultValue) {
|
|
if (sPowerItemMap.containsKey(type)) {
|
|
return sPowerItemMap.get(type);
|
|
} else if (sPowerArrayMap.containsKey(type)) {
|
|
return sPowerArrayMap.get(type)[0];
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the average current in mA consumed by the subsystem
|
|
*
|
|
* @param type the subsystem type
|
|
* @return the average current in milliAmps.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public double getAveragePower(String type) {
|
|
return getAveragePowerOrDefault(type, 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the average current in mA consumed by a subsystem's specified operation, or the given
|
|
* default value if the subsystem has no recorded value.
|
|
*
|
|
* @param key that describes a subsystem's battery draining operation
|
|
* The key is built from multiple constant, see {@link Subsystem} and
|
|
* {@link ModemPowerProfile}.
|
|
* @param defaultValue the value to return if the subsystem has no recorded value.
|
|
* @return the average current in milliAmps.
|
|
*/
|
|
public double getAverageBatteryDrainOrDefaultMa(long key, double defaultValue) {
|
|
final long subsystemType = key & SUBSYSTEM_MASK;
|
|
final int subsystemFields = (int) (key & SUBSYSTEM_FIELDS_MASK);
|
|
|
|
final double value;
|
|
if (subsystemType == SUBSYSTEM_MODEM) {
|
|
value = sModemPowerProfile.getAverageBatteryDrainMa(subsystemFields);
|
|
} else {
|
|
value = Double.NaN;
|
|
}
|
|
|
|
if (Double.isNaN(value)) return defaultValue;
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Returns the average current in mA consumed by a subsystem's specified operation.
|
|
*
|
|
* @param key that describes a subsystem's battery draining operation
|
|
* The key is built from multiple constant, see {@link Subsystem} and
|
|
* {@link ModemPowerProfile}.
|
|
* @return the average current in milliAmps.
|
|
*/
|
|
public double getAverageBatteryDrainMa(long key) {
|
|
return getAverageBatteryDrainOrDefaultMa(key, 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.
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public double getAveragePower(String type, int level) {
|
|
if (sPowerItemMap.containsKey(type)) {
|
|
return sPowerItemMap.get(type);
|
|
} else if (sPowerArrayMap.containsKey(type)) {
|
|
final Double[] values = sPowerArrayMap.get(type);
|
|
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 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the average current in mA consumed by an ordinaled subsystem, or the given
|
|
* default value if the subsystem has no recorded value.
|
|
*
|
|
* @param group the subsystem {@link PowerGroup}.
|
|
* @param ordinal which entity in the {@link PowerGroup}.
|
|
* @param defaultValue the value to return if the subsystem has no recorded value.
|
|
* @return the average current in milliAmps.
|
|
*/
|
|
public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal,
|
|
double defaultValue) {
|
|
final String type = getOrdinalPowerType(group, ordinal);
|
|
return getAveragePowerOrDefault(type, defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Returns the average current in mA consumed by an ordinaled subsystem.
|
|
*
|
|
* @param group the subsystem {@link PowerGroup}.
|
|
* @param ordinal which entity in the {@link PowerGroup}.
|
|
* @return the average current in milliAmps.
|
|
*/
|
|
public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal) {
|
|
return getAveragePowerForOrdinal(group, ordinal, 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the battery capacity, if available, in milli Amp Hours. If not available,
|
|
* it returns zero.
|
|
*
|
|
* @return the battery capacity in mAh
|
|
*/
|
|
@UnsupportedAppUsage
|
|
public double getBatteryCapacity() {
|
|
return getAveragePower(POWER_BATTERY_CAPACITY);
|
|
}
|
|
|
|
/**
|
|
* Dump power constants into PowerProfileProto
|
|
*/
|
|
public void dumpDebug(ProtoOutputStream proto) {
|
|
// cpu.suspend
|
|
writePowerConstantToProto(proto, POWER_CPU_SUSPEND, PowerProfileProto.CPU_SUSPEND);
|
|
|
|
// cpu.idle
|
|
writePowerConstantToProto(proto, POWER_CPU_IDLE, PowerProfileProto.CPU_IDLE);
|
|
|
|
// cpu.active
|
|
writePowerConstantToProto(proto, POWER_CPU_ACTIVE, PowerProfileProto.CPU_ACTIVE);
|
|
|
|
// cpu.clusters.cores
|
|
// cpu.cluster_power.cluster
|
|
// cpu.core_speeds.cluster
|
|
// cpu.core_power.cluster
|
|
for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
|
|
final long token = proto.start(PowerProfileProto.CPU_CLUSTER);
|
|
proto.write(PowerProfileProto.CpuCluster.ID, cluster);
|
|
proto.write(PowerProfileProto.CpuCluster.CLUSTER_POWER,
|
|
sPowerItemMap.get(mCpuClusters[cluster].clusterPowerKey));
|
|
proto.write(PowerProfileProto.CpuCluster.CORES, mCpuClusters[cluster].numCpus);
|
|
for (Double speed : sPowerArrayMap.get(mCpuClusters[cluster].freqKey)) {
|
|
proto.write(PowerProfileProto.CpuCluster.SPEED, speed);
|
|
}
|
|
for (Double corePower : sPowerArrayMap.get(mCpuClusters[cluster].corePowerKey)) {
|
|
proto.write(PowerProfileProto.CpuCluster.CORE_POWER, corePower);
|
|
}
|
|
proto.end(token);
|
|
}
|
|
|
|
// wifi.scan
|
|
writePowerConstantToProto(proto, POWER_WIFI_SCAN, PowerProfileProto.WIFI_SCAN);
|
|
|
|
// wifi.on
|
|
writePowerConstantToProto(proto, POWER_WIFI_ON, PowerProfileProto.WIFI_ON);
|
|
|
|
// wifi.active
|
|
writePowerConstantToProto(proto, POWER_WIFI_ACTIVE, PowerProfileProto.WIFI_ACTIVE);
|
|
|
|
// wifi.controller.idle
|
|
writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_IDLE,
|
|
PowerProfileProto.WIFI_CONTROLLER_IDLE);
|
|
|
|
// wifi.controller.rx
|
|
writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_RX,
|
|
PowerProfileProto.WIFI_CONTROLLER_RX);
|
|
|
|
// wifi.controller.tx
|
|
writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_TX,
|
|
PowerProfileProto.WIFI_CONTROLLER_TX);
|
|
|
|
// wifi.controller.tx_levels
|
|
writePowerConstantArrayToProto(proto, POWER_WIFI_CONTROLLER_TX_LEVELS,
|
|
PowerProfileProto.WIFI_CONTROLLER_TX_LEVELS);
|
|
|
|
// wifi.controller.voltage
|
|
writePowerConstantToProto(proto, POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
|
|
PowerProfileProto.WIFI_CONTROLLER_OPERATING_VOLTAGE);
|
|
|
|
// bluetooth.controller.idle
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_IDLE,
|
|
PowerProfileProto.BLUETOOTH_CONTROLLER_IDLE);
|
|
|
|
// bluetooth.controller.rx
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_RX,
|
|
PowerProfileProto.BLUETOOTH_CONTROLLER_RX);
|
|
|
|
// bluetooth.controller.tx
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_TX,
|
|
PowerProfileProto.BLUETOOTH_CONTROLLER_TX);
|
|
|
|
// bluetooth.controller.voltage
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
|
|
PowerProfileProto.BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE);
|
|
|
|
// modem.controller.sleep
|
|
writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_SLEEP,
|
|
PowerProfileProto.MODEM_CONTROLLER_SLEEP);
|
|
|
|
// modem.controller.idle
|
|
writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_IDLE,
|
|
PowerProfileProto.MODEM_CONTROLLER_IDLE);
|
|
|
|
// modem.controller.rx
|
|
writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_RX,
|
|
PowerProfileProto.MODEM_CONTROLLER_RX);
|
|
|
|
// modem.controller.tx
|
|
writePowerConstantArrayToProto(proto, POWER_MODEM_CONTROLLER_TX,
|
|
PowerProfileProto.MODEM_CONTROLLER_TX);
|
|
|
|
// modem.controller.voltage
|
|
writePowerConstantToProto(proto, POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE,
|
|
PowerProfileProto.MODEM_CONTROLLER_OPERATING_VOLTAGE);
|
|
|
|
// gps.on
|
|
writePowerConstantToProto(proto, POWER_GPS_ON, PowerProfileProto.GPS_ON);
|
|
|
|
// gps.signalqualitybased
|
|
writePowerConstantArrayToProto(proto, POWER_GPS_SIGNAL_QUALITY_BASED,
|
|
PowerProfileProto.GPS_SIGNAL_QUALITY_BASED);
|
|
|
|
// gps.voltage
|
|
writePowerConstantToProto(proto, POWER_GPS_OPERATING_VOLTAGE,
|
|
PowerProfileProto.GPS_OPERATING_VOLTAGE);
|
|
|
|
// bluetooth.on
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_ON, PowerProfileProto.BLUETOOTH_ON);
|
|
|
|
// bluetooth.active
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_ACTIVE,
|
|
PowerProfileProto.BLUETOOTH_ACTIVE);
|
|
|
|
// bluetooth.at
|
|
writePowerConstantToProto(proto, POWER_BLUETOOTH_AT_CMD,
|
|
PowerProfileProto.BLUETOOTH_AT_CMD);
|
|
|
|
// ambient.on
|
|
writePowerConstantToProto(proto, POWER_AMBIENT_DISPLAY, PowerProfileProto.AMBIENT_DISPLAY);
|
|
|
|
// screen.on
|
|
writePowerConstantToProto(proto, POWER_SCREEN_ON, PowerProfileProto.SCREEN_ON);
|
|
|
|
// radio.on
|
|
writePowerConstantToProto(proto, POWER_RADIO_ON, PowerProfileProto.RADIO_ON);
|
|
|
|
// radio.scanning
|
|
writePowerConstantToProto(proto, POWER_RADIO_SCANNING, PowerProfileProto.RADIO_SCANNING);
|
|
|
|
// radio.active
|
|
writePowerConstantToProto(proto, POWER_RADIO_ACTIVE, PowerProfileProto.RADIO_ACTIVE);
|
|
|
|
// screen.full
|
|
writePowerConstantToProto(proto, POWER_SCREEN_FULL, PowerProfileProto.SCREEN_FULL);
|
|
|
|
// audio
|
|
writePowerConstantToProto(proto, POWER_AUDIO, PowerProfileProto.AUDIO);
|
|
|
|
// video
|
|
writePowerConstantToProto(proto, POWER_VIDEO, PowerProfileProto.VIDEO);
|
|
|
|
// camera.flashlight
|
|
writePowerConstantToProto(proto, POWER_FLASHLIGHT, PowerProfileProto.FLASHLIGHT);
|
|
|
|
// memory.bandwidths
|
|
writePowerConstantToProto(proto, POWER_MEMORY, PowerProfileProto.MEMORY);
|
|
|
|
// camera.avg
|
|
writePowerConstantToProto(proto, POWER_CAMERA, PowerProfileProto.CAMERA);
|
|
|
|
// wifi.batchedscan
|
|
writePowerConstantToProto(proto, POWER_WIFI_BATCHED_SCAN,
|
|
PowerProfileProto.WIFI_BATCHED_SCAN);
|
|
|
|
// battery.capacity
|
|
writePowerConstantToProto(proto, POWER_BATTERY_CAPACITY,
|
|
PowerProfileProto.BATTERY_CAPACITY);
|
|
}
|
|
|
|
/**
|
|
* Dump the PowerProfile values.
|
|
*/
|
|
public void dump(PrintWriter pw) {
|
|
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
|
|
sPowerItemMap.forEach((key, value) -> {
|
|
ipw.print(key, value);
|
|
ipw.println();
|
|
});
|
|
sPowerArrayMap.forEach((key, value) -> {
|
|
ipw.print(key, Arrays.toString(value));
|
|
ipw.println();
|
|
});
|
|
ipw.println("Modem values:");
|
|
ipw.increaseIndent();
|
|
sModemPowerProfile.dump(ipw);
|
|
ipw.decreaseIndent();
|
|
}
|
|
|
|
// Writes items in sPowerItemMap to proto if exists.
|
|
private void writePowerConstantToProto(ProtoOutputStream proto, String key, long fieldId) {
|
|
if (sPowerItemMap.containsKey(key)) {
|
|
proto.write(fieldId, sPowerItemMap.get(key));
|
|
}
|
|
}
|
|
|
|
// Writes items in sPowerArrayMap to proto if exists.
|
|
private void writePowerConstantArrayToProto(ProtoOutputStream proto, String key, long fieldId) {
|
|
if (sPowerArrayMap.containsKey(key)) {
|
|
for (Double d : sPowerArrayMap.get(key)) {
|
|
proto.write(fieldId, d);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Creates the key for an ordinaled power constant from the group and ordinal.
|
|
private static String getOrdinalPowerType(@PowerGroup String group, int ordinal) {
|
|
return group + ordinal;
|
|
}
|
|
}
|