diff options
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); |