diff options
4 files changed, 87 insertions, 10 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 7c92793c6281..88ee3a4c7cf4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -33312,6 +33312,7 @@ package android.os { field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1 field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0 field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4 + field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 2; // 0x2 field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1; // 0x1 field public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN = "com.android.lowpowerstandby.WAKE_ON_LAN"; field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000 diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 2142c4c625fe..13d54ef7b12a 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -2994,6 +2994,7 @@ public final class PowerManager { */ @IntDef(prefix = { "LOW_POWER_STANDBY_ALLOWED_REASON_" }, flag = true, value = { LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION, + LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST, }) @Retention(RetentionPolicy.SOURCE) public @interface LowPowerStandbyAllowedReason { @@ -3006,6 +3007,13 @@ public final class PowerManager { */ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1 << 0; + /** + * Exempts apps on the temporary powersave allowlist. + * + * @see #isAllowedInLowPowerStandby(int) + */ + public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 1 << 1; + /** @hide */ public static String lowPowerStandbyAllowedReasonsToString( @LowPowerStandbyAllowedReason int allowedReasons) { @@ -3014,6 +3022,10 @@ public final class PowerManager { allowedStrings.add("ALLOWED_REASON_VOICE_INTERACTION"); allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION; } + if ((allowedReasons & LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST) != 0) { + allowedStrings.add("ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST"); + allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; + } if (allowedReasons != 0) { allowedStrings.add(String.valueOf(allowedReasons)); } diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java index 223bd551b71d..0dc5f76dfd92 100644 --- a/services/core/java/com/android/server/power/LowPowerStandbyController.java +++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java @@ -16,6 +16,7 @@ package com.android.server.power; +import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString; import android.Manifest; @@ -59,6 +60,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.LocalServices; +import com.android.server.PowerAllowlistInternal; import com.android.server.net.NetworkPolicyManagerInternal; import org.xmlpull.v1.XmlPullParser; @@ -134,7 +136,7 @@ public class LowPowerStandbyController { @GuardedBy("mLock") private boolean mEnableCustomPolicy; - private final BroadcastReceiver mIdleBroadcastReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { @@ -150,6 +152,8 @@ public class LowPowerStandbyController { } } }; + private final TempAllowlistChangeListener mTempAllowlistChangeListener = + new TempAllowlistChangeListener(); private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() { @Override @@ -318,7 +322,7 @@ public class LowPowerStandbyController { updateSettingsLocked(); if (mIsEnabled) { - registerBroadcastReceiver(); + registerListeners(); } } @@ -594,7 +598,7 @@ public class LowPowerStandbyController { onNonInteractive(); } - registerBroadcastReceiver(); + registerListeners(); } @GuardedBy("mLock") @@ -604,7 +608,7 @@ public class LowPowerStandbyController { } cancelStandbyTimeoutAlarmLocked(); - unregisterBroadcastReceiver(); + unregisterListeners(); updateActiveLocked(); } @@ -629,13 +633,13 @@ public class LowPowerStandbyController { } } - private void registerBroadcastReceiver() { + private void registerListeners() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - mContext.registerReceiver(mIdleBroadcastReceiver, intentFilter); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); IntentFilter packageFilter = new IntentFilter(); packageFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE); @@ -648,12 +652,18 @@ public class LowPowerStandbyController { userFilter.addAction(Intent.ACTION_USER_ADDED); userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); + + PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); + pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener); } - private void unregisterBroadcastReceiver() { - mContext.unregisterReceiver(mIdleBroadcastReceiver); + private void unregisterListeners() { + mContext.unregisterReceiver(mBroadcastReceiver); mContext.unregisterReceiver(mPackageBroadcastReceiver); mContext.unregisterReceiver(mUserReceiver); + + PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); + pai.unregisterTempAllowlistChangeListener(mTempAllowlistChangeListener); } @GuardedBy("mLock") @@ -1197,4 +1207,18 @@ public class LowPowerStandbyController { onSettingsChanged(); } } + + final class TempAllowlistChangeListener implements + PowerAllowlistInternal.TempAllowlistChangeListener { + @Override + public void onAppAdded(int uid) { + addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); + } + + @Override + public void onAppRemoved(int uid) { + removeFromAllowlistInternal(uid, + LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); + } + } } 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 6553ea907563..454d3f32c96a 100644 --- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java @@ -16,6 +16,7 @@ package com.android.server.power; +import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION; import static android.os.PowerManager.LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN; @@ -62,6 +63,8 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.LocalServices; +import com.android.server.PowerAllowlistInternal; +import com.android.server.PowerAllowlistInternal.TempAllowlistChangeListener; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.power.LowPowerStandbyController.DeviceConfigWrapper; import com.android.server.testutils.OffsettableClock; @@ -117,6 +120,8 @@ public class LowPowerStandbyControllerTest { private PowerManagerInternal mPowerManagerInternalMock; @Mock private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock; + @Mock + private PowerAllowlistInternal mPowerAllowlistInternalMock; @Before public void setUp() throws Exception { @@ -130,6 +135,7 @@ public class LowPowerStandbyControllerTest { when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager); addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock); addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock); + addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock); when(mIPowerManagerMock.isInteractive()).thenReturn(true); @@ -169,6 +175,7 @@ public class LowPowerStandbyControllerTest { LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); + LocalServices.removeServiceForTest(PowerAllowlistInternal.class); mTestPolicyFile.delete(); } @@ -614,7 +621,7 @@ public class LowPowerStandbyControllerTest { InOrder inOrder = inOrder(mPowerManagerInternalMock); - inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] { + inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID), UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID), }); @@ -626,7 +633,7 @@ public class LowPowerStandbyControllerTest { mContextSpy.sendBroadcast(intent); mTestLooper.dispatchAll(); - inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] { + inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{ UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID) }); inOrder.verifyNoMoreInteractions(); @@ -663,6 +670,39 @@ public class LowPowerStandbyControllerTest { assertFalse(mController.isPackageExempt(TEST_PKG1_APP_ID)); } + @Test + public void testAllowReason_tempPowerSaveAllowlist() throws Exception { + mController.systemReady(); + mController.setEnabled(true); + mController.setPolicy(policyWithAllowedReasons( + LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST)); + mTestLooper.dispatchAll(); + + ArgumentCaptor<TempAllowlistChangeListener> tempAllowlistChangeListenerArgumentCaptor = + ArgumentCaptor.forClass(TempAllowlistChangeListener.class); + verify(mPowerAllowlistInternalMock).registerTempAllowlistChangeListener( + tempAllowlistChangeListenerArgumentCaptor.capture()); + TempAllowlistChangeListener tempAllowlistChangeListener = + tempAllowlistChangeListenerArgumentCaptor.getValue(); + + tempAllowlistChangeListener.onAppAdded(TEST_PKG1_APP_ID); + mTestLooper.dispatchAll(); + verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID}); + + tempAllowlistChangeListener.onAppAdded(TEST_PKG2_APP_ID); + mTestLooper.dispatchAll(); + verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist( + new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID}); + + tempAllowlistChangeListener.onAppRemoved(TEST_PKG1_APP_ID); + mTestLooper.dispatchAll(); + verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID}); + + mController.setPolicy(EMPTY_POLICY); + mTestLooper.dispatchAll(); + verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]); + } + private void setInteractive() throws Exception { when(mIPowerManagerMock.isInteractive()).thenReturn(true); mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON)); |