Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +27 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; Loading Loading @@ -307,6 +308,7 @@ public class AlarmManagerService extends SystemService { BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic(); ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic(); // TODO(b/172085676): Move inside alarm store. private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = Loading Loading @@ -1610,6 +1612,10 @@ public class AlarmManagerService extends SystemService { @Override public void onStart() { mInjector.init(); mOptsWithFgs.setPendingIntentBackgroundActivityLaunchAllowed(false); mOptsWithoutFgs.setPendingIntentBackgroundActivityLaunchAllowed(false); mOptsTimeBroadcast.setPendingIntentBackgroundActivityLaunchAllowed(false); mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false); mMetricsHelper = new MetricsHelper(getContext(), mLock); mListenerDeathRecipient = new IBinder.DeathRecipient() { Loading Loading @@ -4339,7 +4345,16 @@ public class AlarmManagerService extends SystemService { for (int i = 0; i < triggerList.size(); i++) { Alarm alarm = triggerList.get(i); try { alarm.operation.send(); // Disallow AlarmManager to start random background activity. final Bundle bundle; if (alarm.operation.isActivity()) { bundle = mActivityOptsRestrictBal.toBundle(); } else { bundle = null; } alarm.operation.send(/* context */ null, /* code */0, /* intent */ null, /* onFinished */null, /* handler */ null, /* requiredPermission */ null, bundle); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this Loading Loading @@ -4901,9 +4916,19 @@ public class AlarmManagerService extends SystemService { mSendCount++; try { final Bundle bundle; if (alarm.mIdleOptions != null) { bundle = alarm.mIdleOptions; } else { if (alarm.operation.isActivity()) { bundle = mActivityOptsRestrictBal.toBundle(); } else { bundle = null; } } alarm.operation.send(getContext(), 0, mBackgroundIntent.putExtra(Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null, alarm.mIdleOptions); mDeliveryTracker, mHandler, null, bundle); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this Loading core/java/android/app/ActivityOptions.java +36 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,14 @@ public class ActivityOptions { */ public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme"; /** * PendingIntent caller allows activity start even if PendingIntent creator is in background. * This only works if the PendingIntent caller is allowed to start background activities, * for example if it's in the foreground, or has BAL permission. * @hide */ public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED = "android.pendingIntent.backgroundActivityAllowed"; /** * Callback for when the last frame of the animation is played. * @hide Loading Loading @@ -380,6 +388,12 @@ public class ActivityOptions { /** @hide */ public static final int ANIM_REMOTE_ANIMATION = 13; /** * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED. * @hide **/ public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true; private String mPackageName; private Rect mLaunchBounds; private int mAnimationType = ANIM_UNDEFINED; Loading Loading @@ -431,6 +445,7 @@ public class ActivityOptions { private String mSplashScreenThemeResName; @SplashScreen.SplashScreenStyle private int mSplashScreenStyle; private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT; private boolean mRemoveWithTaskOrganizer; private boolean mLaunchedFromBubble; private boolean mTransientLaunch; Loading Loading @@ -1184,6 +1199,8 @@ public class ActivityOptions { mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION); mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION); mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME); mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, PENDING_INTENT_BAL_ALLOWED_DEFAULT); mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER); mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE); mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH); Loading Loading @@ -1399,6 +1416,24 @@ public class ActivityOptions { return mSplashScreenStyle; } /** * Set PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * @hide */ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { mPendingIntentBalAllowed = allowed; } /** * Get PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * @hide */ public boolean isPendingIntentBackgroundActivityLaunchAllowed() { return mPendingIntentBalAllowed; } /** * Sets whether the activity is to be launched into LockTask mode. * Loading Loading @@ -1972,6 +2007,7 @@ public class ActivityOptions { if (mSplashScreenThemeResName != null && !mSplashScreenThemeResName.isEmpty()) { b.putString(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResName); } b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed); if (mRemoveWithTaskOrganizer) { b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer); } Loading core/java/android/app/BroadcastOptions.java +35 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ public class BroadcastOptions { private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; private boolean mDontSendToRestrictedApps = false; private boolean mAllowBackgroundActivityStarts; private boolean mPendingIntentBalAllowed = ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; /** * How long to temporarily put an app on the power allowlist when executing this broadcast Loading Loading @@ -78,6 +79,16 @@ public class BroadcastOptions { private static final String KEY_DONT_SEND_TO_RESTRICTED_APPS = "android:broadcast.dontSendToRestrictedApps"; /** * PendingIntent caller allows activity start even if PendingIntent creator is in background. * This only works if the PendingIntent caller is allowed to start background activities, * for example if it's in the foreground, or has BAL permission. * TODO: Merge it with ActivityOptions. * @hide */ public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED = "android.pendingIntent.backgroundActivityAllowed"; /** * Corresponds to {@link #setBackgroundActivityStartsAllowed}. */ Loading Loading @@ -130,6 +141,8 @@ public class BroadcastOptions { mDontSendToRestrictedApps = opts.getBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, false); mAllowBackgroundActivityStarts = opts.getBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, false); mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT); } /** Loading Loading @@ -300,6 +313,26 @@ public class BroadcastOptions { return mAllowBackgroundActivityStarts; } /** * Set PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * TODO: Merge it with ActivityOptions. * @hide */ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { mPendingIntentBalAllowed = allowed; } /** * Get PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * TODO: Merge it with ActivityOptions. * @hide */ public boolean isPendingIntentBackgroundActivityLaunchAllowed() { return mPendingIntentBalAllowed; } /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) Loading Loading @@ -328,6 +361,8 @@ public class BroadcastOptions { if (mAllowBackgroundActivityStarts) { b.putBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, true); } // TODO: Add API for BroadcastOptions and have a shared base class with ActivityOptions. b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed); return b.isEmpty() ? null : b; } } services/core/java/com/android/server/wm/ActivityStarter.java +54 −8 Original line number Diff line number Diff line Loading @@ -88,6 +88,9 @@ import android.app.IApplicationThread; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.app.WaitResult; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; Loading @@ -101,6 +104,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Process; Loading Loading @@ -146,6 +150,13 @@ class ActivityStarter { private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; private static final int INVALID_LAUNCH_MODE = -1; /** * Feature flag to protect PendingIntent being abused to start background activity. */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) static final long ENABLE_PENDING_INTENT_BAL_OPTION = 192341120L; private final ActivityTaskManagerService mService; private final RootWindowContainer mRootWindowContainer; private final ActivityTaskSupervisor mSupervisor; Loading Loading @@ -987,6 +998,10 @@ class ActivityStarter { abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid, callingPackage); // Merge the two options bundles, while realCallerOptions takes precedence. ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; boolean restrictedBgActivity = false; if (!abort) { try { Loading @@ -995,15 +1010,12 @@ class ActivityStarter { restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, request.originatingPendingIntent, request.allowBackgroundActivityStart, intent); intent, checkedOptions); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } // Merge the two options bundles, while realCallerOptions takes precedence. ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; if (request.allowPendingRemoteAnimationRegistryLookup) { checkedOptions = mService.getActivityStartController() .getPendingRemoteAnimationRegistry() Loading Loading @@ -1242,10 +1254,22 @@ class ActivityStarter { return activity != null && packageName.equals(activity.getPackageName()); } private static boolean isPendingIntentBalAllowedByCaller(ActivityOptions activityOptions) { if (activityOptions == null) { return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; } final Bundle options = activityOptions.toBundle(); if (options == null) { return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; } return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT); } boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid, final String callingPackage, int realCallingUid, int realCallingPid, WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart, Intent intent) { boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) { // don't abort for the most important UIDs final int callingAppId = UserHandle.getAppId(callingUid); if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID Loading Loading @@ -1314,7 +1338,29 @@ class ActivityStarter { ? isCallingUidPersistentSystemProcess : (realCallingAppId == Process.SYSTEM_UID) || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { // If caller a legacy app, we won't check if caller has BAL permission. final boolean isPiBalOptionEnabled = CompatChanges.isChangeEnabled( ENABLE_PENDING_INTENT_BAL_OPTION, callingUid); // Legacy behavior allows to use caller foreground state to bypass BAL restriction. final boolean balAllowedByPiSender = isPendingIntentBalAllowedByCaller(checkedOptions); if (balAllowedByPiSender && realCallingUid != callingUid) { if (isPiBalOptionEnabled) { if (ActivityManager.checkComponentPermission( android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, realCallingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid + ") has BAL permission."); } return false; } } // don't abort if the realCallingUid has a visible window // TODO(b/171459802): We should check appSwitchAllowed also if (realCallingUidHasAnyVisibleWindow) { Loading Loading @@ -1389,9 +1435,9 @@ class ActivityStarter { // If we don't have callerApp at this point, no caller was provided to startActivity(). // That's the case for PendingIntent-based starts, since the creator's process might not be // up and alive. If that's the case, we retrieve the WindowProcessController for the send() // caller, so that we can make the decision based on its state. // caller if caller allows, so that we can make the decision based on its state. int callerAppUid = callingUid; if (callerApp == null) { if (callerApp == null && balAllowedByPiSender) { callerApp = mService.getProcessController(realCallingPid, realCallingUid); callerAppUid = realCallingUid; } Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -2077,7 +2077,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final ActivityStarter starter = getActivityStartController().obtainStarter( null /* intent */, "moveTaskToFront"); if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1, -1, callerApp, null, false, null)) { -1, callerApp, null, false, null, null)) { if (!isBackgroundActivityStartsEnabled()) { return; } Loading Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +27 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AlarmManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; Loading Loading @@ -307,6 +308,7 @@ public class AlarmManagerService extends SystemService { BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic(); BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic(); ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic(); // TODO(b/172085676): Move inside alarm store. private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = Loading Loading @@ -1610,6 +1612,10 @@ public class AlarmManagerService extends SystemService { @Override public void onStart() { mInjector.init(); mOptsWithFgs.setPendingIntentBackgroundActivityLaunchAllowed(false); mOptsWithoutFgs.setPendingIntentBackgroundActivityLaunchAllowed(false); mOptsTimeBroadcast.setPendingIntentBackgroundActivityLaunchAllowed(false); mActivityOptsRestrictBal.setPendingIntentBackgroundActivityLaunchAllowed(false); mMetricsHelper = new MetricsHelper(getContext(), mLock); mListenerDeathRecipient = new IBinder.DeathRecipient() { Loading Loading @@ -4339,7 +4345,16 @@ public class AlarmManagerService extends SystemService { for (int i = 0; i < triggerList.size(); i++) { Alarm alarm = triggerList.get(i); try { alarm.operation.send(); // Disallow AlarmManager to start random background activity. final Bundle bundle; if (alarm.operation.isActivity()) { bundle = mActivityOptsRestrictBal.toBundle(); } else { bundle = null; } alarm.operation.send(/* context */ null, /* code */0, /* intent */ null, /* onFinished */null, /* handler */ null, /* requiredPermission */ null, bundle); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this Loading Loading @@ -4901,9 +4916,19 @@ public class AlarmManagerService extends SystemService { mSendCount++; try { final Bundle bundle; if (alarm.mIdleOptions != null) { bundle = alarm.mIdleOptions; } else { if (alarm.operation.isActivity()) { bundle = mActivityOptsRestrictBal.toBundle(); } else { bundle = null; } } alarm.operation.send(getContext(), 0, mBackgroundIntent.putExtra(Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null, alarm.mIdleOptions); mDeliveryTracker, mHandler, null, bundle); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this Loading
core/java/android/app/ActivityOptions.java +36 −0 Original line number Diff line number Diff line Loading @@ -166,6 +166,14 @@ public class ActivityOptions { */ public static final String KEY_SPLASH_SCREEN_THEME = "android.activity.splashScreenTheme"; /** * PendingIntent caller allows activity start even if PendingIntent creator is in background. * This only works if the PendingIntent caller is allowed to start background activities, * for example if it's in the foreground, or has BAL permission. * @hide */ public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED = "android.pendingIntent.backgroundActivityAllowed"; /** * Callback for when the last frame of the animation is played. * @hide Loading Loading @@ -380,6 +388,12 @@ public class ActivityOptions { /** @hide */ public static final int ANIM_REMOTE_ANIMATION = 13; /** * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED. * @hide **/ public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true; private String mPackageName; private Rect mLaunchBounds; private int mAnimationType = ANIM_UNDEFINED; Loading Loading @@ -431,6 +445,7 @@ public class ActivityOptions { private String mSplashScreenThemeResName; @SplashScreen.SplashScreenStyle private int mSplashScreenStyle; private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT; private boolean mRemoveWithTaskOrganizer; private boolean mLaunchedFromBubble; private boolean mTransientLaunch; Loading Loading @@ -1184,6 +1199,8 @@ public class ActivityOptions { mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION); mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION); mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME); mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, PENDING_INTENT_BAL_ALLOWED_DEFAULT); mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER); mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE); mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH); Loading Loading @@ -1399,6 +1416,24 @@ public class ActivityOptions { return mSplashScreenStyle; } /** * Set PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * @hide */ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { mPendingIntentBalAllowed = allowed; } /** * Get PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * @hide */ public boolean isPendingIntentBackgroundActivityLaunchAllowed() { return mPendingIntentBalAllowed; } /** * Sets whether the activity is to be launched into LockTask mode. * Loading Loading @@ -1972,6 +2007,7 @@ public class ActivityOptions { if (mSplashScreenThemeResName != null && !mSplashScreenThemeResName.isEmpty()) { b.putString(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResName); } b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed); if (mRemoveWithTaskOrganizer) { b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer); } Loading
core/java/android/app/BroadcastOptions.java +35 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ public class BroadcastOptions { private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; private boolean mDontSendToRestrictedApps = false; private boolean mAllowBackgroundActivityStarts; private boolean mPendingIntentBalAllowed = ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; /** * How long to temporarily put an app on the power allowlist when executing this broadcast Loading Loading @@ -78,6 +79,16 @@ public class BroadcastOptions { private static final String KEY_DONT_SEND_TO_RESTRICTED_APPS = "android:broadcast.dontSendToRestrictedApps"; /** * PendingIntent caller allows activity start even if PendingIntent creator is in background. * This only works if the PendingIntent caller is allowed to start background activities, * for example if it's in the foreground, or has BAL permission. * TODO: Merge it with ActivityOptions. * @hide */ public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED = "android.pendingIntent.backgroundActivityAllowed"; /** * Corresponds to {@link #setBackgroundActivityStartsAllowed}. */ Loading Loading @@ -130,6 +141,8 @@ public class BroadcastOptions { mDontSendToRestrictedApps = opts.getBoolean(KEY_DONT_SEND_TO_RESTRICTED_APPS, false); mAllowBackgroundActivityStarts = opts.getBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, false); mPendingIntentBalAllowed = opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT); } /** Loading Loading @@ -300,6 +313,26 @@ public class BroadcastOptions { return mAllowBackgroundActivityStarts; } /** * Set PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * TODO: Merge it with ActivityOptions. * @hide */ public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { mPendingIntentBalAllowed = allowed; } /** * Get PendingIntent activity is allowed to be started in the background if the caller * can start background activities. * TODO: Merge it with ActivityOptions. * @hide */ public boolean isPendingIntentBackgroundActivityLaunchAllowed() { return mPendingIntentBalAllowed; } /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) Loading Loading @@ -328,6 +361,8 @@ public class BroadcastOptions { if (mAllowBackgroundActivityStarts) { b.putBoolean(KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS, true); } // TODO: Add API for BroadcastOptions and have a shared base class with ActivityOptions. b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed); return b.isEmpty() ? null : b; } }
services/core/java/com/android/server/wm/ActivityStarter.java +54 −8 Original line number Diff line number Diff line Loading @@ -88,6 +88,9 @@ import android.app.IApplicationThread; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.app.WaitResult; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; Loading @@ -101,6 +104,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Process; Loading Loading @@ -146,6 +150,13 @@ class ActivityStarter { private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; private static final int INVALID_LAUNCH_MODE = -1; /** * Feature flag to protect PendingIntent being abused to start background activity. */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) static final long ENABLE_PENDING_INTENT_BAL_OPTION = 192341120L; private final ActivityTaskManagerService mService; private final RootWindowContainer mRootWindowContainer; private final ActivityTaskSupervisor mSupervisor; Loading Loading @@ -987,6 +998,10 @@ class ActivityStarter { abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid, callingPackage); // Merge the two options bundles, while realCallerOptions takes precedence. ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; boolean restrictedBgActivity = false; if (!abort) { try { Loading @@ -995,15 +1010,12 @@ class ActivityStarter { restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, request.originatingPendingIntent, request.allowBackgroundActivityStart, intent); intent, checkedOptions); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } // Merge the two options bundles, while realCallerOptions takes precedence. ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; if (request.allowPendingRemoteAnimationRegistryLookup) { checkedOptions = mService.getActivityStartController() .getPendingRemoteAnimationRegistry() Loading Loading @@ -1242,10 +1254,22 @@ class ActivityStarter { return activity != null && packageName.equals(activity.getPackageName()); } private static boolean isPendingIntentBalAllowedByCaller(ActivityOptions activityOptions) { if (activityOptions == null) { return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; } final Bundle options = activityOptions.toBundle(); if (options == null) { return ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT; } return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, ActivityOptions.PENDING_INTENT_BAL_ALLOWED_DEFAULT); } boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid, final String callingPackage, int realCallingUid, int realCallingPid, WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart, Intent intent) { boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) { // don't abort for the most important UIDs final int callingAppId = UserHandle.getAppId(callingUid); if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID Loading Loading @@ -1314,7 +1338,29 @@ class ActivityStarter { ? isCallingUidPersistentSystemProcess : (realCallingAppId == Process.SYSTEM_UID) || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { // If caller a legacy app, we won't check if caller has BAL permission. final boolean isPiBalOptionEnabled = CompatChanges.isChangeEnabled( ENABLE_PENDING_INTENT_BAL_OPTION, callingUid); // Legacy behavior allows to use caller foreground state to bypass BAL restriction. final boolean balAllowedByPiSender = isPendingIntentBalAllowedByCaller(checkedOptions); if (balAllowedByPiSender && realCallingUid != callingUid) { if (isPiBalOptionEnabled) { if (ActivityManager.checkComponentPermission( android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, realCallingUid, -1, true) == PackageManager.PERMISSION_GRANTED) { if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid + ") has BAL permission."); } return false; } } // don't abort if the realCallingUid has a visible window // TODO(b/171459802): We should check appSwitchAllowed also if (realCallingUidHasAnyVisibleWindow) { Loading Loading @@ -1389,9 +1435,9 @@ class ActivityStarter { // If we don't have callerApp at this point, no caller was provided to startActivity(). // That's the case for PendingIntent-based starts, since the creator's process might not be // up and alive. If that's the case, we retrieve the WindowProcessController for the send() // caller, so that we can make the decision based on its state. // caller if caller allows, so that we can make the decision based on its state. int callerAppUid = callingUid; if (callerApp == null) { if (callerApp == null && balAllowedByPiSender) { callerApp = mService.getProcessController(realCallingPid, realCallingUid); callerAppUid = realCallingUid; } Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -2077,7 +2077,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final ActivityStarter starter = getActivityStartController().obtainStarter( null /* intent */, "moveTaskToFront"); if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1, -1, callerApp, null, false, null)) { -1, callerApp, null, false, null, null)) { if (!isBackgroundActivityStartsEnabled()) { return; } Loading