diff options
| author | 2021-04-22 19:13:08 -0700 | |
|---|---|---|
| committer | 2021-04-29 16:27:41 -0700 | |
| commit | a6b92260d391544de5453772f81ae16a465de1d0 (patch) | |
| tree | 8327502eb0722115c3401204c2de049cfe7f9b2a | |
| parent | 329a11f7c6158c4c5fc0e6ea03491c099febc7b0 (diff) | |
Do not allow FGS start when temp allowlist reasonCode is REASON_PUSH_MESSAGING_OVER_QUOTA
If temp allowlist reasonCode is REASON_PUSH_MESSAGING_OVER_QUOTA, check
DeviceConfig key "push_messaging_over_quota_behavior" to decide if
temp allowlist and FGS start are allowed. Three options:
1. -1, temp allowlist not allowed, FGS start not allowed.
2. 0, temp allowlist allowed, FGS start allowed.
3. 1, temp allowlist allowed, FGS start not allowed. This is default.
The device config command to change the behavior:
adb shell device_config set activity_manager push_messaging_over_quota_behavior <-1|0|1>
If temp allowlist reasonCode is REASON_DENIED, do not allow temp allowlist
at all.
Also, in DeviceIdleController.addPowerSaveTempAllowlistAppInternal(),
there used to be a check if the callingUid is on the mPowerSaveWhitelistSystemAppIds list,
this is unnecessary because upstream callers already checked if callingUid has
permission CHANGE_DEVICE_IDLE_TEMP_WHITELIST, and this permission is a privileged permission,
so removing the check of mPowerSaveWhitelistSystemAppIds should be safe.
Bug: 182796372
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testPushMessagingOverQuota
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testTempAllowListReasonCode
Change-Id: Id34b1c26c819dc4fe07838eb2e3a8f0138cbcf8f
5 files changed, 98 insertions, 17 deletions
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java index a9ca5cf5a26a..caf7e7f4a4ed 100644 --- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java @@ -96,4 +96,13 @@ public interface DeviceIdleInternal { * that the device is stationary or in motion. */ void unregisterStationaryListener(StationaryListener listener); + + /** + * Apply some restrictions on temp allowlist type based on the reasonCode. + * @param reasonCode temp allowlist reason code. + * @param defaultType default temp allowlist type if reasonCode can not decide a type. + * @return temp allowlist type based on the reasonCode. + */ + @TempAllowListType int getTempAllowListType(@ReasonCode int reasonCode, + @TempAllowListType int defaultType); } diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 57c8300b66f6..60f5769a46f7 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -19,6 +19,7 @@ package com.android.server; import static android.os.PowerExemptionManager.REASON_SHELL; import static android.os.PowerExemptionManager.REASON_UNKNOWN; import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; +import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE; import static android.os.Process.INVALID_UID; import android.Manifest; @@ -58,6 +59,7 @@ import android.os.Handler; import android.os.IDeviceIdleController; import android.os.Looper; import android.os.Message; +import android.os.PowerExemptionManager; import android.os.PowerExemptionManager.ReasonCode; import android.os.PowerExemptionManager.TempAllowListType; import android.os.PowerManager; @@ -2015,6 +2017,12 @@ public class DeviceIdleController extends SystemService public void unregisterStationaryListener(StationaryListener listener) { DeviceIdleController.this.unregisterStationaryListener(listener); } + + @Override + public @TempAllowListType int getTempAllowListType(@ReasonCode int reasonCode, + @TempAllowListType int defaultType) { + return DeviceIdleController.this.getTempAllowListType(reasonCode, defaultType); + } } private class LocalPowerAllowlistService implements PowerAllowlistInternal { @@ -2689,6 +2697,18 @@ public class DeviceIdleController extends SystemService } } + private @TempAllowListType int getTempAllowListType(@ReasonCode int reasonCode, + @TempAllowListType int defaultType) { + switch (reasonCode) { + case PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA: + return mLocalActivityManager.getPushMessagingOverQuotaBehavior(); + case PowerExemptionManager.REASON_DENIED: + return TEMPORARY_ALLOW_LIST_TYPE_NONE; + default: + return defaultType; + } + } + void addPowerSaveTempAllowlistAppChecked(String packageName, long duration, int userId, @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException { @@ -2705,9 +2725,12 @@ public class DeviceIdleController extends SystemService "addPowerSaveTempWhitelistApp", null); final long token = Binder.clearCallingIdentity(); try { - addPowerSaveTempAllowlistAppInternal(callingUid, - packageName, duration, TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, - userId, true, reasonCode, reason); + @TempAllowListType int type = getTempAllowListType(reasonCode, + TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED); + if (type != TEMPORARY_ALLOW_LIST_TYPE_NONE) { + addPowerSaveTempAllowlistAppInternal(callingUid, + packageName, duration, type, userId, true, reasonCode, reason); + } } finally { Binder.restoreCallingIdentity(token); } @@ -2741,16 +2764,6 @@ public class DeviceIdleController extends SystemService void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName, long durationMs, @TempAllowListType int tempAllowListType, int userId, boolean sync, @ReasonCode int reasonCode, @Nullable String reason) { - synchronized (this) { - int callingAppId = UserHandle.getAppId(callingUid); - if (callingAppId >= Process.FIRST_APPLICATION_UID) { - if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) { - throw new SecurityException( - "Calling app " + UserHandle.formatUid(callingUid) - + " is not on whitelist"); - } - } - } try { int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId); addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, durationMs, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 605340061994..ab610e4e71c6 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -583,4 +583,9 @@ public abstract class ActivityManagerInternal { * Is the FGS started from an uid temporarily allowed to have while-in-use permission? */ public abstract boolean isTempAllowlistedForFgsWhileInUse(int uid); + + /** + * Return the temp allowlist type when server push messaging is over the quota. + */ + public abstract @TempAllowListType int getPushMessagingOverQuotaBehavior(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index bf574521b895..d8eccef8488e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -16,6 +16,9 @@ package com.android.server.am; +import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED; +import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE; + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK; import android.app.ActivityThread; @@ -27,6 +30,7 @@ import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.os.PowerExemptionManager; import android.provider.DeviceConfig; import android.provider.DeviceConfig.OnPropertiesChangedListener; import android.provider.DeviceConfig.Properties; @@ -139,6 +143,11 @@ final class ActivityManagerConstants extends ContentObserver { private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000; private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000; private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 % + /** + * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} + */ + private static final int + DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = 1; // Flag stored in the DeviceConfig API. /** @@ -210,6 +219,13 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_DEFERRED_FGS_NOTIFICATION_EXCLUSION_TIME = "deferred_fgs_notification_exclusion_time"; + /** + * Default value for mPushMessagingOverQuotaBehavior if not explicitly set in + * Settings.Global. + */ + private static final String KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = + "push_messaging_over_quota_behavior"; + // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -413,6 +429,13 @@ final class ActivityManagerConstants extends ContentObserver { // before another FGS notifiction from that app can be deferred. volatile long mFgsNotificationDeferralExclusionTime = 2 * 60 * 1000L; + /** + * When server pushing message is over the quote, select one of the temp allow list type as + * defined in {@link PowerExemptionManager.TempAllowListType} + */ + volatile @PowerExemptionManager.TempAllowListType int mPushMessagingOverQuotaBehavior = + DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR; + /* * At boot time, broadcast receiver ACTION_BOOT_COMPLETED, ACTION_LOCKED_BOOT_COMPLETED and * ACTION_PRE_BOOT_COMPLETED are temp allowlisted to start FGS for a duration of time in @@ -605,6 +628,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_DEFERRED_FGS_NOTIFICATION_EXCLUSION_TIME: updateFgsNotificationDeferralExclusionTime(); break; + case KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR: + updatePushMessagingOverQuotaBehavior(); + break; case KEY_OOMADJ_UPDATE_POLICY: updateOomAdjUpdatePolicy(); break; @@ -909,6 +935,19 @@ final class ActivityManagerConstants extends ContentObserver { /*default value*/ 2 * 60 * 1000L); } + private void updatePushMessagingOverQuotaBehavior() { + mPushMessagingOverQuotaBehavior = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR, + DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR); + if (mPushMessagingOverQuotaBehavior < TEMPORARY_ALLOW_LIST_TYPE_NONE + || mPushMessagingOverQuotaBehavior + > TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED) { + mPushMessagingOverQuotaBehavior = + DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR; + } + } + private void updateOomAdjUpdatePolicy() { OOMADJ_UPDATE_QUICK = DeviceConfig.getInt( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -1166,6 +1205,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mFgsStartRestrictionCheckCallerTargetSdk); pw.print(" "); pw.print(KEY_FGS_ATOM_SAMPLE_RATE); pw.print("="); pw.println(mDefaultFgsAtomSampleRate); + pw.print(" "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR); + pw.print("="); pw.println(mPushMessagingOverQuotaBehavior); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 00b13b1bb6b0..9aedf1504df5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -51,7 +51,8 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import static android.os.IServiceManager.DUMP_FLAG_PROTO; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED; -import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; +import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; +import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE; import static android.os.Process.BLUETOOTH_UID; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.INVALID_UID; @@ -14603,15 +14604,20 @@ public class ActivityManagerService extends IActivityManager.Stub */ @GuardedBy("this") void tempAllowlistUidLocked(int targetUid, long duration, @ReasonCode int reasonCode, - String reason, int type, int callingUid) { + String reason, @TempAllowListType int type, int callingUid) { synchronized (mProcLock) { + // The temp allowlist type could change according to the reasonCode. + type = mLocalDeviceIdleController.getTempAllowListType(reasonCode, type); + if (type == TEMPORARY_ALLOW_LIST_TYPE_NONE) { + return; + } mPendingTempAllowlist.put(targetUid, new PendingTempAllowlist(targetUid, duration, reasonCode, reason, type, callingUid)); setUidTempAllowlistStateLSP(targetUid, true); mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget(); - if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { + if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { mFgsStartTempAllowList.add(targetUid, duration, new FgsTempAllowListItem(duration, reasonCode, reason, callingUid)); } @@ -15285,7 +15291,7 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (mProcLock) { mDeviceIdleTempAllowlist = appids; if (adding) { - if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { + if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) { mFgsStartTempAllowList.add(changingUid, durationMs, new FgsTempAllowListItem(durationMs, reasonCode, reason, callingUid)); @@ -16152,6 +16158,13 @@ public class ActivityManagerService extends IActivityManager.Stub return mServices.canAllowWhileInUsePermissionInFgsLocked(pid, uid, packageName); } } + + @Override + public @TempAllowListType int getPushMessagingOverQuotaBehavior() { + synchronized (ActivityManagerService.this) { + return mConstants.mPushMessagingOverQuotaBehavior; + } + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { |