Update PowerProfile to support multidisplay devices

Replaced the display related power constants with new ones that support
multidisply.

The legacy constants are marked as UnsupportedAppUsage, so they have not
been removed yet and they attempting to read them will return the power
constant values for the first display.

Fixes: 200226329
Test: atest com.android.internal.os.PowerProfileTest#testPowerProfile
Test: atest FrameworksCoreTests:com.android.internal.os.BatteryStatsTests
Change-Id: Id181443bd6f553ee37fc4a1647d31644fcad7912
This commit is contained in:
Michael Wachenschwanz
2021-09-16 19:25:40 -07:00
parent 782a906e71
commit 8ac63071a4
8 changed files with 185 additions and 10 deletions

View File

@@ -16,6 +16,8 @@
package com.android.internal.os;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
@@ -32,8 +34,9 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator {
private final UsageBasedPowerEstimator mPowerEstimator;
public AmbientDisplayPowerCalculator(PowerProfile powerProfile) {
// TODO(b/200239964): update to support multidisplay.
mPowerEstimator = new UsageBasedPowerEstimator(
powerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY));
powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0));
}
/**

View File

@@ -17,10 +17,12 @@
package com.android.internal.os;
import android.annotation.StringDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -30,6 +32,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
@@ -40,6 +44,8 @@ import java.util.HashMap;
*/
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
@@ -145,12 +151,18 @@ public class PowerProfile {
/**
* 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";
@@ -175,7 +187,10 @@ public class PowerProfile {
/**
* 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";
@@ -220,6 +235,29 @@ public class PowerProfile {
*/
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 {}
/**
* A map from Power Use Item to its power consumption.
*/
@@ -255,6 +293,7 @@ public class PowerProfile {
readPowerValuesFromXml(context, forTest);
}
initCpuClusters();
initDisplays();
}
}
@@ -424,6 +463,58 @@ public class PowerProfile {
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;
}
/**
* Returns the number of memory bandwidth buckets defined in power_profile.xml, or a
* default value if the subsystem has no recorded value.
@@ -495,6 +586,32 @@ public class PowerProfile {
}
}
/**
* 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.
@@ -682,4 +799,9 @@ public class PowerProfile {
}
}
}
// 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;
}
}

View File

@@ -16,6 +16,9 @@
package com.android.internal.os;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
@@ -50,10 +53,11 @@ public class ScreenPowerCalculator extends PowerCalculator {
}
public ScreenPowerCalculator(PowerProfile powerProfile) {
// TODO(b/200239964): update to support multidisplay.
mScreenOnPowerEstimator = new UsageBasedPowerEstimator(
powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON));
powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0));
mScreenFullPowerEstimator = new UsageBasedPowerEstimator(
powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL));
powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0));
}
@Override

View File

@@ -27,9 +27,33 @@
are totally dependent on the platform and can vary
significantly, so should be measured on the shipping platform
with a power meter. -->
<item name="ambient.on">0.1</item> <!-- ~100mA -->
<item name="screen.on">0.1</item> <!-- ~100mA -->
<item name="screen.full">0.1</item> <!-- ~100mA -->
<!-- Display related values. -->
<!-- Average battery current draw of display0 while in ambient mode, including backlight.
There must be one of these for each display, labeled:
ambient.on.display0, ambient.on.display1, etc...
Each display suffix number should match it's ordinal in its display device config.
-->
<item name="ambient.on.display0">0.1</item> <!-- ~100mA -->
<!-- Average battery current draw of display0 while on without backlight.
There must be one of these for each display, labeled:
screen.on.display0, screen.on.display1, etc...
Each display suffix number should match it's ordinal in its display device config.
-->
<item name="screen.on.display0">0.1</item> <!-- ~100mA -->
<!-- Average battery current draw of the backlight at full brightness.
The full current draw of display N at full brightness should be the sum of screen.on.displayN
and screen.full.displayN
There must be one of these for each display, labeled:
screen.full.display0, screen.full.display1, etc...
Each display suffix number should match it's ordinal in its display device config.
-->
<item name="screen.full.display0">0.1</item> <!-- ~100mA -->
<item name="bluetooth.active">0.1</item> <!-- Bluetooth data transfer, ~10mA -->
<item name="bluetooth.on">0.1</item> <!-- Bluetooth on & connectable, but not connected, ~0.1mA -->
<item name="wifi.on">0.1</item> <!-- ~3mA -->

View File

@@ -16,6 +16,8 @@
package com.android.internal.os;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT;
import static com.google.common.truth.Truth.assertThat;
import android.os.BatteryConsumer;
@@ -36,7 +38,7 @@ public class AmbientDisplayPowerCalculatorTest {
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
.setAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY, 10.0);
.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0);
@Test
public void testMeasuredEnergyBasedModel() {

View File

@@ -110,6 +110,14 @@ public class BatteryUsageStatsRule implements TestRule {
return this;
}
public BatteryUsageStatsRule setAveragePowerForOrdinal(String group, int ordinal,
double value) {
when(mPowerProfile.getAveragePowerForOrdinal(group, ordinal)).thenReturn(value);
when(mPowerProfile.getAveragePowerForOrdinal(eq(group), eq(ordinal),
anyDouble())).thenReturn(value);
return this;
}
/** Call only after setting the power profile information. */
public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() {
return initMeasuredEnergyStatsLocked(new String[0]);

View File

@@ -17,6 +17,10 @@
package com.android.internal.os;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -53,7 +57,12 @@ public class PowerProfileTest extends TestCase {
assertEquals(4, mProfile.getNumSpeedStepsInCpuCluster(1));
assertEquals(60.0, mProfile.getAveragePowerForCpuCore(1, 3));
assertEquals(3000.0, mProfile.getBatteryCapacity());
assertEquals(0.5, mProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY));
assertEquals(0.5,
mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0));
assertEquals(100.0,
mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0));
assertEquals(800.0,
mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0));
assertEquals(100.0, mProfile.getAveragePower(PowerProfile.POWER_AUDIO));
assertEquals(150.0, mProfile.getAveragePower(PowerProfile.POWER_VIDEO));
}

View File

@@ -16,6 +16,9 @@
package com.android.internal.os;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;
import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON;
import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityManager;
@@ -42,8 +45,8 @@ public class ScreenPowerCalculatorTest {
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
.setAveragePower(PowerProfile.POWER_SCREEN_ON, 36.0)
.setAveragePower(PowerProfile.POWER_SCREEN_FULL, 48.0);
.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0, 36.0)
.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0, 48.0);
@Test
public void testMeasuredEnergyBasedModel() {