diff options
6 files changed, 77 insertions, 3 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 471b14885b62..115901a16d3d 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1713,6 +1713,7 @@ package android.os { } public final class PowerManager { + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void forceLowPowerStandbyActive(boolean); field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED"; field @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public static final int SYSTEM_WAKELOCK = -2147483648; // 0x80000000 } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index b59409ef2de4..f4c691d2f30e 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -68,6 +68,7 @@ interface IPowerManager boolean isLowPowerStandbySupported(); boolean isLowPowerStandbyEnabled(); void setLowPowerStandbyEnabled(boolean enabled); + void forceLowPowerStandbyActive(boolean active); @UnsupportedAppUsage void reboot(boolean confirm, String reason, boolean wait); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index c0d4347e6857..c5e5438c2e63 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2215,6 +2215,26 @@ public final class PowerManager { } /** + * Force Low Power Standby restrictions to be active. + * Does nothing if Low Power Standby is not supported. + * + * @see #isLowPowerStandbySupported() + * @hide + */ + @TestApi + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, + android.Manifest.permission.DEVICE_POWER + }) + public void forceLowPowerStandbyActive(boolean active) { + try { + mService.forceLowPowerStandbyActive(active); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Return whether the given application package name is on the device's power allowlist. * Apps can be placed on the allowlist through the settings UI invoked by * {@link android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}. diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java index 27c1d3a8fc1b..1e326a6c8540 100644 --- a/services/core/java/com/android/server/power/LowPowerStandbyController.java +++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java @@ -149,6 +149,10 @@ public final class LowPowerStandbyController { @GuardedBy("mLock") private boolean mIdleSinceNonInteractive; + /** Force Low Power Standby to be active. */ + @GuardedBy("mLock") + private boolean mForceActive; + /** Functional interface for providing time. */ @VisibleForTesting interface Clock { @@ -211,12 +215,14 @@ public final class LowPowerStandbyController { (now - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig; final boolean maintenanceMode = mIdleSinceNonInteractive && !mIsDeviceIdle; final boolean newActive = - mIsEnabled && !mIsInteractive && standbyTimeoutExpired && !maintenanceMode; + mForceActive || (mIsEnabled && !mIsInteractive && standbyTimeoutExpired + && !maintenanceMode); if (DEBUG) { Slog.d(TAG, "updateActiveLocked: mIsEnabled=" + mIsEnabled + ", mIsInteractive=" + mIsInteractive + ", standbyTimeoutExpired=" + standbyTimeoutExpired + ", mIdleSinceNonInteractive=" + mIdleSinceNonInteractive + ", mIsDeviceIdle=" - + mIsDeviceIdle + ", mIsActive=" + mIsActive + ", newActive=" + newActive); + + mIsDeviceIdle + ", mForceActive=" + mForceActive + ", mIsActive=" + mIsActive + + ", newActive=" + newActive); } if (mIsActive != newActive) { mIsActive = newActive; @@ -410,6 +416,13 @@ public final class LowPowerStandbyController { } } + void forceActive(boolean active) { + synchronized (mLock) { + mForceActive = active; + updateActiveLocked(); + } + } + void dump(PrintWriter pw) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); @@ -428,7 +441,7 @@ public final class LowPowerStandbyController { ipw.print("mStandbyTimeoutConfig="); ipw.println(mStandbyTimeoutConfig); - if (mIsEnabled) { + if (mIsActive || mIsEnabled) { ipw.print("mIsInteractive="); ipw.println(mIsInteractive); ipw.print("mLastInteractiveTime="); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index afadda792683..dd455e381d39 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -5902,6 +5902,27 @@ public final class PowerManagerService extends SystemService } } + @Override // Binder call + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, + android.Manifest.permission.DEVICE_POWER + }) + public void forceLowPowerStandbyActive(boolean active) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER) + != PackageManager.PERMISSION_GRANTED) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, + "forceLowPowerStandbyActive"); + } + + final long ident = Binder.clearCallingIdentity(); + try { + mLowPowerStandbyController.forceActive(active); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + /** * Gets the reason for the last time the phone had to reboot. * diff --git a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java index 2fc399eb0a9d..9117c3278818 100644 --- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java @@ -338,6 +338,24 @@ public class LowPowerStandbyControllerTest { verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {}); } + @Test + public void testForceActive() throws Exception { + setLowPowerStandbySupportedConfig(false); + mController.systemReady(); + + mController.forceActive(true); + mTestLooper.dispatchAll(); + + assertThat(mController.isActive()).isTrue(); + verify(mPowerManagerInternalMock).setLowPowerStandbyActive(true); + + mController.forceActive(false); + mTestLooper.dispatchAll(); + + assertThat(mController.isActive()).isFalse(); + verify(mPowerManagerInternalMock).setLowPowerStandbyActive(false); + } + private void setLowPowerStandbySupportedConfig(boolean supported) { when(mResourcesSpy.getBoolean( com.android.internal.R.bool.config_lowPowerStandbySupported)) |