Merge "Update BatteryStatsImpl to handle multidisplay" into sc-v2-dev am: 684c0b4a77

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15913462

Change-Id: Id788a5ca13e871baa85bb2ada6ead28b50170e55
This commit is contained in:
Michael Wachenschwanz
2021-10-15 21:52:10 +00:00
committed by Automerger Merge Worker
9 changed files with 924 additions and 62 deletions

View File

@@ -2302,6 +2302,38 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract Timer getScreenBrightnessTimer(int brightnessBin);
/**
* Returns the number of physical displays on the device.
*
* {@hide}
*/
public abstract int getDisplayCount();
/**
* Returns the time in microseconds that the screen has been on for a display while the
* device was running on battery.
*
* {@hide}
*/
public abstract long getDisplayScreenOnTime(int display, long elapsedRealtimeUs);
/**
* Returns the time in microseconds that a display has been dozing while the device was
* running on battery.
*
* {@hide}
*/
public abstract long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs);
/**
* Returns the time in microseconds that a display has been on with the given brightness
* level while the device was running on battery.
*
* {@hide}
*/
public abstract long getDisplayScreenBrightnessTime(int display, int brightnessBin,
long elapsedRealtimeUs);
/**
* Returns the time in microseconds that power save mode has been enabled while the device was
* running on battery.
@@ -5038,6 +5070,71 @@ public abstract class BatteryStats implements Parcelable {
pw.println(sb.toString());
}
final int numDisplays = getDisplayCount();
if (numDisplays > 1) {
pw.println("");
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
sb.append(" MULTI-DISPLAY POWER SUMMARY START");
pw.println(sb.toString());
for (int display = 0; display < numDisplays; display++) {
sb.setLength(0);
sb.append(prefix);
sb.append(" Display ");
sb.append(display);
sb.append(" Statistics:");
pw.println(sb.toString());
final long displayScreenOnTime = getDisplayScreenOnTime(display, rawRealtime);
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen on: ");
formatTimeMs(sb, displayScreenOnTime / 1000);
sb.append("(");
sb.append(formatRatioLocked(displayScreenOnTime, whichBatteryRealtime));
sb.append(") ");
pw.println(sb.toString());
sb.setLength(0);
sb.append(" Screen brightness levels:");
didOne = false;
for (int bin = 0; bin < NUM_SCREEN_BRIGHTNESS_BINS; bin++) {
final long timeUs = getDisplayScreenBrightnessTime(display, bin, rawRealtime);
if (timeUs == 0) {
continue;
}
didOne = true;
sb.append("\n ");
sb.append(prefix);
sb.append(SCREEN_BRIGHTNESS_NAMES[bin]);
sb.append(" ");
formatTimeMs(sb, timeUs / 1000);
sb.append("(");
sb.append(formatRatioLocked(timeUs, displayScreenOnTime));
sb.append(")");
}
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
final long displayScreenDozeTimeUs = getDisplayScreenDozeTime(display, rawRealtime);
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen Doze: ");
formatTimeMs(sb, displayScreenDozeTimeUs / 1000);
sb.append("(");
sb.append(formatRatioLocked(displayScreenDozeTimeUs, whichBatteryRealtime));
sb.append(") ");
pw.println(sb.toString());
}
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
sb.append(" MULTI-DISPLAY POWER SUMMARY END");
pw.println(sb.toString());
}
pw.println("");
pw.print(prefix);
sb.setLength(0);

View File

@@ -690,7 +690,7 @@ public class BatteryStatsImpl extends BatteryStats {
* Schedule a sync because of a screen state change.
*/
Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery,
boolean onBatteryScreenOff, int screenState);
boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates);
Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
void cancelCpuSyncDueToWakelockChange();
Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis);
@@ -851,17 +851,84 @@ public class BatteryStatsImpl extends BatteryStats {
public boolean mRecordAllHistory;
boolean mNoAutoReset;
/**
* Overall screen state. For multidisplay devices, this represents the current highest screen
* state of the displays.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
protected int mScreenState = Display.STATE_UNKNOWN;
/**
* Overall screen on timer. For multidisplay devices, this represents the time spent with at
* least one display in the screen on state.
*/
StopwatchTimer mScreenOnTimer;
/**
* Overall screen doze timer. For multidisplay devices, this represents the time spent with
* screen doze being the highest screen state.
*/
StopwatchTimer mScreenDozeTimer;
/**
* Overall screen brightness bin. For multidisplay devices, this represents the current
* brightest screen.
*/
int mScreenBrightnessBin = -1;
/**
* Overall screen brightness timers. For multidisplay devices, the {@link mScreenBrightnessBin}
* timer will be active at any given time
*/
final StopwatchTimer[] mScreenBrightnessTimer =
new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
boolean mPretendScreenOff;
private static class DisplayBatteryStats {
/**
* Per display screen state.
*/
public int screenState = Display.STATE_UNKNOWN;
/**
* Per display screen on timers.
*/
public StopwatchTimer screenOnTimer;
/**
* Per display screen doze timers.
*/
public StopwatchTimer screenDozeTimer;
/**
* Per display screen brightness bins.
*/
public int screenBrightnessBin = -1;
/**
* Per display screen brightness timers.
*/
public StopwatchTimer[] screenBrightnessTimers =
new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
DisplayBatteryStats(Clocks clocks, TimeBase timeBase) {
screenOnTimer = new StopwatchTimer(clocks, null, -1, null,
timeBase);
screenDozeTimer = new StopwatchTimer(clocks, null, -1, null,
timeBase);
for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) {
screenBrightnessTimers[i] = new StopwatchTimer(clocks, null, -100 - i, null,
timeBase);
}
}
/**
* Reset display timers.
*/
public void reset(long elapsedRealtimeUs) {
screenOnTimer.reset(false, elapsedRealtimeUs);
screenDozeTimer.reset(false, elapsedRealtimeUs);
for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) {
screenBrightnessTimers[i].reset(false, elapsedRealtimeUs);
}
}
}
DisplayBatteryStats[] mPerDisplayBatteryStats;
boolean mInteractive;
StopwatchTimer mInteractiveTimer;
@@ -4308,8 +4375,10 @@ public class BatteryStatsImpl extends BatteryStats {
public void setPretendScreenOff(boolean pretendScreenOff) {
if (mPretendScreenOff != pretendScreenOff) {
mPretendScreenOff = pretendScreenOff;
noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON,
mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis());
final int primaryScreenState = mPerDisplayBatteryStats[0].screenState;
noteScreenStateLocked(0, primaryScreenState,
mClocks.elapsedRealtime(), mClocks.uptimeMillis(),
mClocks.currentTimeMillis());
}
}
@@ -4907,29 +4976,158 @@ public class BatteryStatsImpl extends BatteryStats {
}
@GuardedBy("this")
public void noteScreenStateLocked(int state) {
noteScreenStateLocked(state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(),
public void noteScreenStateLocked(int display, int state) {
noteScreenStateLocked(display, state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(),
mClocks.currentTimeMillis());
}
@GuardedBy("this")
public void noteScreenStateLocked(int state,
public void noteScreenStateLocked(int display, int displayState,
long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
state = mPretendScreenOff ? Display.STATE_OFF : state;
// Battery stats relies on there being 4 states. To accommodate this, new states beyond the
// original 4 are mapped to one of the originals.
if (state > MAX_TRACKED_SCREEN_STATE) {
switch (state) {
case Display.STATE_VR:
state = Display.STATE_ON;
if (displayState > MAX_TRACKED_SCREEN_STATE) {
if (Display.isOnState(displayState)) {
displayState = Display.STATE_ON;
} else if (Display.isDozeState(displayState)) {
if (Display.isSuspendedState(displayState)) {
displayState = Display.STATE_DOZE_SUSPEND;
} else {
displayState = Display.STATE_DOZE;
}
} else if (Display.isOffState(displayState)) {
displayState = Display.STATE_OFF;
} else {
Slog.wtf(TAG, "Unknown screen state (not mapped): " + displayState);
displayState = Display.STATE_UNKNOWN;
}
}
// As of this point, displayState should be mapped to one of:
// - Display.STATE_ON,
// - Display.STATE_DOZE
// - Display.STATE_DOZE_SUSPEND
// - Display.STATE_OFF
// - Display.STATE_UNKNOWN
int state;
int overallBin = mScreenBrightnessBin;
int externalUpdateFlag = 0;
boolean shouldScheduleSync = false;
final int numDisplay = mPerDisplayBatteryStats.length;
if (display < 0 || display >= numDisplay) {
Slog.wtf(TAG, "Unexpected note screen state for display " + display + " (only "
+ mPerDisplayBatteryStats.length + " displays exist...)");
return;
}
final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display];
final int oldDisplayState = displayStats.screenState;
if (oldDisplayState == displayState) {
// Nothing changed
state = mScreenState;
} else {
displayStats.screenState = displayState;
// Stop timer for previous display state.
switch (oldDisplayState) {
case Display.STATE_ON:
displayStats.screenOnTimer.stopRunningLocked(elapsedRealtimeMs);
final int bin = displayStats.screenBrightnessBin;
if (bin >= 0) {
displayStats.screenBrightnessTimers[bin].stopRunningLocked(
elapsedRealtimeMs);
}
overallBin = evaluateOverallScreenBrightnessBinLocked();
shouldScheduleSync = true;
break;
case Display.STATE_DOZE:
// Transition from doze to doze suspend can be ignored.
if (displayState == Display.STATE_DOZE_SUSPEND) break;
displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs);
shouldScheduleSync = true;
break;
case Display.STATE_DOZE_SUSPEND:
// Transition from doze suspend to doze can be ignored.
if (displayState == Display.STATE_DOZE) break;
displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs);
shouldScheduleSync = true;
break;
case Display.STATE_OFF: // fallthrough
case Display.STATE_UNKNOWN:
// Not tracked by timers.
break;
default:
Slog.wtf(TAG, "Unknown screen state (not mapped): " + state);
Slog.wtf(TAG,
"Attempted to stop timer for unexpected display state " + display);
}
// Start timer for new display state.
switch (displayState) {
case Display.STATE_ON:
displayStats.screenOnTimer.startRunningLocked(elapsedRealtimeMs);
final int bin = displayStats.screenBrightnessBin;
if (bin >= 0) {
displayStats.screenBrightnessTimers[bin].startRunningLocked(
elapsedRealtimeMs);
}
overallBin = evaluateOverallScreenBrightnessBinLocked();
shouldScheduleSync = true;
break;
case Display.STATE_DOZE:
// Transition from doze suspend to doze can be ignored.
if (oldDisplayState == Display.STATE_DOZE_SUSPEND) break;
displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs);
shouldScheduleSync = true;
break;
case Display.STATE_DOZE_SUSPEND:
// Transition from doze to doze suspend can be ignored.
if (oldDisplayState == Display.STATE_DOZE) break;
displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs);
shouldScheduleSync = true;
break;
case Display.STATE_OFF: // fallthrough
case Display.STATE_UNKNOWN:
// Not tracked by timers.
break;
default:
Slog.wtf(TAG,
"Attempted to start timer for unexpected display state " + displayState
+ " for display " + display);
}
if (shouldScheduleSync
&& mGlobalMeasuredEnergyStats != null
&& mGlobalMeasuredEnergyStats.isStandardBucketSupported(
MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON)) {
// Display measured energy stats is available. Prepare to schedule an
// external sync.
externalUpdateFlag |= ExternalStatsSync.UPDATE_DISPLAY;
}
// Reevaluate most important display screen state.
state = Display.STATE_UNKNOWN;
for (int i = 0; i < numDisplay; i++) {
final int tempState = mPerDisplayBatteryStats[i].screenState;
if (tempState == Display.STATE_ON
|| state == Display.STATE_ON) {
state = Display.STATE_ON;
} else if (tempState == Display.STATE_DOZE
|| state == Display.STATE_DOZE) {
state = Display.STATE_DOZE;
} else if (tempState == Display.STATE_DOZE_SUSPEND
|| state == Display.STATE_DOZE_SUSPEND) {
state = Display.STATE_DOZE_SUSPEND;
} else if (tempState == Display.STATE_OFF
|| state == Display.STATE_OFF) {
state = Display.STATE_OFF;
}
}
}
final boolean batteryRunning = mOnBatteryTimeBase.isRunning();
final boolean batteryScreenOffRunning = mOnBatteryScreenOffTimeBase.isRunning();
state = mPretendScreenOff ? Display.STATE_OFF : state;
if (mScreenState != state) {
recordDailyStatsIfNeededLocked(true, currentTimeMs);
final int oldState = mScreenState;
@@ -4983,11 +5181,11 @@ public class BatteryStatsImpl extends BatteryStats {
+ Display.stateToString(state));
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
// TODO: (Probably overkill) Have mGlobalMeasuredEnergyStats store supported flags and
// only update DISPLAY if it is. Currently overkill since CPU is scheduled anyway.
final int updateFlag = ExternalStatsSync.UPDATE_CPU | ExternalStatsSync.UPDATE_DISPLAY;
mExternalSync.scheduleSyncDueToScreenStateChange(updateFlag,
mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning(), state);
// Per screen state Cpu stats needed. Prepare to schedule an external sync.
externalUpdateFlag |= ExternalStatsSync.UPDATE_CPU;
shouldScheduleSync = true;
if (Display.isOnState(state)) {
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
uptimeMs * 1000, elapsedRealtimeMs * 1000);
@@ -5005,33 +5203,116 @@ public class BatteryStatsImpl extends BatteryStats {
updateDischargeScreenLevelsLocked(oldState, state);
}
}
// Changing display states might have changed the screen used to determine the overall
// brightness.
maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs);
if (shouldScheduleSync) {
final int numDisplays = mPerDisplayBatteryStats.length;
final int[] displayStates = new int[numDisplays];
for (int i = 0; i < numDisplays; i++) {
displayStates[i] = mPerDisplayBatteryStats[i].screenState;
}
mExternalSync.scheduleSyncDueToScreenStateChange(externalUpdateFlag,
batteryRunning, batteryScreenOffRunning, state, displayStates);
}
}
@UnsupportedAppUsage
public void noteScreenBrightnessLocked(int brightness) {
noteScreenBrightnessLocked(brightness, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
noteScreenBrightnessLocked(0, brightness);
}
public void noteScreenBrightnessLocked(int brightness, long elapsedRealtimeMs, long uptimeMs) {
/**
* Note screen brightness change for a display.
*/
public void noteScreenBrightnessLocked(int display, int brightness) {
noteScreenBrightnessLocked(display, brightness, mClocks.elapsedRealtime(),
mClocks.uptimeMillis());
}
/**
* Note screen brightness change for a display.
*/
public void noteScreenBrightnessLocked(int display, int brightness, long elapsedRealtimeMs,
long uptimeMs) {
// Bin the brightness.
int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
| (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
final int overallBin;
final int numDisplays = mPerDisplayBatteryStats.length;
if (display < 0 || display >= numDisplays) {
Slog.wtf(TAG, "Unexpected note screen brightness for display " + display + " (only "
+ mPerDisplayBatteryStats.length + " displays exist...)");
return;
}
final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display];
final int oldBin = displayStats.screenBrightnessBin;
if (oldBin == bin) {
// Nothing changed
overallBin = mScreenBrightnessBin;
} else {
displayStats.screenBrightnessBin = bin;
if (displayStats.screenState == Display.STATE_ON) {
if (oldBin >= 0) {
displayStats.screenBrightnessTimers[oldBin].stopRunningLocked(
elapsedRealtimeMs);
}
displayStats.screenBrightnessTimers[bin].startRunningLocked(
elapsedRealtimeMs);
}
overallBin = evaluateOverallScreenBrightnessBinLocked();
}
maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs);
}
private int evaluateOverallScreenBrightnessBinLocked() {
int overallBin = -1;
final int numDisplays = getDisplayCount();
for (int display = 0; display < numDisplays; display++) {
final int displayBrightnessBin;
if (mPerDisplayBatteryStats[display].screenState == Display.STATE_ON) {
displayBrightnessBin = mPerDisplayBatteryStats[display].screenBrightnessBin;
} else {
displayBrightnessBin = -1;
}
if (displayBrightnessBin > overallBin) {
overallBin = displayBrightnessBin;
}
}
return overallBin;
}
private void maybeUpdateOverallScreenBrightness(int overallBin, long elapsedRealtimeMs,
long uptimeMs) {
if (mScreenBrightnessBin != overallBin) {
if (overallBin >= 0) {
mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK)
| (overallBin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) {
Slog.v(TAG, "Screen brightness " + overallBin + " to: "
+ Integer.toHexString(mHistoryCur.states));
}
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
if (mScreenState == Display.STATE_ON) {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin]
.stopRunningLocked(elapsedRealtimeMs);
}
mScreenBrightnessTimer[bin]
.startRunningLocked(elapsedRealtimeMs);
if (overallBin >= 0) {
mScreenBrightnessTimer[overallBin]
.startRunningLocked(elapsedRealtimeMs);
}
}
mScreenBrightnessBin = bin;
mScreenBrightnessBin = overallBin;
}
}
@@ -6693,6 +6974,31 @@ public class BatteryStatsImpl extends BatteryStats {
return mScreenBrightnessTimer[brightnessBin];
}
@Override
public int getDisplayCount() {
return mPerDisplayBatteryStats.length;
}
@Override
public long getDisplayScreenOnTime(int display, long elapsedRealtimeUs) {
return mPerDisplayBatteryStats[display].screenOnTimer.getTotalTimeLocked(elapsedRealtimeUs,
STATS_SINCE_CHARGED);
}
@Override
public long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs) {
return mPerDisplayBatteryStats[display].screenDozeTimer.getTotalTimeLocked(
elapsedRealtimeUs, STATS_SINCE_CHARGED);
}
@Override
public long getDisplayScreenBrightnessTime(int display, int brightnessBin,
long elapsedRealtimeUs) {
final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display];
return displayStats.screenBrightnessTimers[brightnessBin].getTotalTimeLocked(
elapsedRealtimeUs, STATS_SINCE_CHARGED);
}
@Override public long getInteractiveTime(long elapsedRealtimeUs, int which) {
return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -10694,6 +11000,10 @@ public class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
mOnBatteryTimeBase);
}
mPerDisplayBatteryStats = new DisplayBatteryStats[1];
mPerDisplayBatteryStats[0] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase);
mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase);
mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
mOnBatteryTimeBase);
@@ -10806,6 +11116,8 @@ public class BatteryStatsImpl extends BatteryStats {
// Initialize the estimated battery capacity to a known preset one.
mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity();
}
setDisplayCountLocked(mPowerProfile.getNumDisplays());
}
PowerProfile getPowerProfile() {
@@ -10838,6 +11150,16 @@ public class BatteryStatsImpl extends BatteryStats {
mExternalSync = sync;
}
/**
* Initialize and set multi display timers and states.
*/
public void setDisplayCountLocked(int numDisplays) {
mPerDisplayBatteryStats = new DisplayBatteryStats[numDisplays];
for (int i = 0; i < numDisplays; i++) {
mPerDisplayBatteryStats[i] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase);
}
}
public void updateDailyDeadlineLocked() {
// Get the current time.
long currentTimeMs = mDailyStartTimeMs = mClocks.currentTimeMillis();
@@ -11314,6 +11636,11 @@ public class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].reset(false, elapsedRealtimeUs);
}
final int numDisplays = mPerDisplayBatteryStats.length;
for (int i = 0; i < numDisplays; i++) {
mPerDisplayBatteryStats[i].reset(elapsedRealtimeUs);
}
if (mPowerProfile != null) {
mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity();
} else {

View File

@@ -47,13 +47,13 @@ public class AmbientDisplayPowerCalculatorTest {
stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 0);
stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
30 * MINUTE_IN_MS);
stats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_DOZE,
30 * MINUTE_IN_MS);
stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
120 * MINUTE_IN_MS);
stats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_OFF,
@@ -78,9 +78,9 @@ public class AmbientDisplayPowerCalculatorTest {
public void testPowerProfileBasedModel() {
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
30 * MINUTE_IN_MS);
stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
120 * MINUTE_IN_MS);
AmbientDisplayPowerCalculator calculator =

View File

@@ -16,9 +16,13 @@
package com.android.internal.os;
import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
import android.app.ActivityManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
@@ -37,8 +41,10 @@ import com.android.internal.power.MeasuredEnergyStats;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.IntConsumer;
/**
* Test various BatteryStatsImpl noteStart methods.
@@ -317,18 +323,130 @@ public class BatteryStatsNoteTest extends TestCase {
public void testNoteScreenStateLocked() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
bi.noteScreenStateLocked(Display.STATE_ON);
bi.noteScreenStateLocked(Display.STATE_DOZE);
bi.noteScreenStateLocked(0, Display.STATE_ON);
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(bi.getScreenState(), Display.STATE_DOZE);
bi.noteScreenStateLocked(Display.STATE_ON);
assertEquals(Display.STATE_DOZE, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(bi.getScreenState(), Display.STATE_ON);
bi.noteScreenStateLocked(Display.STATE_OFF);
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(bi.getScreenState(), Display.STATE_OFF);
assertEquals(Display.STATE_OFF, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE_SUSPEND, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
// STATE_VR note should map to STATE_ON.
bi.noteScreenStateLocked(0, Display.STATE_VR);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
// STATE_ON_SUSPEND note should map to STATE_ON.
bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
// Transition from ON to ON state should not cause an External Sync
assertEquals(0, bi.getAndClearExternalStatsSyncFlags());
}
/**
* Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly for
* multi display devices
*/
@SmallTest
public void testNoteScreenStateLocked_multiDisplay() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setDisplayCountLocked(2);
bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"});
bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
bi.noteScreenStateLocked(0, Display.STATE_OFF);
bi.noteScreenStateLocked(1, Display.STATE_OFF);
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertEquals(Display.STATE_ON, bi.getScreenState());
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_OFF, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE_SUSPEND, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
// STATE_VR note should map to STATE_ON.
bi.noteScreenStateLocked(0, Display.STATE_VR);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
// STATE_ON_SUSPEND note should map to STATE_ON.
bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
// Transition from ON to ON state should not cause an External Sync
assertEquals(0, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(1, Display.STATE_DOZE);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
// Should remain STATE_ON since display0 is still on.
assertEquals(Display.STATE_ON, bi.getScreenState());
// Overall screen state did not change, so no need to sync CPU stats.
assertEquals(UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND);
assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_DOZE, bi.getScreenState());
// Overall screen state did not change, so no need to sync CPU stats.
assertEquals(UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_VR);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags());
bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND);
assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
assertEquals(Display.STATE_ON, bi.getScreenState());
assertEquals(0, bi.getAndClearExternalStatsSyncFlags());
}
/*
@@ -352,32 +470,317 @@ public class BatteryStatsNoteTest extends TestCase {
bi.updateTimeBasesLocked(true, Display.STATE_UNKNOWN, 100_000, 100_000);
// Turn on display at 200us
clocks.realtime = clocks.uptime = 200;
bi.noteScreenStateLocked(Display.STATE_ON);
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertEquals(150_000, bi.computeBatteryRealtime(250_000, STATS_SINCE_CHARGED));
assertEquals(100_000, bi.computeBatteryScreenOffRealtime(250_000, STATS_SINCE_CHARGED));
assertEquals(50_000, bi.getScreenOnTime(250_000, STATS_SINCE_CHARGED));
assertEquals(0, bi.getScreenDozeTime(250_000, STATS_SINCE_CHARGED));
assertEquals(50_000, bi.getDisplayScreenOnTime(0, 250_000));
assertEquals(0, bi.getDisplayScreenDozeTime(0, 250_000));
clocks.realtime = clocks.uptime = 310;
bi.noteScreenStateLocked(Display.STATE_OFF);
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(250_000, bi.computeBatteryRealtime(350_000, STATS_SINCE_CHARGED));
assertEquals(140_000, bi.computeBatteryScreenOffRealtime(350_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(350_000, STATS_SINCE_CHARGED));
assertEquals(0, bi.getScreenDozeTime(350_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 350_000));
assertEquals(0, bi.getDisplayScreenDozeTime(0, 350_000));
clocks.realtime = clocks.uptime = 400;
bi.noteScreenStateLocked(Display.STATE_DOZE);
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertEquals(400_000, bi.computeBatteryRealtime(500_000, STATS_SINCE_CHARGED));
assertEquals(290_000, bi.computeBatteryScreenOffRealtime(500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(500_000, STATS_SINCE_CHARGED));
assertEquals(100_000, bi.getScreenDozeTime(500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 500_000));
assertEquals(100_000, bi.getDisplayScreenDozeTime(0, 500_000));
clocks.realtime = clocks.uptime = 1000;
bi.noteScreenStateLocked(Display.STATE_OFF);
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(1400_000, bi.computeBatteryRealtime(1500_000, STATS_SINCE_CHARGED));
assertEquals(1290_000, bi.computeBatteryScreenOffRealtime(1500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(1500_000, STATS_SINCE_CHARGED));
assertEquals(600_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1500_000));
assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1500_000));
}
/*
* Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly for multi display
* devices.
*/
@SmallTest
public void testNoteScreenStateTimersLocked_multiDisplay() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
bi.setDisplayCountLocked(2);
clocks.realtime = clocks.uptime = 100;
// Device startup, setOnBatteryLocked calls updateTimebases
bi.updateTimeBasesLocked(true, Display.STATE_UNKNOWN, 100_000, 100_000);
// Turn on display at 200us
clocks.realtime = clocks.uptime = 200;
bi.noteScreenStateLocked(0, Display.STATE_ON);
bi.noteScreenStateLocked(1, Display.STATE_OFF);
assertEquals(150_000, bi.computeBatteryRealtime(250_000, STATS_SINCE_CHARGED));
assertEquals(100_000, bi.computeBatteryScreenOffRealtime(250_000, STATS_SINCE_CHARGED));
assertEquals(50_000, bi.getScreenOnTime(250_000, STATS_SINCE_CHARGED));
assertEquals(0, bi.getScreenDozeTime(250_000, STATS_SINCE_CHARGED));
assertEquals(50_000, bi.getDisplayScreenOnTime(0, 250_000));
assertEquals(0, bi.getDisplayScreenDozeTime(0, 250_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 250_000));
assertEquals(0, bi.getDisplayScreenDozeTime(1, 250_000));
clocks.realtime = clocks.uptime = 310;
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(250_000, bi.computeBatteryRealtime(350_000, STATS_SINCE_CHARGED));
assertEquals(140_000, bi.computeBatteryScreenOffRealtime(350_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(350_000, STATS_SINCE_CHARGED));
assertEquals(0, bi.getScreenDozeTime(350_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 350_000));
assertEquals(0, bi.getDisplayScreenDozeTime(0, 350_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 350_000));
assertEquals(0, bi.getDisplayScreenDozeTime(1, 350_000));
clocks.realtime = clocks.uptime = 400;
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertEquals(400_000, bi.computeBatteryRealtime(500_000, STATS_SINCE_CHARGED));
assertEquals(290_000, bi.computeBatteryScreenOffRealtime(500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(500_000, STATS_SINCE_CHARGED));
assertEquals(100_000, bi.getScreenDozeTime(500_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 500_000));
assertEquals(100_000, bi.getDisplayScreenDozeTime(0, 500_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 500_000));
assertEquals(0, bi.getDisplayScreenDozeTime(1, 500_000));
clocks.realtime = clocks.uptime = 1000;
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(1000_000, bi.computeBatteryRealtime(1100_000, STATS_SINCE_CHARGED));
assertEquals(890_000, bi.computeBatteryScreenOffRealtime(1100_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(1100_000, STATS_SINCE_CHARGED));
assertEquals(600_000, bi.getScreenDozeTime(1100_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1100_000));
assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1100_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 1100_000));
assertEquals(0, bi.getDisplayScreenDozeTime(1, 1100_000));
clocks.realtime = clocks.uptime = 1200;
// Change state of second display to doze
bi.noteScreenStateLocked(1, Display.STATE_DOZE);
assertEquals(1150_000, bi.computeBatteryRealtime(1250_000, STATS_SINCE_CHARGED));
assertEquals(1040_000, bi.computeBatteryScreenOffRealtime(1250_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getScreenOnTime(1250_000, STATS_SINCE_CHARGED));
assertEquals(650_000, bi.getScreenDozeTime(1250_000, STATS_SINCE_CHARGED));
assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1250_000));
assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1250_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 1250_000));
assertEquals(50_000, bi.getDisplayScreenDozeTime(1, 1250_000));
clocks.realtime = clocks.uptime = 1310;
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertEquals(1250_000, bi.computeBatteryRealtime(1350_000, STATS_SINCE_CHARGED));
assertEquals(1100_000, bi.computeBatteryScreenOffRealtime(1350_000, STATS_SINCE_CHARGED));
assertEquals(150_000, bi.getScreenOnTime(1350_000, STATS_SINCE_CHARGED));
assertEquals(710_000, bi.getScreenDozeTime(1350_000, STATS_SINCE_CHARGED));
assertEquals(150_000, bi.getDisplayScreenOnTime(0, 1350_000));
assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1350_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 1350_000));
assertEquals(150_000, bi.getDisplayScreenDozeTime(1, 1350_000));
clocks.realtime = clocks.uptime = 1400;
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertEquals(1400_000, bi.computeBatteryRealtime(1500_000, STATS_SINCE_CHARGED));
assertEquals(1200_000, bi.computeBatteryScreenOffRealtime(1500_000, STATS_SINCE_CHARGED));
assertEquals(200_000, bi.getScreenOnTime(1500_000, STATS_SINCE_CHARGED));
assertEquals(810_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED));
assertEquals(200_000, bi.getDisplayScreenOnTime(0, 1500_000));
assertEquals(700_000, bi.getDisplayScreenDozeTime(0, 1500_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 1500_000));
assertEquals(300_000, bi.getDisplayScreenDozeTime(1, 1500_000));
clocks.realtime = clocks.uptime = 2000;
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(2000_000, bi.computeBatteryRealtime(2100_000, STATS_SINCE_CHARGED));
assertEquals(1800_000, bi.computeBatteryScreenOffRealtime(2100_000, STATS_SINCE_CHARGED));
assertEquals(200_000, bi.getScreenOnTime(2100_000, STATS_SINCE_CHARGED));
assertEquals(1410_000, bi.getScreenDozeTime(2100_000, STATS_SINCE_CHARGED));
assertEquals(200_000, bi.getDisplayScreenOnTime(0, 2100_000));
assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2100_000));
assertEquals(0, bi.getDisplayScreenOnTime(1, 2100_000));
assertEquals(900_000, bi.getDisplayScreenDozeTime(1, 2100_000));
clocks.realtime = clocks.uptime = 2200;
// Change state of second display to on
bi.noteScreenStateLocked(1, Display.STATE_ON);
assertEquals(2150_000, bi.computeBatteryRealtime(2250_000, STATS_SINCE_CHARGED));
assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2250_000, STATS_SINCE_CHARGED));
assertEquals(250_000, bi.getScreenOnTime(2250_000, STATS_SINCE_CHARGED));
assertEquals(1510_000, bi.getScreenDozeTime(2250_000, STATS_SINCE_CHARGED));
assertEquals(200_000, bi.getDisplayScreenOnTime(0, 2250_000));
assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2250_000));
assertEquals(50_000, bi.getDisplayScreenOnTime(1, 2250_000));
assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2250_000));
clocks.realtime = clocks.uptime = 2310;
bi.noteScreenStateLocked(0, Display.STATE_ON);
assertEquals(2250_000, bi.computeBatteryRealtime(2350_000, STATS_SINCE_CHARGED));
assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2350_000, STATS_SINCE_CHARGED));
assertEquals(350_000, bi.getScreenOnTime(2350_000, STATS_SINCE_CHARGED));
assertEquals(1510_000, bi.getScreenDozeTime(2350_000, STATS_SINCE_CHARGED));
assertEquals(240_000, bi.getDisplayScreenOnTime(0, 2350_000));
assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2350_000));
assertEquals(150_000, bi.getDisplayScreenOnTime(1, 2350_000));
assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2350_000));
clocks.realtime = clocks.uptime = 2400;
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
assertEquals(2400_000, bi.computeBatteryRealtime(2500_000, STATS_SINCE_CHARGED));
assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2500_000, STATS_SINCE_CHARGED));
assertEquals(500_000, bi.getScreenOnTime(2500_000, STATS_SINCE_CHARGED));
assertEquals(1510_000, bi.getScreenDozeTime(2500_000, STATS_SINCE_CHARGED));
assertEquals(290_000, bi.getDisplayScreenOnTime(0, 2500_000));
assertEquals(1300_000, bi.getDisplayScreenDozeTime(0, 2500_000));
assertEquals(300_000, bi.getDisplayScreenOnTime(1, 2500_000));
assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2500_000));
clocks.realtime = clocks.uptime = 3000;
bi.noteScreenStateLocked(0, Display.STATE_OFF);
assertEquals(3000_000, bi.computeBatteryRealtime(3100_000, STATS_SINCE_CHARGED));
assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(3100_000, STATS_SINCE_CHARGED));
assertEquals(1100_000, bi.getScreenOnTime(3100_000, STATS_SINCE_CHARGED));
assertEquals(1510_000, bi.getScreenDozeTime(3100_000, STATS_SINCE_CHARGED));
assertEquals(290_000, bi.getDisplayScreenOnTime(0, 3100_000));
assertEquals(1800_000, bi.getDisplayScreenDozeTime(0, 3100_000));
assertEquals(900_000, bi.getDisplayScreenOnTime(1, 3100_000));
assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 3100_000));
}
/**
* Test BatteryStatsImpl.noteScreenBrightnessLocked updates timers correctly.
*/
@SmallTest
public void testScreenBrightnessLocked_multiDisplay() throws Exception {
final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
final int numDisplay = 2;
bi.setDisplayCountLocked(numDisplay);
final long[] overallExpected = new long[NUM_SCREEN_BRIGHTNESS_BINS];
final long[][] perDisplayExpected = new long[numDisplay][NUM_SCREEN_BRIGHTNESS_BINS];
class Bookkeeper {
public long currentTimeMs = 100;
public int overallActiveBin = -1;
public int[] perDisplayActiveBin = new int[numDisplay];
}
final Bookkeeper bk = new Bookkeeper();
Arrays.fill(bk.perDisplayActiveBin, -1);
IntConsumer incrementTime = inc -> {
bk.currentTimeMs += inc;
if (bk.overallActiveBin >= 0) {
overallExpected[bk.overallActiveBin] += inc;
}
for (int i = 0; i < numDisplay; i++) {
final int bin = bk.perDisplayActiveBin[i];
if (bin >= 0) {
perDisplayExpected[i][bin] += inc;
}
}
clocks.realtime = clocks.uptime = bk.currentTimeMs;
};
bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
bi.noteScreenStateLocked(0, Display.STATE_ON);
bi.noteScreenStateLocked(1, Display.STATE_ON);
incrementTime.accept(100);
bi.noteScreenBrightnessLocked(0, 25);
bi.noteScreenBrightnessLocked(1, 25);
// floor(25/256*5) = bin 0
bk.overallActiveBin = 0;
bk.perDisplayActiveBin[0] = 0;
bk.perDisplayActiveBin[1] = 0;
incrementTime.accept(50);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(13);
bi.noteScreenBrightnessLocked(0, 100);
// floor(25/256*5) = bin 1
bk.overallActiveBin = 1;
bk.perDisplayActiveBin[0] = 1;
incrementTime.accept(44);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(22);
bi.noteScreenBrightnessLocked(1, 200);
// floor(200/256*5) = bin 3
bk.overallActiveBin = 3;
bk.perDisplayActiveBin[1] = 3;
incrementTime.accept(33);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(77);
bi.noteScreenBrightnessLocked(0, 150);
// floor(150/256*5) = bin 2
// Overall active bin should not change
bk.perDisplayActiveBin[0] = 2;
incrementTime.accept(88);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(11);
bi.noteScreenStateLocked(1, Display.STATE_OFF);
// Display 1 should timers should stop incrementing
// Overall active bin should fallback to display 0's bin
bk.overallActiveBin = 2;
bk.perDisplayActiveBin[1] = -1;
incrementTime.accept(99);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(200);
bi.noteScreenBrightnessLocked(0, 255);
// floor(150/256*5) = bin 4
bk.overallActiveBin = 4;
bk.perDisplayActiveBin[0] = 4;
incrementTime.accept(300);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(200);
bi.noteScreenStateLocked(0, Display.STATE_DOZE);
// No displays are on. No brightness timers should be active.
bk.overallActiveBin = -1;
bk.perDisplayActiveBin[0] = -1;
incrementTime.accept(300);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(400);
bi.noteScreenStateLocked(1, Display.STATE_ON);
// Display 1 turned back on.
bk.overallActiveBin = 3;
bk.perDisplayActiveBin[1] = 3;
incrementTime.accept(500);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
incrementTime.accept(600);
bi.noteScreenStateLocked(0, Display.STATE_ON);
// Display 0 turned back on.
bk.overallActiveBin = 4;
bk.perDisplayActiveBin[0] = 4;
incrementTime.accept(700);
checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs);
}
@SmallTest
@@ -822,4 +1225,19 @@ public class BatteryStatsNoteTest extends TestCase {
assertEquals("Wrong uid2 blame in bucket 1 for Case " + caseName, blame2B, actualUid2[1]);
}
private void checkScreenBrightnesses(long[] overallExpected, long[][] perDisplayExpected,
BatteryStatsImpl bi, long currentTimeMs) {
final int numDisplay = bi.getDisplayCount();
for (int bin = 0; bin < NUM_SCREEN_BRIGHTNESS_BINS; bin++) {
for (int display = 0; display < numDisplay; display++) {
assertEquals("Failure for display " + display + " screen brightness bin " + bin,
perDisplayExpected[display][bin] * 1000,
bi.getDisplayScreenBrightnessTime(display, bin, currentTimeMs * 1000));
}
assertEquals("Failure for overall screen brightness bin " + bin,
overallExpected[bin] * 1000,
bi.getScreenBrightnessTime(bin, currentTimeMs * 1000, STATS_SINCE_CHARGED));
}
}
}

View File

@@ -39,13 +39,14 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
public BatteryStatsImpl.Clocks clocks;
public boolean mForceOnBattery;
private NetworkStats mNetworkStats;
private DummyExternalStatsSync mExternalStatsSync = new DummyExternalStatsSync();
MockBatteryStatsImpl(Clocks clocks) {
super(clocks);
this.clocks = mClocks;
initTimersAndCounters();
setExternalStatsSyncLocked(new DummyExternalStatsSync());
setExternalStatsSyncLocked(mExternalStatsSync);
informThatAllExternalStatsAreFlushed();
// A no-op handler.
@@ -182,7 +183,15 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return mPendingUids;
}
public int getAndClearExternalStatsSyncFlags() {
final int flags = mExternalStatsSync.flags;
mExternalStatsSync.flags = 0;
return flags;
}
private class DummyExternalStatsSync implements ExternalStatsSync {
public int flags = 0;
@Override
public Future<?> scheduleSync(String reason, int flags) {
return null;
@@ -211,8 +220,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
}
@Override
public Future<?> scheduleSyncDueToScreenStateChange(
int flag, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
public Future<?> scheduleSyncDueToScreenStateChange(int flag, boolean onBattery,
boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates) {
flags |= flag;
return null;
}

View File

@@ -53,7 +53,7 @@ public class ScreenPowerCalculatorTest {
mStatsRule.initMeasuredEnergyStatsLocked();
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0);
batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
batteryStats.updateDisplayMeasuredEnergyStatsLocked(0, Display.STATE_ON, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
@@ -70,7 +70,7 @@ public class ScreenPowerCalculatorTest {
batteryStats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON,
60 * MINUTE_IN_MS);
batteryStats.noteScreenStateLocked(Display.STATE_OFF,
batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
@@ -133,20 +133,20 @@ public class ScreenPowerCalculatorTest {
public void testPowerProfileBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(255, 0, 0);
batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
batteryStats.noteScreenBrightnessLocked(100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(0, 100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(0, 200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_CACHED_EMPTY, false,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
batteryStats.noteScreenStateLocked(Display.STATE_OFF,
batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);

View File

@@ -113,6 +113,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
@GuardedBy("this")
private int mScreenState;
@GuardedBy("this")
private int[] mPerDisplayScreenStates = null;
@GuardedBy("this")
private boolean mUseLatestStates = true;
@@ -291,8 +294,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
@Override
public Future<?> scheduleSyncDueToScreenStateChange(
int flags, boolean onBattery, boolean onBatteryScreenOff, int screenState) {
public Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery,
boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates) {
synchronized (BatteryExternalStatsWorker.this) {
if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
mOnBattery = onBattery;
@@ -301,6 +304,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
// always update screen state
mScreenState = screenState;
mPerDisplayScreenStates = perDisplayScreenStates;
return scheduleSyncLocked("screen-state", flags);
}
}
@@ -432,6 +436,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
final boolean onBattery;
final boolean onBatteryScreenOff;
final int screenState;
final int[] displayScreenStates;
final boolean useLatestStates;
synchronized (BatteryExternalStatsWorker.this) {
updateFlags = mUpdateFlags;
@@ -440,6 +445,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
onBattery = mOnBattery;
onBatteryScreenOff = mOnBatteryScreenOff;
screenState = mScreenState;
displayScreenStates = mPerDisplayScreenStates;
useLatestStates = mUseLatestStates;
mUpdateFlags = 0;
mCurrentReason = null;
@@ -461,7 +467,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
try {
updateExternalStatsLocked(reason, updateFlags, onBattery,
onBatteryScreenOff, screenState, useLatestStates);
onBatteryScreenOff, screenState, displayScreenStates,
useLatestStates);
} finally {
if (DEBUG) {
Slog.d(TAG, "end updateExternalStatsSync");
@@ -506,7 +513,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
@GuardedBy("mWorkerLock")
private void updateExternalStatsLocked(final String reason, int updateFlags, boolean onBattery,
boolean onBatteryScreenOff, int screenState, boolean useLatestStates) {
boolean onBatteryScreenOff, int screenState, int[] displayScreenStates,
boolean useLatestStates) {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
@@ -661,7 +669,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
if (measuredEnergyDeltas != null) {
final long[] displayChargeUC = measuredEnergyDeltas.displayChargeUC;
if (displayChargeUC != null && displayChargeUC.length > 0) {
// TODO (b/194107383): pass all display ordinals to mStats.
// TODO (b/194107383): pass all display ordinals to mStats with
// displayScreenStates
final long primaryDisplayChargeUC = displayChargeUC[0];
// If updating, pass in what BatteryExternalStatsWorker thinks screenState is.
mStats.updateDisplayMeasuredEnergyStatsLocked(primaryDisplayChargeUC,

View File

@@ -1215,7 +1215,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mHandler.post(() -> {
if (DBG) Slog.d(TAG, "begin noteScreenState");
synchronized (mStats) {
mStats.noteScreenStateLocked(state, elapsedRealtime, uptime, currentTime);
mStats.noteScreenStateLocked(0, state, elapsedRealtime, uptime, currentTime);
}
if (DBG) Slog.d(TAG, "end noteScreenState");
});
@@ -1230,7 +1230,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
synchronized (mStats) {
mStats.noteScreenBrightnessLocked(brightness, elapsedRealtime, uptime);
mStats.noteScreenBrightnessLocked(0, brightness, elapsedRealtime, uptime);
}
});
}

View File

@@ -202,6 +202,7 @@ public class BatteryExternalStatsWorkerTest {
public class TestBatteryStatsImpl extends BatteryStatsImpl {
public TestBatteryStatsImpl(Context context) {
mPowerProfile = new PowerProfile(context, true /* forTest */);
initTimersAndCounters();
}
}