From e57eb6d07e403bf4bd0c25d76faacddecbac1e5a Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Mon, 6 Dec 2021 15:01:29 +0100 Subject: [PATCH] Add TestApi to force Low Power Standby to be active Since Low Power Standby depends on multiple factors to activate, including the private device configuration for the delay after the device becomes non-interactive, having this TestApi makes testing faster and more reliable. Bug: 190822356 Test: atest LowPowerStandbyTest Change-Id: I5a16083f996bd7421197b08c6632655c8c3d8c29 --- core/api/test-current.txt | 1 + core/java/android/os/IPowerManager.aidl | 1 + core/java/android/os/PowerManager.java | 20 ++++++++++++++++++ .../power/LowPowerStandbyController.java | 19 ++++++++++++++--- .../server/power/PowerManagerService.java | 21 +++++++++++++++++++ .../power/LowPowerStandbyControllerTest.java | 18 ++++++++++++++++ 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 471b14885b62b..115901a16d3db 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 b59409ef2de4f..f4c691d2f30e9 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 c0d4347e68574..c5e5438c2e635 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2214,6 +2214,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 diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java index 27c1d3a8fc1bb..1e326a6c8540e 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 afadda792683c..dd455e381d396 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 2fc399eb0a9de..9117c32788184 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))