summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java7
-rw-r--r--core/api/system-current.txt1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java32
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java28
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java2
11 files changed, 141 insertions, 28 deletions
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 711caf7feb62..8e9f4746798f 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -397,6 +397,13 @@ public class PowerExemptionManager {
*/
public static final int REASON_PACKAGE_INSTALLER = 326;
+ /**
+ * {@link android.app.AppOpsManager#OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS}
+ * set to MODE_ALLOWED
+ * @hide
+ */
+ public static final int REASON_SYSTEM_EXEMPT_APP_OP = 327;
+
/** @hide The app requests out-out. */
public static final int REASON_OPT_OUT_REQUESTED = 1000;
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cc8bb8df6eea..a28f9c3cccc9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1301,6 +1301,7 @@ package android.app.admin {
field public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = 1; // 0x1
field public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4; // 0x4
field public static final int EXEMPT_FROM_HIBERNATION = 3; // 0x3
+ field public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 5; // 0x5
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ac65a6b5c048..6a68aaa62522 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3914,6 +3914,16 @@ public class DevicePolicyManager {
public static final int EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION = 4;
/**
+ * Exempt an app from all power-related restrictions, including app standby and doze.
+ * In addition, the app will be able to start foreground services from the background,
+ * and the user will not be able to stop foreground services run by the app.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EXEMPT_FROM_POWER_RESTRICTIONS = 5;
+
+ /**
* Exemptions to platform restrictions, given to an application through
* {@link #setApplicationExemptions(String, Set)}.
*
@@ -3924,7 +3934,8 @@ public class DevicePolicyManager {
EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
EXEMPT_FROM_HIBERNATION,
- EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION
+ EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
+ EXEMPT_FROM_POWER_RESTRICTIONS
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationExemptionConstants {}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
index 2e8f36834584..8fd4e912e04a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
@@ -16,6 +16,9 @@
package com.android.settingslib.fuelgauge;
+import static android.provider.DeviceConfig.NAMESPACE_ACTIVITY_MANAGER;
+
+import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -23,6 +26,7 @@ import android.content.pm.PackageManager;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.provider.DeviceConfig;
import android.telecom.DefaultDialerManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -42,6 +46,10 @@ public class PowerAllowlistBackend {
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
+ private static final String SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED =
+ "system_exempt_power_restrictions_enabled";
+ private static final boolean DEFAULT_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED = true;
+
private static PowerAllowlistBackend sInstance;
private final Context mAppContext;
@@ -76,12 +84,12 @@ public class PowerAllowlistBackend {
/**
* Check if target package is in allow list
*/
- public boolean isAllowlisted(String pkg) {
+ public boolean isAllowlisted(String pkg, int uid) {
if (mAllowlistedApps.contains(pkg)) {
return true;
}
- if (isDefaultActiveApp(pkg)) {
+ if (isDefaultActiveApp(pkg, uid)) {
return true;
}
@@ -91,7 +99,7 @@ public class PowerAllowlistBackend {
/**
* Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..)
*/
- public boolean isDefaultActiveApp(String pkg) {
+ public boolean isDefaultActiveApp(String pkg, int uid) {
// Additionally, check if pkg is default dialer/sms. They are considered essential apps and
// should be automatically allowlisted (otherwise user may be able to set restriction on
// them, leading to bad device behavior.)
@@ -106,9 +114,23 @@ public class PowerAllowlistBackend {
return true;
}
+ final AppOpsManager appOpsManager = mAppContext.getSystemService(AppOpsManager.class);
+ if (isSystemExemptFlagEnabled() && appOpsManager.checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid, pkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+
return false;
}
+ private static boolean isSystemExemptFlagEnabled() {
+ return DeviceConfig.getBoolean(
+ NAMESPACE_ACTIVITY_MANAGER,
+ SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED,
+ DEFAULT_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED);
+ }
+
/**
* Check if target package is in allow list except idle app
*/
@@ -126,12 +148,12 @@ public class PowerAllowlistBackend {
* @param pkgs a list of packageName
* @return true when one of package is in allow list
*/
- public boolean isAllowlisted(String[] pkgs) {
+ public boolean isAllowlisted(String[] pkgs, int uid) {
if (ArrayUtils.isEmpty(pkgs)) {
return false;
}
for (String pkg : pkgs) {
- if (isAllowlisted(pkg)) {
+ if (isAllowlisted(pkg, uid)) {
return true;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
index 6caf7624e1bc..b656253ba147 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -51,11 +52,14 @@ public class PowerAllowlistBackendTest {
private static final String PACKAGE_ONE = "com.example.packageone";
private static final String PACKAGE_TWO = "com.example.packagetwo";
+ private static final int UID = 12345;
@Mock
private IDeviceIdleController mDeviceIdleService;
@Mock
private DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ private AppOpsManager mAppOpsManager;
private PowerAllowlistBackend mPowerAllowlistBackend;
private ShadowPackageManager mPackageManager;
private Context mContext;
@@ -73,6 +77,11 @@ public class PowerAllowlistBackendTest {
mPackageManager = Shadow.extract(mContext.getPackageManager());
mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
+ doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+ doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, UID, PACKAGE_ONE);
+ doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, UID, PACKAGE_TWO);
mPowerAllowlistBackend = new PowerAllowlistBackend(mContext, mDeviceIdleService);
}
@@ -82,34 +91,34 @@ public class PowerAllowlistBackendTest {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getFullPowerWhitelist();
mPowerAllowlistBackend.refreshList();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO, UID)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE}, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO}, UID)).isFalse();
mPowerAllowlistBackend.addApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO, UID)).isTrue();
assertThat(mPowerAllowlistBackend.isAllowlisted(
- new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
+ new String[] {PACKAGE_ONE, PACKAGE_TWO}, UID)).isTrue();
mPowerAllowlistBackend.removeApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO, UID)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE}, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO}, UID)).isFalse();
mPowerAllowlistBackend.removeApp(PACKAGE_ONE);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE);
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO, UID)).isFalse();
assertThat(mPowerAllowlistBackend.isAllowlisted(
- new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+ new String[] {PACKAGE_ONE, PACKAGE_TWO}, UID)).isFalse();
}
@Test
@@ -119,8 +128,8 @@ public class PowerAllowlistBackendTest {
mPowerAllowlistBackend.refreshList();
- assertThat(mPowerAllowlistBackend.isAllowlisted(testSms)).isTrue();
- assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testSms)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testSms, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testSms, UID)).isTrue();
}
@Test
@@ -130,16 +139,25 @@ public class PowerAllowlistBackendTest {
mPowerAllowlistBackend.refreshList();
- assertThat(mPowerAllowlistBackend.isAllowlisted(testDialer)).isTrue();
- assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testDialer)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testDialer, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testDialer, UID)).isTrue();
}
@Test
public void isAllowlisted_shouldAllowlistActiveDeviceAdminApp() {
doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE, UID)).isTrue();
+ }
+
+ @Test
+ public void isAllowlisted_shouldAllowlistAppWithSystemExemptAppOp() {
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, UID, PACKAGE_ONE);
+
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE, UID)).isTrue();
}
@Test
@@ -149,7 +167,7 @@ public class PowerAllowlistBackendTest {
assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE, UID)).isFalse();
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index 048d40c2a33d..5355865de093 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -701,7 +701,8 @@ class FgsManagerControllerImpl @Inject constructor(
PowerExemptionManager.REASON_PROC_STATE_PERSISTENT,
PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI,
PowerExemptionManager.REASON_ROLE_DIALER,
- PowerExemptionManager.REASON_SYSTEM_MODULE -> UIControl.HIDE_BUTTON
+ PowerExemptionManager.REASON_SYSTEM_MODULE,
+ PowerExemptionManager.REASON_SYSTEM_EXEMPT_APP_OP -> UIControl.HIDE_BUTTON
PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE ->
if (showStopBtnForUserAllowlistedApps) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 24ce684e3d99..2527e79c8b14 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -67,6 +67,7 @@ import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH;
import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_EXEMPT_APP_OP;
import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE;
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
@@ -2464,6 +2465,7 @@ public final class ActiveServices {
case REASON_ROLE_EMERGENCY:
case REASON_ALLOWLISTED_PACKAGE:
case REASON_PACKAGE_INSTALLER:
+ case REASON_SYSTEM_EXEMPT_APP_OP:
return PERMISSION_GRANTED;
default:
return PERMISSION_DENIED;
@@ -7567,6 +7569,16 @@ public final class ActiveServices {
if (ret == REASON_DENIED) {
final AppOpsManager appOpsManager = mAm.getAppOpsManager();
+ if (mAm.mConstants.mFlagSystemExemptPowerRestrictionsEnabled
+ && appOpsManager.checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, callingUid,
+ callingPackage) == AppOpsManager.MODE_ALLOWED) {
+ ret = REASON_SYSTEM_EXEMPT_APP_OP;
+ }
+ }
+
+ if (ret == REASON_DENIED) {
+ final AppOpsManager appOpsManager = mAm.getAppOpsManager();
if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, callingUid,
callingPackage) == AppOpsManager.MODE_ALLOWED) {
ret = REASON_OP_ACTIVATE_VPN;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 13f327c4bae0..44f475f92517 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -206,6 +206,8 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = 1;
private static final boolean DEFAULT_FGS_ALLOW_OPT_OUT = false;
+ private static final boolean DEFAULT_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED = true;
+
/**
* The extra delays we're putting to service restarts, based on current memory pressure.
*/
@@ -343,6 +345,12 @@ final class ActivityManagerConstants extends ContentObserver {
"deferred_fgs_notification_exclusion_time_for_short";
/**
+ * Default value for mFlagSystemExemptPowerRestrictionEnabled.
+ */
+ private static final String KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED =
+ "system_exempt_power_restrictions_enabled";
+
+ /**
* Default value for mPushMessagingOverQuotaBehavior if not explicitly set in
* Settings.Global.
*/
@@ -617,6 +625,13 @@ final class ActivityManagerConstants extends ContentObserver {
volatile long mFgsNotificationDeferralExclusionTimeForShort =
mFgsNotificationDeferralExclusionTime;
+ // Indicates whether the system-applied exemption from all power restrictions is enabled.
+ // When the exemption is enabled, any app which has the OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS
+ // app op will be exempt from all power-related restrictions, including app standby
+ // and doze. In addition, the app will be able to start foreground services from the background,
+ // and the user will not be able to stop foreground services run by the app.
+ volatile boolean mFlagSystemExemptPowerRestrictionsEnabled = true;
+
/**
* When server pushing message is over the quote, select one of the temp allow list type as
* defined in {@link PowerExemptionManager.TempAllowListType}
@@ -1039,6 +1054,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_DEFERRED_FGS_NOTIFICATION_EXCLUSION_TIME_FOR_SHORT:
updateFgsNotificationDeferralExclusionTimeForShort();
break;
+ case KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED:
+ updateSystemExemptPowerRestrictionsEnabled();
+ break;
case KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR:
updatePushMessagingOverQuotaBehavior();
break;
@@ -1490,6 +1508,13 @@ final class ActivityManagerConstants extends ContentObserver {
/*default value*/ 2 * 60 * 1000L);
}
+ private void updateSystemExemptPowerRestrictionsEnabled() {
+ mFlagSystemExemptPowerRestrictionsEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED,
+ DEFAULT_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED);
+ }
+
private void updatePushMessagingOverQuotaBehavior() {
mPushMessagingOverQuotaBehavior = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -2057,6 +2082,9 @@ final class ActivityManagerConstants extends ContentObserver {
pw.print(" "); pw.print(KEY_DEFERRED_FGS_NOTIFICATION_EXCLUSION_TIME_FOR_SHORT);
pw.print("="); pw.println(mFgsNotificationDeferralExclusionTimeForShort);
+ pw.print(" "); pw.print(KEY_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED);
+ pw.print("="); pw.println(mFlagSystemExemptPowerRestrictionsEnabled);
+
pw.print(" "); pw.print(KEY_SHORT_FGS_TIMEOUT_DURATION);
pw.print("="); pw.println(mShortFgsTimeoutDuration);
pw.print(" "); pw.print(KEY_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION);
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 6abf6d8e9eea..2d779c4c85a1 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -72,6 +72,7 @@ import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
import static android.os.PowerExemptionManager.REASON_ROLE_DIALER;
import static android.os.PowerExemptionManager.REASON_ROLE_EMERGENCY;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_EXEMPT_APP_OP;
import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE;
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.getExemptionReasonForStatsd;
@@ -2855,6 +2856,7 @@ public final class AppRestrictionController {
int getPotentialSystemExemptionReason(int uid, String pkg) {
final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
+ final AppOpsManager appOpsManager = mInjector.getAppOpsManager();
final int userId = UserHandle.getUserId(uid);
if (isSystemModule(pkg)) {
return REASON_SYSTEM_MODULE;
@@ -2868,6 +2870,11 @@ public final class AppRestrictionController {
return REASON_DPO_PROTECTED_APP;
} else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) {
return REASON_ACTIVE_DEVICE_ADMIN;
+ } else if (mActivityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled
+ && appOpsManager.checkOpNoThrow(
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid, pkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ return REASON_SYSTEM_EXEMPT_APP_OP;
}
return REASON_DENIED;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c847aa25cd44..1ba9c3d872b7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -36,6 +36,7 @@ import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
+import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
@@ -66,6 +67,7 @@ import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_APP_STANDBY;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_HIBERNATION;
+import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_POWER_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -742,6 +744,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION,
OPSTR_SYSTEM_EXEMPT_FROM_FGS_BG_START_WHILE_IN_USE_PERMISSION_RESTRICTION);
+ APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
+ EXEMPT_FROM_POWER_RESTRICTIONS, OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS);
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index f02571fe7cd1..3042edec6aad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -36,6 +36,7 @@ import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
@@ -324,6 +325,7 @@ public final class BackgroundRestrictionTest {
OP_FINE_LOCATION,
OP_CAMERA,
OP_RECORD_AUDIO,
+ OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS,
};
for (int op : ops) {
setAppOpState(packageName, uid, op, false);