Loading core/java/android/app/IActivityManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -685,6 +685,14 @@ interface IActivityManager { */ boolean enableAppFreezer(in boolean enable); /** * Suppress or reenable the rate limit on foreground service notification deferral. * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG. * * @param enable false to suppress rate-limit policy; true to reenable it. */ boolean enableFgsNotificationRateLimit(in boolean enable); /** * Holds the AM lock for the specified amount of milliseconds. * This is intended for use by the tests that need to imitate lock contention. Loading services/core/java/com/android/server/am/ActiveServices.java +45 −2 Original line number Diff line number Diff line Loading @@ -249,6 +249,14 @@ public final class ActiveServices { */ final ArrayList<ServiceRecord> mPendingFgsNotifications = new ArrayList<>(); /** * Whether there is a rate limit that suppresses immediate re-deferral of new FGS * notifications from each app. On by default, disabled only by shell command for * test-suite purposes. To disable the behavior more generally, use the usual * DeviceConfig mechanism to set the rate limit interval to zero. */ private boolean mFgsDeferralRateLimited = true; /** * Uptime at which a given uid becomes eliglible again for FGS notification deferral */ Loading Loading @@ -2142,8 +2150,10 @@ public final class ActiveServices { } } if (mFgsDeferralRateLimited) { final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime; mFgsDeferralEligible.put(uid, nextEligible); } r.fgDisplayTime = when; r.mFgsNotificationDeferred = true; r.mFgsNotificationShown = false; Loading Loading @@ -2204,6 +2214,38 @@ public final class ActiveServices { } }; /** * Suppress or reenable the rate limit on foreground service notification deferral. * Invoked from the activity manager shell command. * * @param enable false to suppress rate-limit policy; true to reenable it. */ boolean enableFgsNotificationRateLimitLocked(final boolean enable) { if (enable != mFgsDeferralRateLimited) { mFgsDeferralRateLimited = enable; if (!enable) { // make sure to reset any active rate limiting mFgsDeferralEligible.clear(); } } return enable; } private void removeServiceNotificationDeferralsLocked(String packageName, final @UserIdInt int userId) { for (int i = mPendingFgsNotifications.size() - 1; i >= 0; i--) { final ServiceRecord r = mPendingFgsNotifications.get(i); if (userId == r.userId && r.appInfo.packageName.equals(packageName)) { mPendingFgsNotifications.remove(i); if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Removing notification deferral for " + r); } } } } private void maybeLogFGSStateEnteredLocked(ServiceRecord r) { if (r.mLogEntering) { logFGSStateChangeLocked(r, Loading Loading @@ -4689,6 +4731,7 @@ public final class ActiveServices { } } removeServiceRestartBackoffEnabledLocked(packageName); removeServiceNotificationDeferralsLocked(packageName, userId); } void cleanUpServices(int userId, ComponentName component, Intent baseIntent) { Loading services/core/java/com/android/server/am/ActivityManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -17065,6 +17065,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } /** * Suppress or reenable the rate limit on foreground service notification deferral. * @param enable false to suppress rate-limit policy; true to reenable it. */ @Override public boolean enableFgsNotificationRateLimit(boolean enable) { enforceCallingPermission(permission.WRITE_DEVICE_CONFIG, "enableFgsNotificationRateLimit"); synchronized (this) { return mServices.enableFgsNotificationRateLimitLocked(enable); } } /** * Holds the AM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention. services/core/java/com/android/server/am/ActivityManagerShellCommand.java +22 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runBugReport(pw); case "force-stop": return runForceStop(pw); case "fgs-notification-rate-limit": return runFgsNotificationRateLimit(pw); case "crash": return runCrash(pw); case "kill": Loading Loading @@ -1103,6 +1105,24 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } int runFgsNotificationRateLimit(PrintWriter pw) throws RemoteException { final String toggleValue = getNextArgRequired(); final boolean enable; switch (toggleValue) { case "enable": enable = true; break; case "disable": enable = false; break; default: throw new IllegalArgumentException( "Argument must be either 'enable' or 'disable'"); } mInterface.enableFgsNotificationRateLimit(enable); return 0; } int runCrash(PrintWriter pw) throws RemoteException { int userId = UserHandle.USER_ALL; Loading Loading @@ -3303,6 +3323,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" when done to select where it should be delivered. Options are:"); pw.println(" --progress: will launch a notification right away to show its progress."); pw.println(" --telephony: will dump only telephony sections."); pw.println(" fgs-notification-rate-limit {enable | disable}"); pw.println(" Enable/disable rate limit on FGS notification deferral policy."); pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>"); pw.println(" Completely stop the given application package."); pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>"); Loading Loading
core/java/android/app/IActivityManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -685,6 +685,14 @@ interface IActivityManager { */ boolean enableAppFreezer(in boolean enable); /** * Suppress or reenable the rate limit on foreground service notification deferral. * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG. * * @param enable false to suppress rate-limit policy; true to reenable it. */ boolean enableFgsNotificationRateLimit(in boolean enable); /** * Holds the AM lock for the specified amount of milliseconds. * This is intended for use by the tests that need to imitate lock contention. Loading
services/core/java/com/android/server/am/ActiveServices.java +45 −2 Original line number Diff line number Diff line Loading @@ -249,6 +249,14 @@ public final class ActiveServices { */ final ArrayList<ServiceRecord> mPendingFgsNotifications = new ArrayList<>(); /** * Whether there is a rate limit that suppresses immediate re-deferral of new FGS * notifications from each app. On by default, disabled only by shell command for * test-suite purposes. To disable the behavior more generally, use the usual * DeviceConfig mechanism to set the rate limit interval to zero. */ private boolean mFgsDeferralRateLimited = true; /** * Uptime at which a given uid becomes eliglible again for FGS notification deferral */ Loading Loading @@ -2142,8 +2150,10 @@ public final class ActiveServices { } } if (mFgsDeferralRateLimited) { final long nextEligible = when + mAm.mConstants.mFgsNotificationDeferralExclusionTime; mFgsDeferralEligible.put(uid, nextEligible); } r.fgDisplayTime = when; r.mFgsNotificationDeferred = true; r.mFgsNotificationShown = false; Loading Loading @@ -2204,6 +2214,38 @@ public final class ActiveServices { } }; /** * Suppress or reenable the rate limit on foreground service notification deferral. * Invoked from the activity manager shell command. * * @param enable false to suppress rate-limit policy; true to reenable it. */ boolean enableFgsNotificationRateLimitLocked(final boolean enable) { if (enable != mFgsDeferralRateLimited) { mFgsDeferralRateLimited = enable; if (!enable) { // make sure to reset any active rate limiting mFgsDeferralEligible.clear(); } } return enable; } private void removeServiceNotificationDeferralsLocked(String packageName, final @UserIdInt int userId) { for (int i = mPendingFgsNotifications.size() - 1; i >= 0; i--) { final ServiceRecord r = mPendingFgsNotifications.get(i); if (userId == r.userId && r.appInfo.packageName.equals(packageName)) { mPendingFgsNotifications.remove(i); if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Removing notification deferral for " + r); } } } } private void maybeLogFGSStateEnteredLocked(ServiceRecord r) { if (r.mLogEntering) { logFGSStateChangeLocked(r, Loading Loading @@ -4689,6 +4731,7 @@ public final class ActiveServices { } } removeServiceRestartBackoffEnabledLocked(packageName); removeServiceNotificationDeferralsLocked(packageName, userId); } void cleanUpServices(int userId, ComponentName component, Intent baseIntent) { Loading
services/core/java/com/android/server/am/ActivityManagerService.java +13 −0 Original line number Diff line number Diff line Loading @@ -17065,6 +17065,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } /** * Suppress or reenable the rate limit on foreground service notification deferral. * @param enable false to suppress rate-limit policy; true to reenable it. */ @Override public boolean enableFgsNotificationRateLimit(boolean enable) { enforceCallingPermission(permission.WRITE_DEVICE_CONFIG, "enableFgsNotificationRateLimit"); synchronized (this) { return mServices.enableFgsNotificationRateLimitLocked(enable); } } /** * Holds the AM lock for the specified amount of milliseconds. * Intended for use by the tests that need to imitate lock contention.
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +22 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runBugReport(pw); case "force-stop": return runForceStop(pw); case "fgs-notification-rate-limit": return runFgsNotificationRateLimit(pw); case "crash": return runCrash(pw); case "kill": Loading Loading @@ -1103,6 +1105,24 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } int runFgsNotificationRateLimit(PrintWriter pw) throws RemoteException { final String toggleValue = getNextArgRequired(); final boolean enable; switch (toggleValue) { case "enable": enable = true; break; case "disable": enable = false; break; default: throw new IllegalArgumentException( "Argument must be either 'enable' or 'disable'"); } mInterface.enableFgsNotificationRateLimit(enable); return 0; } int runCrash(PrintWriter pw) throws RemoteException { int userId = UserHandle.USER_ALL; Loading Loading @@ -3303,6 +3323,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" when done to select where it should be delivered. Options are:"); pw.println(" --progress: will launch a notification right away to show its progress."); pw.println(" --telephony: will dump only telephony sections."); pw.println(" fgs-notification-rate-limit {enable | disable}"); pw.println(" Enable/disable rate limit on FGS notification deferral policy."); pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>"); pw.println(" Completely stop the given application package."); pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>"); Loading