Merge "Allow FGS start for proc state BOUND_FOREGROUND_SERVICE and above."
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4a338b3..e1124ab 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Process.NFC_UID;
@@ -145,7 +146,7 @@
private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
public static final int FGS_FEATURE_DENIED = 0;
- public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 1;
+ public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
@@ -154,10 +155,12 @@
public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
+ public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
- FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+ FGS_FEATURE_ALLOWED_BY_UID_STATE,
FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
FGS_FEATURE_ALLOWED_BY_FLAG,
FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
@@ -165,7 +168,9 @@
FGS_FEATURE_ALLOWED_BY_TOKEN,
FGS_FEATURE_ALLOWED_BY_PERMISSION,
FGS_FEATURE_ALLOWED_BY_WHITELIST,
- FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER
+ FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
+ FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+ FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -576,18 +581,11 @@
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
&& (mAm.mConstants.mFlagFgsStartRestrictionEnabled
|| isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
- && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
- // uid is on DeviceIdleController's allowlist.
- Slog.d(TAG, "startForegroundService() mAllowStartForeground false "
- + "but allowlist true: service " + r.shortInstanceName);
- } else {
- Slog.w(TAG, "startForegroundService() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- return null;
- }
+ Slog.w(TAG, "startForegroundService() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ return null;
}
}
}
@@ -1488,20 +1486,12 @@
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
&& (mAm.mConstants.mFlagFgsStartRestrictionEnabled
|| isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
- && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
- // uid is on DeviceIdleController's allowlist.
- Slog.d(TAG, "Service.startForeground() "
- + "mAllowStartForeground false but allowlist true: service "
- + r.shortInstanceName);
- } else {
- Slog.w(TAG, "Service.startForeground() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- updateServiceForegroundLocked(r.app, true);
- ignoreForeground = true;
- }
+ Slog.w(TAG, "Service.startForeground() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ updateServiceForegroundLocked(r.app, true);
+ ignoreForeground = true;
}
}
}
@@ -4944,38 +4934,39 @@
r.mAllowWhileInUsePermissionInFgs = true;
}
- if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
- final @FgsFeatureRetCode int temp = shouldAllowFgsFeatureLocked(callingPackage,
- callingPid, callingUid, intent, r, allowBackgroundActivityStarts);
+ if (!r.mAllowWhileInUsePermissionInFgs
+ || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
+ final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
+ callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs = (temp != FGS_FEATURE_DENIED);
+ r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
- r.mAllowStartForeground = temp;
+ r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
+ callingPackage, callingPid, callingUid, intent, r,
+ allowBackgroundActivityStarts);
}
}
}
/**
- * Should allow FGS feature or not.
+ * Should allow while-in-use permissions in FGS or not.
+ * A typical BG started FGS is not allowed to have while-in-use permissions.
* @param callingPackage caller app's package name.
* @param callingUid caller app's uid.
- * @param intent intent to start/bind service.
* @param r the service to start.
* @return {@link FgsFeatureRetCode}
*/
- private @FgsFeatureRetCode int shouldAllowFgsFeatureLocked(String callingPackage,
- int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+ int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
int ret = FGS_FEATURE_DENIED;
- final StringBuilder sb = new StringBuilder(64);
final int uidState = mAm.getUidState(callingUid);
if (ret == FGS_FEATURE_DENIED) {
// Is the calling UID at PROCESS_STATE_TOP or above?
if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
- sb.append("uidState=").append(uidState);
- ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
}
}
@@ -5010,7 +5001,6 @@
}
if (isCallerSystem) {
- sb.append("callingUid=").append(callingAppId);
ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
}
}
@@ -5049,6 +5039,53 @@
ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
}
}
+ return ret;
+ }
+
+ /**
+ * Should allow the FGS to start (AKA startForeground()) or not.
+ * The check in this method is in addition to check in
+ * {@link #shouldAllowFgsWhileInUsePermissionLocked}
+ * @param allowWhileInUse the return code from {@link #shouldAllowFgsWhileInUsePermissionLocked}
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param intent intent to start/bind service.
+ * @param r the service to start.
+ * @return {@link FgsFeatureRetCode}
+ */
+ private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
+ @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
+ int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
+ int ret = allowWhileInUse;
+
+ final StringBuilder sb = new StringBuilder(64);
+ final int uidState = mAm.getUidState(callingUid);
+ if (ret == FGS_FEATURE_DENIED) {
+ // Is the calling UID at PROCESS_STATE_TOP or above?
+ if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
+ sb.append("uidState=").append(uidState);
+ ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+ if (pr.uid == callingUid
+ && pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ break;
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
+ && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
+ // uid is on DeviceIdleController's allowlist.
+ ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+ }
+ }
final String debugInfo =
"[callingPackage: " + callingPackage
@@ -5071,8 +5108,8 @@
switch (code) {
case FGS_FEATURE_DENIED:
return "DENIED";
- case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
- return "ALLOWED_BY_PROC_STATE";
+ case FGS_FEATURE_ALLOWED_BY_UID_STATE:
+ return "ALLOWED_BY_UID_STATE";
case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
return "ALLOWED_BY_UID_VISIBLE";
case FGS_FEATURE_ALLOWED_BY_FLAG:
@@ -5089,13 +5126,17 @@
return "ALLOWED_BY_WHITELIST";
case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
return "ALLOWED_BY_DEVICE_OWNER";
+ case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+ return "ALLOWED_BY_PROC_STATE";
+ case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
+ return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
default:
return "";
}
}
private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
- return code != FGS_FEATURE_ALLOWED_BY_PROC_STATE
+ return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
&& code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 01d0a6d..771f273 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1329,6 +1329,8 @@
app.setCached(false);
app.shouldNotFreeze = false;
+ app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -1349,6 +1351,7 @@
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
app.curCapability = PROCESS_CAPABILITY_ALL;
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
+ app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT);
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
@@ -1403,6 +1406,7 @@
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
+ app.bumpAllowStartFgsState(PROCESS_STATE_TOP);
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
}
@@ -1500,6 +1504,7 @@
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_FOREGROUND_SERVICE;
+ app.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
app.adjType = "fg-service";
app.setCached(false);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -1887,7 +1892,9 @@
// into the top state, since they are not on top. Instead
// give them the best bound state after that.
if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; ;
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.bumpAllowStartFgsState(
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
} else if (mService.mWakefulness
== PowerManagerInternal.WAKEFULNESS_AWAKE
&& (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
@@ -1901,6 +1908,7 @@
// Go at most to BOUND_TOP, unless requested to elevate
// to client's state.
clientProcState = PROCESS_STATE_BOUND_TOP;
+ app.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
boolean enabled = false;
try {
enabled = mPlatformCompatCache.isChangeEnabled(
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 5dbaaaf..85c5bdc 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -353,6 +353,10 @@
long mKillTime; // The timestamp in uptime when this process was killed.
+ // If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS.
+ // It must obtain the proc state from a persistent/top process or FGS, not transitive.
+ int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -466,6 +470,8 @@
pw.print(" setCapability=");
ActivityManager.printCapabilitiesFull(pw, setCapability);
pw.println();
+ pw.print(prefix); pw.print("allowStartFgsState=");
+ pw.println(mAllowStartFgsState);
if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
@@ -1942,6 +1948,12 @@
return mDialogController;
}
+ void bumpAllowStartFgsState(int newProcState) {
+ if (newProcState < mAllowStartFgsState) {
+ mAllowStartFgsState = newProcState;
+ }
+ }
+
/** A controller to generate error dialogs in {@link ProcessRecord} */
class ErrorDialogController {
/** dialogs being displayed due to crash */