Add LowPowerStandby allowed Reason: Temp PowerSave Allowlist
When ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST is set in the Low Power
Standby policy, apps on the temporary power-save allowlist will be
exempt from Low Power Standby restrictions.
Bug: 234002812
Test: atest LowPowerStandbyControllerTest LowPowerStandbyTest
Change-Id: I5575e38d5c6ede861f2543326f9135895dce2a23
diff --git a/core/api/current.txt b/core/api/current.txt
index d5be322..0db4569 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -32859,6 +32859,7 @@
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 b675587..30df189 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2957,6 +2957,7 @@
*/
@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 {
@@ -2969,6 +2970,13 @@
*/
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) {
@@ -2977,6 +2985,10 @@
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 223bd55..0dc5f76 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.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 @@
@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 @@
}
}
};
+ private final TempAllowlistChangeListener mTempAllowlistChangeListener =
+ new TempAllowlistChangeListener();
private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -318,7 +322,7 @@
updateSettingsLocked();
if (mIsEnabled) {
- registerBroadcastReceiver();
+ registerListeners();
}
}
@@ -594,7 +598,7 @@
onNonInteractive();
}
- registerBroadcastReceiver();
+ registerListeners();
}
@GuardedBy("mLock")
@@ -604,7 +608,7 @@
}
cancelStandbyTimeoutAlarmLocked();
- unregisterBroadcastReceiver();
+ unregisterListeners();
updateActiveLocked();
}
@@ -629,13 +633,13 @@
}
}
- 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 @@
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 @@
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 6553ea9..454d3f3 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 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 @@
private PowerManagerInternal mPowerManagerInternalMock;
@Mock
private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock;
+ @Mock
+ private PowerAllowlistInternal mPowerAllowlistInternalMock;
@Before
public void setUp() throws Exception {
@@ -130,6 +135,7 @@
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 @@
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class);
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerAllowlistInternal.class);
mTestPolicyFile.delete();
}
@@ -614,7 +621,7 @@
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 @@
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 @@
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));