Update dream battery drain monitoring to exclude when charging is being

artificially limited.

We may limit charging when battery is overheating, or due to dock defend
or other battery defend mechanisms. In these cases, the battery is
expected to drain while dreaming since charging is limited. Therefore,
do not exit dreams in this case.

Test: atest PowerManagerServiceTest
Fixes: 258027228
Change-Id: I10ce0c848892b42267d819d07a284d17a97899d1
This commit is contained in:
Lucas Silva
2022-11-14 22:53:07 -05:00
parent 2d7fb7b2b5
commit a233bba91e
5 changed files with 96 additions and 14 deletions

View File

@@ -46,6 +46,14 @@ public abstract class BatteryManagerInternal {
*/
public abstract int getBatteryLevel();
/**
* Returns battery health status as an integer representing the current battery health constant.
*
* This is a simple accessor that's safe to be called from any locks, but internally it may
* wait on the battery service lock.
*/
public abstract int getBatteryHealth();
/**
* Instantaneous battery capacity in uA-h, as defined in the HealthInfo HAL struct.
* Please note apparently it could be bigger than {@link #getBatteryFullCharge}.

View File

@@ -189,6 +189,8 @@ message PowerManagerServiceDumpProto {
optional bool is_enhanced_discharge_prediction_personalized = 54;
optional bool is_low_power_standby_active = 55;
optional LowPowerStandbyControllerDumpProto low_power_standby_controller = 56;
// The battery level drained by the dream.
optional int32 battery_level_drained_while_dreaming = 57;
}
// A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.

View File

@@ -1286,6 +1286,13 @@ public final class BatteryService extends SystemService {
}
}
@Override
public int getBatteryHealth() {
synchronized (mLock) {
return mHealthInfo.batteryHealth;
}
}
@Override
public boolean getBatteryLevelLow() {
synchronized (mLock) {

View File

@@ -419,6 +419,9 @@ public final class PowerManagerService extends SystemService
// The current battery level percentage.
private int mBatteryLevel;
// The amount of battery drained while the device has been in a dream state.
private int mDreamsBatteryLevelDrain;
// True if updatePowerStateLocked() is already in progress.
// TODO(b/215518989): Remove this once transactions are in place
private boolean mUpdatePowerStateInProgress;
@@ -451,11 +454,6 @@ public final class PowerManagerService extends SystemService
@GuardedBy("mEnhancedDischargeTimeLock")
private boolean mEnhancedDischargePredictionIsPersonalized;
// The battery level percentage at the time the dream started.
// This is used to terminate a dream and go to sleep if the battery is
// draining faster than it is charging and the user activity timeout has expired.
private int mBatteryLevelWhenDreamStarted;
// The current dock state.
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -2448,15 +2446,25 @@ public final class PowerManagerService extends SystemService
final int oldPlugType = mPlugType;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
final int oldBatteryLevel = mBatteryLevel;
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
final boolean isOverheat = mBatteryManagerInternal.getBatteryHealth()
== BatteryManager.BATTERY_HEALTH_OVERHEAT;
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
+ ", mIsPowered=" + mIsPowered
+ ", oldPlugType=" + oldPlugType
+ ", mPlugType=" + mPlugType
+ ", mBatteryLevel=" + mBatteryLevel);
+ ", oldBatteryLevel=" + oldBatteryLevel
+ ", mBatteryLevel=" + mBatteryLevel
+ ", isOverheat=" + isOverheat);
}
if (!isOverheat && oldBatteryLevel > 0
&& getGlobalWakefulnessLocked() == WAKEFULNESS_DREAMING) {
mDreamsBatteryLevelDrain += (oldBatteryLevel - mBatteryLevel);
}
if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
@@ -3278,7 +3286,7 @@ public final class PowerManagerService extends SystemService
// Remember the initial battery level when the dream started.
if (startDreaming && isDreaming) {
mBatteryLevelWhenDreamStarted = mBatteryLevel;
mDreamsBatteryLevelDrain = 0;
if (wakefulness == WAKEFULNESS_DOZING) {
Slog.i(TAG, "Dozing...");
} else {
@@ -3299,16 +3307,15 @@ public final class PowerManagerService extends SystemService
if (wakefulness == WAKEFULNESS_DREAMING) {
if (isDreaming && canDreamLocked(powerGroup)) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
&& mDreamsBatteryLevelDrain > mDreamsBatteryLevelDrainCutoffConfig
&& !isBeingKeptAwakeLocked(powerGroup)) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
Slog.i(TAG, "Stopping dream because the battery appears to "
+ "be draining faster than it is charging. "
+ "Battery level when dream started: "
+ mBatteryLevelWhenDreamStarted + "%. "
+ "Battery level drained while dreaming: "
+ mDreamsBatteryLevelDrain + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
return; // continue dreaming
@@ -3539,6 +3546,11 @@ public final class PowerManagerService extends SystemService
mScreenBrightnessBoostInProgress);
}
@VisibleForTesting
int getDreamsBatteryLevelDrain() {
return mDreamsBatteryLevelDrain;
}
private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
new DisplayManagerInternal.DisplayPowerCallbacks() {
@@ -4383,7 +4395,7 @@ public final class PowerManagerService extends SystemService
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
pw.println(" mBatteryLevel=" + mBatteryLevel);
pw.println(" mBatteryLevelWhenDreamStarted=" + mBatteryLevelWhenDreamStarted);
pw.println(" mDreamsBatteryLevelDrain=" + mDreamsBatteryLevelDrain);
pw.println(" mDockState=" + mDockState);
pw.println(" mStayOn=" + mStayOn);
pw.println(" mProximityPositive=" + mProximityPositive);
@@ -4625,8 +4637,8 @@ public final class PowerManagerService extends SystemService
proto.write(PowerManagerServiceDumpProto.PLUG_TYPE, mPlugType);
proto.write(PowerManagerServiceDumpProto.BATTERY_LEVEL, mBatteryLevel);
proto.write(
PowerManagerServiceDumpProto.BATTERY_LEVEL_WHEN_DREAM_STARTED,
mBatteryLevelWhenDreamStarted);
PowerManagerServiceDumpProto.BATTERY_LEVEL_DRAINED_WHILE_DREAMING,
mDreamsBatteryLevelDrain);
proto.write(PowerManagerServiceDumpProto.DOCK_STATE, mDockState);
proto.write(PowerManagerServiceDumpProto.IS_STAY_ON, mStayOn);
proto.write(PowerManagerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);

View File

@@ -375,6 +375,18 @@ public class PowerManagerServiceTest {
mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
}
private void setBatteryLevel(int batteryLevel) {
when(mBatteryManagerInternalMock.getBatteryLevel())
.thenReturn(batteryLevel);
mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
}
private void setBatteryHealth(int batteryHealth) {
when(mBatteryManagerInternalMock.getBatteryHealth())
.thenReturn(batteryHealth);
mBatteryReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_BATTERY_CHANGED));
}
private void setAttentiveTimeout(int attentiveTimeoutMillis) {
Settings.Secure.putInt(
mContextSpy.getContentResolver(), Settings.Secure.ATTENTIVE_TIMEOUT,
@@ -399,6 +411,12 @@ public class PowerManagerServiceTest {
.thenReturn(disable);
}
private void setDreamsBatteryLevelDrainConfig(int threshold) {
when(mResourcesSpy.getInteger(
com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff)).thenReturn(
threshold);
}
private void advanceTime(long timeMs) {
mClock.fastForward(timeMs);
mTestLooper.dispatchAll();
@@ -881,6 +899,41 @@ public class PowerManagerServiceTest {
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
}
@Test
public void testBatteryDrainDuringDream() {
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ENABLED, 1);
setMinimumScreenOffTimeoutConfig(100);
setDreamsBatteryLevelDrainConfig(5);
createService();
startSystem();
doAnswer(inv -> {
when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
return null;
}).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
setBatteryLevel(100);
setPluggedIn(true);
forceAwake(); // Needs to be awake first before it can dream.
forceDream();
advanceTime(10); // Allow async calls to happen
assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
setBatteryLevel(90);
advanceTime(10); // Allow async calls to happen
assertThat(mService.getDreamsBatteryLevelDrain()).isEqualTo(10);
// If battery overheat protection is enabled, we shouldn't count battery drain
setBatteryHealth(BatteryManager.BATTERY_HEALTH_OVERHEAT);
setBatteryLevel(70);
advanceTime(10); // Allow async calls to happen
assertThat(mService.getDreamsBatteryLevelDrain()).isEqualTo(10);
}
@Test
public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() {
final String suspendBlockerName = "PowerManagerService.Display";