BG-FGS-launch restriction exemptions.
1. Add a new permission START_FOREGROUND_SERVICES_FROM_BACKGROUND.
2. Add a new bind flag BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
3. BroadcastOptions.setTemporaryAppWhitelistDuration() is currently
protected with CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission, also open
it for START_ACTIVITIES_FROM_BACKGROUND and
START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
4. Exempt SYSTEM_ALERT_WINDOW permission.
5. if Context.startForegroundService() or Service.startForeground() is
restricted by BG-FGS-launch restriction, and app's targetSdkVersion is S
and above, throw a IllegalStateException.
Bug: 171305836
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsBindingFlagFGS
atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsBindingFlagActivity
atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsStartSystemAlertWindow
atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testFgsStartFromBGException
Change-Id: Iff3ed65e174a8406d4d6045cda42bdde6cecf30d
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 505d246..7d82f43 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -228,6 +228,7 @@
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
+ field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
@@ -603,7 +604,7 @@
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
method public void setDontSendToRestrictedApps(boolean);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void setTemporaryAppWhitelistDuration(long);
+ method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
method public android.os.Bundle toBundle();
}
@@ -1764,6 +1765,7 @@
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+ field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 03dca30..298c455 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -90,7 +90,9 @@
* power allowlist when this broadcast is being delivered to it.
* @param duration The duration in milliseconds; 0 means to not place on allowlist.
*/
- @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+ android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
public void setTemporaryAppWhitelistDuration(long duration) {
mTemporaryAppWhitelistDuration = duration;
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index b96b54a..3798de9 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -697,6 +697,10 @@
* service element of manifest file. The value of attribute
* {@link android.R.attr#foregroundServiceType} can be multiple flags ORed together.</p>
*
+ * @throws IllegalStateException If the app targeting API is
+ * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
+ * becoming foreground service due to background restriction.
+ *
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6a3f6b4..8f92bf1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -367,6 +367,16 @@
/*********** Hidden flags below this line ***********/
/**
+ * Flag for {@link #bindService}: allow background foreground service starts from the bound
+ * service's process.
+ * This flag is only respected if the caller is holding
+ * {@link android.Manifest.permission#START_FOREGROUND_SERVICES_FROM_BACKGROUND}.
+ * @hide
+ */
+ @SystemApi
+ public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 0x00040000;
+
+ /**
* Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
* the scheduling policy for IMEs (and any other out-of-process user-visible components that
* work closely with the top app) so that UI hosted in such services can have the same
@@ -3107,6 +3117,10 @@
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
*
+ * @throws IllegalStateException If the caller app's targeting API is
+ * {@link android.os.Build.VERSION_CODES#S} or later, and the foreground service is restricted
+ * from start due to background restriction.
+ *
* @see #stopService
* @see android.app.Service#startForeground(int, android.app.Notification)
*/
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ea667277..c9e8f71 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2557,6 +2557,10 @@
<permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+ <!-- @SystemApi @hide Allows an application to start foreground services from background -->
+ <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
+
<!-- @SystemApi Must be required by activities that handle the intent action
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a97af4b..2a699ea 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -146,6 +146,7 @@
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+ <uses-permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
<uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 43474d5..61ccf11 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -52,6 +52,9 @@
// Whether the caller holds START_ACTIVITIES_FROM_BACKGROUND permission
boolean mHasBackgroundActivityStartsPermission;
+ // Whether the caller holds START_FOREGROUND_SERVICES_FROM_BACKGROUND permission
+ boolean mHasBackgroundForegroundServiceStartsPermission;
+
// As given to us
Bundle mArguments;
@@ -128,6 +131,8 @@
}
pw.print("mHasBackgroundActivityStartsPermission=");
pw.println(mHasBackgroundActivityStartsPermission);
+ pw.print("mHasBackgroundForegroundServiceStartsPermission=");
+ pw.println(mHasBackgroundForegroundServiceStartsPermission);
pw.print(prefix); pw.print("mArguments=");
pw.println(mArguments);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d6f7299..8729026 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,8 @@
package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
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;
@@ -56,9 +58,11 @@
import android.app.Service;
import android.app.ServiceStartArgs;
import android.app.admin.DevicePolicyEventLogger;
+import android.app.compat.CompatChanges;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
import android.content.Context;
@@ -104,7 +108,6 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.ServiceState;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
@@ -147,30 +150,40 @@
public static final int FGS_FEATURE_DENIED = 0;
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;
- public static final int FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION = 5;
- public static final int FGS_FEATURE_ALLOWED_BY_TOKEN = 6;
- 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;
+ public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 2;
+ public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 3;
+ public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 4;
+ public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 5;
+ public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 6;
+ public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION = 7;
+ public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN = 8;
+ public static final int FGS_FEATURE_ALLOWED_BY_FGS_TOKEN = 9;
+ public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION = 10;
+ public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION = 12;
+ public static final int FGS_FEATURE_ALLOWED_BY_ALLOWLIST = 13;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 14;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
+ public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
+ public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
FGS_FEATURE_ALLOWED_BY_UID_STATE,
+ FGS_FEATURE_ALLOWED_BY_PROC_STATE,
FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
FGS_FEATURE_ALLOWED_BY_FLAG,
FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
- FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_TOKEN,
- FGS_FEATURE_ALLOWED_BY_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_WHITELIST,
+ FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN,
+ FGS_FEATURE_ALLOWED_BY_FGS_TOKEN,
+ FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_ALLOWLIST,
FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
- FGS_FEATURE_ALLOWED_BY_PROC_STATE,
- FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
+ FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
+ FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
+ FGS_FEATURE_ALLOWED_BY_FGS_BINDING
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -242,14 +255,12 @@
AppWidgetManagerInternal mAppWidgetManagerInternal;
// white listed packageName.
- ArraySet<String> mWhiteListAllowWhileInUsePermissionInFgs = new ArraySet<>();
+ ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
// TODO: remove this after feature development is done
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- private final IPlatformCompat mPlatformCompat;
-
/**
* The BG-launch FGS restriction feature is going to be allowed only for apps targetSdkVersion
* is higher than R.
@@ -258,6 +269,14 @@
@Disabled
static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
+ /**
+ * If a service can not become foreground service due to BG-FGS-launch restriction or other
+ * reasons, throws an IllegalStateException.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -456,26 +475,25 @@
? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
final IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
}
void systemServicesReady() {
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
ast.addServiceStateListener(new ForcedStandbyListener());
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
- setWhiteListAllowWhileInUsePermissionInFgs();
+ setAllowListWhileInUsePermissionInFgs();
}
- private void setWhiteListAllowWhileInUsePermissionInFgs() {
+ private void setAllowListWhileInUsePermissionInFgs() {
final String attentionServicePackageName =
mAm.mContext.getPackageManager().getAttentionServicePackageName();
if (!TextUtils.isEmpty(attentionServicePackageName)) {
- mWhiteListAllowWhileInUsePermissionInFgs.add(attentionServicePackageName);
+ mAllowListWhileInUsePermissionInFgs.add(attentionServicePackageName);
}
final String systemCaptionsServicePackageName =
mAm.mContext.getPackageManager().getSystemCaptionsServicePackageName();
if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
- mWhiteListAllowWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
+ mAllowListWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
}
}
@@ -583,13 +601,27 @@
Slog.wtf(TAG, "Background started FGS " + r.mInfoAllowStartForeground);
r.mLoggedInfoAllowStartForeground = true;
}
- if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
- || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- Slog.w(TAG, "startForegroundService() not allowed due to "
+ if (r.mAllowStartForeground == FGS_FEATURE_DENIED && isBgFgsRestrictionEnabled(r)) {
+ String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
- + r.shortInstanceName);
+ + r.shortInstanceName;
+ Slog.w(TAG, msg);
showFgsBgRestrictedNotificationLocked(r);
+ ApplicationInfo aInfo = null;
+ try {
+ aInfo = AppGlobals.getPackageManager().getApplicationInfo(
+ callingPackage, ActivityManagerService.STOCK_PM_FLAGS,
+ userId);
+ } catch (android.os.RemoteException e) {
+ // pm is in same process, this will never happen.
+ }
+ if (aInfo == null) {
+ throw new SecurityException("startServiceLocked failed, "
+ + "could not resolve client package " + callingPackage);
+ }
+ if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, aInfo.uid)) {
+ throw new IllegalStateException(msg);
+ }
return null;
}
}
@@ -1449,7 +1481,7 @@
}
try {
- boolean ignoreForeground = false;
+ String ignoreForeground = null;
final int mode = mAm.getAppOpsManager().checkOpNoThrow(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
@@ -1459,9 +1491,9 @@
break;
case AppOpsManager.MODE_IGNORED:
// Whoops, silently ignore this.
- Slog.w(TAG, "Service.startForeground() not allowed due to app op: service "
- + r.shortInstanceName);
- ignoreForeground = true;
+ ignoreForeground = "Service.startForeground() not allowed due to app op: "
+ + "service " + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
break;
default:
throw new SecurityException("Foreground not allowed as per app op");
@@ -1469,19 +1501,18 @@
// Apps that are TOP or effectively similar may call startForeground() on
// their services even if they are restricted from doing that while in bg.
- if (!ignoreForeground
+ if (ignoreForeground == null
&& !appIsTopLocked(r.appInfo.uid)
&& appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
- Slog.w(TAG,
- "Service.startForeground() not allowed due to bg restriction: service "
- + r.shortInstanceName);
+ ignoreForeground = "Service.startForeground() not allowed due to bg restriction"
+ + ":service " + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
// Back off of any foreground expectations around this service, since we've
// just turned down its fg request.
updateServiceForegroundLocked(r.app, false);
- ignoreForeground = true;
}
- if (!ignoreForeground) {
+ if (ignoreForeground == null) {
if (isFgsBgStart(r.mAllowStartForeground)) {
if (!r.mLoggedInfoAllowStartForeground) {
Slog.wtf(TAG, "Background started FGS "
@@ -1489,14 +1520,13 @@
r.mLoggedInfoAllowStartForeground = true;
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
- && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
- || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- Slog.w(TAG, "Service.startForeground() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
+ && isBgFgsRestrictionEnabled(r)) {
+ ignoreForeground = "Service.startForeground() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName;
+ Slog.w(TAG, ignoreForeground);
showFgsBgRestrictedNotificationLocked(r);
updateServiceForegroundLocked(r.app, true);
- ignoreForeground = true;
}
}
}
@@ -1505,7 +1535,7 @@
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
// is not restricted.
- if (!ignoreForeground) {
+ if (ignoreForeground == null) {
if (r.foregroundId != id) {
cancelForegroundNotificationLocked(r);
r.foregroundId = id;
@@ -1567,6 +1597,10 @@
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
}
+ if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, r.appInfo.uid)
+ && isBgFgsRestrictionEnabled(r)) {
+ throw new IllegalStateException(ignoreForeground);
+ }
}
} finally {
if (stopProcStatsOp) {
@@ -2094,6 +2128,12 @@
"BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS");
}
+ if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ mAm.enforceCallingPermission(
+ android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND,
+ "BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND");
+ }
+
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
@@ -2239,6 +2279,11 @@
if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.setAllowedBgActivityStartsByBinding(true);
}
+
+ if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ s.setAllowedBgFgsStartsByBinding(true);
+ }
+
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -2256,7 +2301,6 @@
return 0;
}
}
-
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false);
if (s.app != null) {
@@ -3647,6 +3691,9 @@
if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.updateIsAllowedBgActivityStartsByBinding();
}
+ if ((c.flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ s.updateIsAllowedBgFgsStartsByBinding();
+ }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
@@ -5113,13 +5160,22 @@
}
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) {
+ if (pr.areBackgroundActivityStartsAllowedByToken()) {
+ ret = FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN;
+ break;
+ }
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
if (r.app != null) {
ActiveInstrumentation instr = r.app.getActiveInstrumentation();
if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
- ret = FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION;
- }
- if (r.app.areBackgroundActivityStartsAllowedByToken()) {
- ret = FGS_FEATURE_ALLOWED_BY_TOKEN;
+ ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
}
}
}
@@ -5127,15 +5183,15 @@
if (ret == FGS_FEATURE_DENIED) {
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PERMISSION_GRANTED) {
- ret = FGS_FEATURE_ALLOWED_BY_PERMISSION;
+ ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
}
}
if (ret == FGS_FEATURE_DENIED) {
- final boolean isWhiteListedPackage =
- mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
- if (isWhiteListedPackage) {
- ret = FGS_FEATURE_ALLOWED_BY_WHITELIST;
+ final boolean isAllowedPackage =
+ mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isAllowedPackage) {
+ ret = FGS_FEATURE_ALLOWED_BY_ALLOWLIST;
}
}
@@ -5187,6 +5243,39 @@
}
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) {
+ if (pr.areBackgroundFgsStartsAllowedByToken()) {
+ ret = FGS_FEATURE_ALLOWED_BY_FGS_BINDING;
+ break;
+ } else {
+ final ActiveInstrumentation instr = pr.getActiveInstrumentation();
+ if (instr != null
+ && instr.mHasBackgroundForegroundServiceStartsPermission) {
+ ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,
+ callingUid) == PERMISSION_GRANTED) {
+ ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.checkPermission(SYSTEM_ALERT_WINDOW, callingPid,
+ callingUid) == PERMISSION_GRANTED) {
+ ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
&& mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
// uid is on DeviceIdleController's allowlist.
@@ -5217,26 +5306,36 @@
return "DENIED";
case FGS_FEATURE_ALLOWED_BY_UID_STATE:
return "ALLOWED_BY_UID_STATE";
+ case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+ return "ALLOWED_BY_PROC_STATE";
case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
return "ALLOWED_BY_UID_VISIBLE";
case FGS_FEATURE_ALLOWED_BY_FLAG:
return "ALLOWED_BY_FLAG";
case FGS_FEATURE_ALLOWED_BY_SYSTEM_UID:
return "ALLOWED_BY_SYSTEM_UID";
- case FGS_FEATURE_ALLOWED_BY_INSTR_PERMISSION:
- return "ALLOWED_BY_INSTR_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_TOKEN:
- return "ALLOWED_BY_TOKEN";
- case FGS_FEATURE_ALLOWED_BY_PERMISSION:
- return "ALLOWED_BY_PERMISSION";
- case FGS_FEATURE_ALLOWED_BY_WHITELIST:
+ case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
+ return "ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION:
+ return "ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN:
+ return "ALLOWED_BY_ACTIVITY_TOKEN";
+ case FGS_FEATURE_ALLOWED_BY_FGS_TOKEN:
+ return "ALLOWED_BY_FGS_TOKEN";
+ case FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION:
+ return "ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
+ return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
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";
+ case FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION:
+ return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
+ case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
+ return "ALLOWED_BY_FGS_BINDING";
default:
return "";
}
@@ -5271,11 +5370,10 @@
NOTE_FOREGROUND_SERVICE_BG_LAUNCH, n.build(), UserHandle.ALL);
}
- private boolean isChangeEnabled(long changeId, ServiceRecord r) {
- boolean enabled = false;
- try {
- enabled = mPlatformCompat.isChangeEnabled(changeId, r.appInfo);
- } catch (RemoteException e) { }
- return enabled;
+ private boolean isBgFgsRestrictionEnabled(ServiceRecord r) {
+ if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
+ return true;
+ }
+ return CompatChanges.isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r.appInfo.uid);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9eca15b..75e8b13 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
@@ -13321,15 +13322,22 @@
// See if the caller is allowed to do this. Note we are checking against
// the actual real caller (not whoever provided the operation as say a
// PendingIntent), because that who is actually supplied the arguments.
- if (checkComponentPermission(
- android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ realCallingPid, realCallingUid, -1, true)
+ != PackageManager.PERMISSION_GRANTED
+ && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
+ realCallingPid, realCallingUid, -1, true)
+ != PackageManager.PERMISSION_GRANTED
+ && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,
realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
- + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+ + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "
+ + START_ACTIVITIES_FROM_BACKGROUND + " or "
+ + START_FOREGROUND_SERVICES_FROM_BACKGROUND;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
@@ -14289,8 +14297,10 @@
activeInstr.mHasBackgroundActivityStartsPermission = checkPermission(
START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
+ activeInstr.mHasBackgroundForegroundServiceStartsPermission = checkPermission(
+ START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED;
activeInstr.mNoRestart = noRestart;
-
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
boolean disableTestApiChecks = disableHiddenApiChecks
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1b06dd9..cf4adc6 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -359,6 +359,8 @@
// It must obtain the proc state from a persistent/top process or FGS, not transitive.
int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+ private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -1965,6 +1967,18 @@
}
}
+ public void addAllowBackgroundFgsStartsToken(Binder entity) {
+ mBackgroundFgsStartTokens.add(entity);
+ }
+
+ public void removeAllowBackgroundFgsStartsToken(Binder entity) {
+ mBackgroundFgsStartTokens.remove(entity);
+ }
+
+ public boolean areBackgroundFgsStartsAllowedByToken() {
+ return !mBackgroundFgsStartTokens.isEmpty();
+ }
+
ErrorDialogController getDialogController() {
return mDialogController;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 364ad21..e129561 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -147,6 +147,10 @@
@GuardedBy("ams")
private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
+ // any current binding to this service has BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
+ // flag? if true, the process can start FGS from background.
+ boolean mIsAllowedBgFgsStartsByBinding;
+
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@@ -418,6 +422,10 @@
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
pw.println(mIsAllowedBgActivityStartsByStart);
}
+ if (mIsAllowedBgFgsStartsByBinding) {
+ pw.print(prefix); pw.print("mIsAllowedBgFgsStartsByBinding=");
+ pw.println(mIsAllowedBgFgsStartsByBinding);
+ }
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
@@ -600,6 +608,11 @@
} else {
_proc.removeAllowBackgroundActivityStartsToken(this);
}
+ if (mIsAllowedBgFgsStartsByBinding) {
+ _proc.addAllowBackgroundFgsStartsToken(this);
+ } else {
+ _proc.removeAllowBackgroundFgsStartsToken(this);
+ }
}
if (app != null && app != _proc) {
// If the old app is allowed to start bg activities because of a service start, leave it
@@ -686,11 +699,34 @@
setAllowedBgActivityStartsByBinding(isAllowedByBinding);
}
+ void updateIsAllowedBgFgsStartsByBinding() {
+ boolean isAllowedByBinding = false;
+ for (int conni = connections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+ for (int i = 0; i < cr.size(); i++) {
+ if ((cr.get(i).flags
+ & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
+ isAllowedByBinding = true;
+ break;
+ }
+ }
+ if (isAllowedByBinding) {
+ break;
+ }
+ }
+ setAllowedBgFgsStartsByBinding(isAllowedByBinding);
+ }
+
void setAllowedBgActivityStartsByBinding(boolean newValue) {
mIsAllowedBgActivityStartsByBinding = newValue;
updateParentProcessBgActivityStartsToken();
}
+ void setAllowedBgFgsStartsByBinding(boolean newValue) {
+ mIsAllowedBgFgsStartsByBinding = newValue;
+ updateParentProcessBgFgsStartsToken();
+ }
+
/**
* Called when the service is started with allowBackgroundActivityStarts set. We allow
* it for background activity starts, setting up a callback to remove this ability after a
@@ -777,6 +813,17 @@
}
}
+ private void updateParentProcessBgFgsStartsToken() {
+ if (app == null) {
+ return;
+ }
+ if (mIsAllowedBgFgsStartsByBinding) {
+ app.addAllowBackgroundFgsStartsToken(this);
+ } else {
+ app.removeAllowBackgroundFgsStartsToken(this);
+ }
+ }
+
/**
* Returns the originating token if that's the only reason background activity starts are
* allowed. In order for that to happen the service has to be allowed only due to starts, since