diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 4663662c5585f..39106f61d5155 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -98,6 +98,8 @@ public class ActivityStartController { /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */ private boolean mInExecution = false; + private final BackgroundActivityStartController mBalController; + /** * TODO(b/64750076): Capture information necessary for dump and * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object @@ -120,6 +122,7 @@ public class ActivityStartController { mFactory.setController(this); mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock, service.mH); + mBalController = new BackgroundActivityStartController(mService, mSupervisor); } /** @@ -670,4 +673,8 @@ public class ActivityStartController { pw.println("(nothing)"); } } + + BackgroundActivityStartController getBackgroundActivityLaunchController() { + return mBalController; + } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index aad89b441732f..d1a5ead78af26 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.app.Activity.RESULT_CANCELED; import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_CANCELED; @@ -52,7 +51,6 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.content.pm.ActivityInfo.launchModeToString; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.INVALID_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_NONE; @@ -63,7 +61,6 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.RESUMED; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; @@ -74,11 +71,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; -import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; -import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT; +import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT; @@ -99,7 +96,6 @@ import android.app.WaitResult; import android.app.WindowConfiguration; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; -import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; @@ -115,15 +111,12 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.os.Process; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.service.voice.IVoiceInteractionSession; import android.text.TextUtils; -import android.util.ArraySet; -import android.util.DebugUtils; import android.util.Pools.SynchronizedPool; import android.util.Slog; import android.window.RemoteTransition; @@ -139,6 +132,7 @@ import com.android.server.power.ShutdownCheckPoints; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; +import com.android.server.wm.BackgroundActivityStartController.BalCode; import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.wm.TaskFragment.EmbeddingCheckResult; @@ -180,9 +174,10 @@ class ActivityStarter { private int mCallingUid; private ActivityOptions mOptions; - // If it is true, background activity can only be started in an existing task that contains + // If it is BAL_BLOCK, background activity can only be started in an existing task that contains // an activity with same uid, or if activity starts are enabled in developer options. - private boolean mRestrictedBgActivity; + @BalCode + private int mBalCode; private int mLaunchMode; private boolean mLaunchTaskBehind; @@ -264,8 +259,6 @@ class ActivityStarter { /** * Generates an {@link ActivityStarter} that is ready to handle a new start request. - * @param controller The {@link ActivityStartController} which the starter who will own - * this instance. * @return an {@link ActivityStarter} */ ActivityStarter obtain(); @@ -600,7 +593,7 @@ class ActivityStarter { mIntent = starter.mIntent; mCallingUid = starter.mCallingUid; mOptions = starter.mOptions; - mRestrictedBgActivity = starter.mRestrictedBgActivity; + mBalCode = starter.mBalCode; mLaunchTaskBehind = starter.mLaunchTaskBehind; mLaunchFlags = starter.mLaunchFlags; @@ -1031,15 +1024,25 @@ class ActivityStarter { ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; - boolean restrictedBgActivity = false; + @BalCode int balCode = BAL_ALLOW_DEFAULT; if (!abort) { try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "shouldAbortBackgroundActivityStart"); - restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid, - callingPid, callingPackage, realCallingUid, realCallingPid, callerApp, - request.originatingPendingIntent, request.allowBackgroundActivityStart, - intent, checkedOptions); + BackgroundActivityStartController balController = + mController.getBackgroundActivityLaunchController(); + balCode = + balController.checkBackgroundActivityStart( + callingUid, + callingPid, + callingPackage, + realCallingUid, + realCallingPid, + callerApp, + request.originatingPendingIntent, + request.allowBackgroundActivityStart, + intent, + checkedOptions); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @@ -1217,13 +1220,13 @@ class ActivityStarter { WindowProcessController homeProcess = mService.mHomeProcess; boolean isHomeProcess = homeProcess != null && aInfo.applicationInfo.uid == homeProcess.mUid; - if (!restrictedBgActivity && !isHomeProcess) { + if (balCode != BAL_BLOCK && !isHomeProcess) { mService.resumeAppSwitches(); } mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, - inTask, inTaskFragment, restrictedBgActivity, intentGrants); + inTask, inTaskFragment, balCode, intentGrants); if (request.outActivity != null) { request.outActivity[0] = mLastStartActivityRecord; @@ -1273,282 +1276,6 @@ class ActivityStarter { mController.onExecutionStarted(); } - private boolean isHomeApp(int uid, @Nullable String packageName) { - if (mService.mHomeProcess != null) { - // Fast check - return uid == mService.mHomeProcess.mUid; - } - if (packageName == null) { - return false; - } - ComponentName activity = - mService.getPackageManagerInternalLocked().getDefaultHomeActivity( - UserHandle.getUserId(uid)); - return activity != null && packageName.equals(activity.getPackageName()); - } - - boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid, - final String callingPackage, int realCallingUid, int realCallingPid, - WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent, - boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) { - // don't abort for the most important UIDs - final int callingAppId = UserHandle.getAppId(callingUid); - final boolean useCallingUidState = - originatingPendingIntent == null || checkedOptions == null - || !checkedOptions.getIgnorePendingIntentCreatorForegroundState(); - if (useCallingUidState) { - if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID - || callingAppId == Process.NFC_UID) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, - "Activity start allowed for important callingUid (" + callingUid + ")"); - } - return false; - } - - // Always allow home application to start activities. - if (isHomeApp(callingUid, callingPackage)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, - "Activity start allowed for home app callingUid (" + callingUid + ")"); - } - return false; - } - - // IME should always be allowed to start activity, like IME settings. - final WindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow(); - if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")"); - } - return false; - } - } - - // This is used to block background activity launch even if the app is still - // visible to user after user clicking home button. - final int appSwitchState = mService.getBalAppSwitchesState(); - - // don't abort if the callingUid has a visible window or is a persistent system process - final int callingUidProcState = mService.mActiveUids.getUidState(callingUid); - final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid); - final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow - || callingUidProcState == ActivityManager.PROCESS_STATE_TOP - || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; - final boolean isCallingUidPersistentSystemProcess = - callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - - // Normal apps with visible app window will be allowed to start activity if app switching - // is allowed, or apps like live wallpaper with non app visible window will be allowed. - final boolean appSwitchAllowedOrFg = - appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY; - final boolean allowCallingUidStartActivity = - ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid)) - && callingUidHasAnyVisibleWindow) - || isCallingUidPersistentSystemProcess; - if (useCallingUidState && allowCallingUidStartActivity) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid - + ", isCallingUidPersistentSystemProcess = " - + isCallingUidPersistentSystemProcess); - } - return false; - } - // take realCallingUid into consideration - final int realCallingUidProcState = (callingUid == realCallingUid) - ? callingUidProcState - : mService.mActiveUids.getUidState(realCallingUid); - final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid) - ? callingUidHasAnyVisibleWindow - : mService.hasActiveVisibleWindow(realCallingUid); - final boolean isRealCallingUidForeground = (callingUid == realCallingUid) - ? isCallingUidForeground - : realCallingUidHasAnyVisibleWindow - || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP; - final int realCallingAppId = UserHandle.getAppId(realCallingUid); - final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid) - ? isCallingUidPersistentSystemProcess - : (realCallingAppId == Process.SYSTEM_UID) - || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - - // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a - // visible window. - if (Process.isSdkSandboxUid(realCallingUid)) { - int realCallingSdkSandboxUidToAppUid = Process.getAppUidForSdkSandboxUid( - UserHandle.getAppId(realCallingUid)); - - if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed: uid in SDK sandbox (" - + realCallingUid + ") has visible (non-toast) window."); - } - return false; - } - } - - // Legacy behavior allows to use caller foreground state to bypass BAL restriction. - final boolean balAllowedByPiSender = - PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions); - - if (balAllowedByPiSender && realCallingUid != callingUid) { - final boolean useCallerPermission = - PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions); - if (useCallerPermission && 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) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid - + ") has visible (non-toast) window"); - } - return false; - } - // if the realCallingUid is a persistent system process, abort if the IntentSender - // wasn't allowed to start an activity - if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid - + ") is persistent system process AND intent sender allowed " - + "(allowBackgroundActivityStart = true)"); - } - return false; - } - // don't abort if the realCallingUid is an associated companion app - if (mService.isAssociatedCompanionApp(UserHandle.getUserId(realCallingUid), - realCallingUid)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid - + ") is companion app"); - } - return false; - } - } - if (useCallingUidState) { - // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission - if (mService.checkPermission( - START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) - == PERMISSION_GRANTED) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, - "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND " - + "permission granted for uid " - + callingUid); - } - return false; - } - // don't abort if the caller has the same uid as the recents component - if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid - + ") is recents"); - } - return false; - } - // don't abort if the callingUid is the device owner - if (mService.isDeviceOwner(callingUid)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid - + ") is device owner"); - } - return false; - } - // don't abort if the callingUid has companion device - final int callingUserId = UserHandle.getUserId(callingUid); - if (mService.isAssociatedCompanionApp(callingUserId, - callingUid)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid - + ") is companion app"); - } - return false; - } - // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission - if (mService.hasSystemAlertWindowPermission(callingUid, - callingPid, callingPackage)) { - Slog.w(TAG, "Background activity start for " + callingPackage - + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); - return false; - } - } - // 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 if caller allows, so that we can make the decision based on its state. - int callerAppUid = callingUid; - if (callerApp == null && balAllowedByPiSender) { - callerApp = mService.getProcessController(realCallingPid, realCallingUid); - callerAppUid = realCallingUid; - } - // don't abort if the callerApp or other processes of that uid are allowed in any way - if (callerApp != null && useCallingUidState) { - // first check the original calling process - if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "Background activity start allowed: callerApp process (pid = " - + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed"); - } - return false; - } - // only if that one wasn't allowed, check the other ones - final ArraySet uidProcesses = - mService.mProcessMap.getProcesses(callerAppUid); - if (uidProcesses != null) { - for (int i = uidProcesses.size() - 1; i >= 0; i--) { - final WindowProcessController proc = uidProcesses.valueAt(i); - if (proc != callerApp - && proc.areBackgroundActivityStartsAllowed(appSwitchState)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, - "Background activity start allowed: process " + proc.getPid() - + " from uid " + callerAppUid + " is allowed"); - } - return false; - } - } - } - } - // anything that has fallen through would currently be aborted - Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage - + "; callingUid: " + callingUid - + "; appSwitchState: " + appSwitchState - + "; isCallingUidForeground: " + isCallingUidForeground - + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow - + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class, - "PROCESS_STATE_", callingUidProcState) - + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess - + "; realCallingUid: " + realCallingUid - + "; isRealCallingUidForeground: " + isRealCallingUidForeground - + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow - + "; realCallingUidProcState: " + DebugUtils.valueToString(ActivityManager.class, - "PROCESS_STATE_", realCallingUidProcState) - + "; isRealCallingUidPersistentSystemProcess: " - + isRealCallingUidPersistentSystemProcess - + "; originatingPendingIntent: " + originatingPendingIntent - + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart - + "; intent: " + intent - + "; callerApp: " + callerApp - + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask()) - + "]"); - // log aborted activity start to TRON - if (mService.isActivityStartsLoggingEnabled()) { - mSupervisor.getActivityMetricsLogger().logAbortedBgActivityStart(intent, callerApp, - callingUid, callingPackage, callingUidProcState, callingUidHasAnyVisibleWindow, - realCallingUid, realCallingUidProcState, realCallingUidHasAnyVisibleWindow, - (originatingPendingIntent != null)); - } - return true; - } - /** * Creates a launch intent for the given auxiliary resolution data. */ @@ -1649,7 +1376,7 @@ class ActivityStarter { private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, - TaskFragment inTaskFragment, boolean restrictedBgActivity, + TaskFragment inTaskFragment, @BalCode int balCode, NeededUriGrants intentGrants) { int result = START_CANCELED; final Task startedActivityRootTask; @@ -1669,7 +1396,7 @@ class ActivityStarter { try { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, - startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity, + startFlags, doResume, options, inTask, inTaskFragment, balCode, intentGrants); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); @@ -1816,10 +1543,10 @@ class ActivityStarter { int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, - TaskFragment inTaskFragment, boolean restrictedBgActivity, + TaskFragment inTaskFragment, @BalCode int balCode, NeededUriGrants intentGrants) { setInitialState(r, options, inTask, inTaskFragment, doResume, startFlags, sourceRecord, - voiceSession, voiceInteractor, restrictedBgActivity); + voiceSession, voiceInteractor, balCode); computeLaunchingTaskFlags(); mIntent.setFlags(mLaunchFlags); @@ -2055,7 +1782,8 @@ class ActivityStarter { || !targetTask.isUidPresent(mCallingUid) || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode())); - if (mRestrictedBgActivity && blockBalInTask && handleBackgroundActivityAbort(r)) { + if (mBalCode == BAL_BLOCK && blockBalInTask + && handleBackgroundActivityAbort(r)) { Slog.e(TAG, "Abort background activity starts from " + mCallingUid); return START_ABORTED; } @@ -2452,7 +2180,7 @@ class ActivityStarter { mIntent = null; mCallingUid = -1; mOptions = null; - mRestrictedBgActivity = false; + mBalCode = BAL_ALLOW_DEFAULT; mLaunchTaskBehind = false; mLaunchFlags = 0; @@ -2497,7 +2225,7 @@ class ActivityStarter { private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask, TaskFragment inTaskFragment, boolean doResume, int startFlags, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor, boolean restrictedBgActivity) { + IVoiceInteractor voiceInteractor, @BalCode int balCode) { reset(false /* clearRequest */); mStartActivity = r; @@ -2508,7 +2236,7 @@ class ActivityStarter { mSourceRootTask = mSourceRecord != null ? mSourceRecord.getRootTask() : null; mVoiceSession = voiceSession; mVoiceInteractor = voiceInteractor; - mRestrictedBgActivity = restrictedBgActivity; + mBalCode = balCode; mLaunchParams.reset(); @@ -2645,7 +2373,7 @@ class ActivityStarter { mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; - if (mRestrictedBgActivity && !mService.isBackgroundActivityStartsEnabled()) { + if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) { mAvoidMoveToFront = true; mDoResume = false; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index c527310abb144..f6e92a6429003 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2182,10 +2182,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (appThread != null) { callerApp = getProcessController(appThread); } - final ActivityStarter starter = getActivityStartController().obtainStarter( - null /* intent */, "moveTaskToFront"); - if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1, - -1, callerApp, null, false, null, null)) { + final BackgroundActivityStartController balController = + getActivityStartController().getBackgroundActivityLaunchController(); + if (balController.shouldAbortBackgroundActivityStart( + callingUid, + callingPid, + callingPackage, + -1, + -1, + callerApp, + null, + false, + null, + null)) { if (!isBackgroundActivityStartsEnabled()) { return; } diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index 0bfc48b4b54c5..b160af6a3e11f 100644 --- a/services/core/java/com/android/server/wm/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -119,10 +119,20 @@ class AppTaskImpl extends IAppTask.Stub { if (appThread != null) { callerApp = mService.getProcessController(appThread); } - final ActivityStarter starter = mService.getActivityStartController().obtainStarter( - null /* intent */, "moveToFront"); - if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, - callingPackage, -1, -1, callerApp, null, false, null, null)) { + final BackgroundActivityStartController balController = + mService.getActivityStartController() + .getBackgroundActivityLaunchController(); + if (balController.shouldAbortBackgroundActivityStart( + callingUid, + callingPid, + callingPackage, + -1, + -1, + callerApp, + null, + false, + null, + null)) { if (!mService.isBackgroundActivityStartsEnabled()) { return; } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java new file mode 100644 index 0000000000000..c7e44b347f6b4 --- /dev/null +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; +import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Process; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.DebugUtils; +import android.util.Slog; + +import com.android.internal.util.FrameworkStatsLog; +import com.android.server.am.PendingIntentRecord; + +import java.lang.annotation.Retention; + +/** + * Helper class to check permissions for starting Activities. + * + *

This class collects all the logic to prevent malicious attempts to start activities. + */ +public class BackgroundActivityStartController { + + private static final String TAG = + TAG_WITH_CLASS_NAME ? "BackgroundActivityStartController" : TAG_ATM; + + private final ActivityTaskManagerService mService; + private final ActivityTaskSupervisor mSupervisor; + + // TODO(b/263368846) Rename when ASM logic is moved in + @Retention(SOURCE) + @IntDef({BAL_BLOCK, + BAL_ALLOW_DEFAULT, + BAL_ALLOW_ALLOWLISTED_UID, + BAL_ALLOW_ALLOWLISTED_COMPONENT, + BAL_ALLOW_VISIBLE_WINDOW, + BAL_ALLOW_PENDING_INTENT, + BAL_ALLOW_BAL_PERMISSION, + BAL_ALLOW_SAW_PERMISSION, + BAL_ALLOW_GRACE_PERIOD, + BAL_ALLOW_FOREGROUND, + BAL_ALLOW_SDK_SANDBOX + }) + public @interface BalCode {} + + static final int BAL_BLOCK = 0; + + static final int BAL_ALLOW_DEFAULT = 1; + + // Following codes are in order of precedence + + /** Important UIDs which should be always allowed to launch activities */ + static final int BAL_ALLOW_ALLOWLISTED_UID = 2; + + /** Apps that fulfill a certain role that can can always launch new tasks */ + static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3; + + /** Apps which currently have a visible window */ + static final int BAL_ALLOW_VISIBLE_WINDOW = 4; + + /** Allowed due to the PendingIntent sender */ + static final int BAL_ALLOW_PENDING_INTENT = 5; + + /** App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges + * granted to it */ + static final int BAL_ALLOW_BAL_PERMISSION = 6; + + /** Process has SYSTEM_ALERT_WINDOW permission granted to it */ + static final int BAL_ALLOW_SAW_PERMISSION = 7; + + /** App is in grace period after an activity was started or finished */ + static final int BAL_ALLOW_GRACE_PERIOD = 8; + + /** App is in a foreground task or bound to a foreground service (but not itself visible) */ + static final int BAL_ALLOW_FOREGROUND = 9; + + /** Process belongs to a SDK sandbox */ + static final int BAL_ALLOW_SDK_SANDBOX = 10; + + BackgroundActivityStartController( + final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) { + mService = service; + mSupervisor = supervisor; + } + + private boolean isHomeApp(int uid, @Nullable String packageName) { + if (mService.mHomeProcess != null) { + // Fast check + return uid == mService.mHomeProcess.mUid; + } + if (packageName == null) { + return false; + } + ComponentName activity = + mService.getPackageManagerInternalLocked() + .getDefaultHomeActivity(UserHandle.getUserId(uid)); + return activity != null && packageName.equals(activity.getPackageName()); + } + + boolean shouldAbortBackgroundActivityStart( + int callingUid, + int callingPid, + final String callingPackage, + int realCallingUid, + int realCallingPid, + WindowProcessController callerApp, + PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart, + Intent intent, + ActivityOptions checkedOptions) { + return checkBackgroundActivityStart(callingUid, callingPid, callingPackage, + realCallingUid, realCallingPid, callerApp, originatingPendingIntent, + allowBackgroundActivityStart, intent, checkedOptions) == BAL_BLOCK; + } + + /** + * @return A code denoting which BAL rule allows an activity to be started, + * or {@link BAL_BLOCK} if the launch should be blocked + */ + @BalCode + int checkBackgroundActivityStart( + int callingUid, + int callingPid, + final String callingPackage, + int realCallingUid, + int realCallingPid, + WindowProcessController callerApp, + PendingIntentRecord originatingPendingIntent, + boolean allowBackgroundActivityStart, + Intent intent, + ActivityOptions checkedOptions) { + // don't abort for the most important UIDs + final int callingAppId = UserHandle.getAppId(callingUid); + final boolean useCallingUidState = + originatingPendingIntent == null + || checkedOptions == null + || !checkedOptions.getIgnorePendingIntentCreatorForegroundState(); + if (useCallingUidState) { + if (callingUid == Process.ROOT_UID + || callingAppId == Process.SYSTEM_UID + || callingAppId == Process.NFC_UID) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_UID, /*background*/ false, + callingUid, realCallingUid, intent, "Important callingUid"); + } + + // Always allow home application to start activities. + if (isHomeApp(callingUid, callingPackage)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ false, callingUid, realCallingUid, intent, + "Home app"); + } + + // IME should always be allowed to start activity, like IME settings. + final WindowState imeWindow = + mService.mRootWindowContainer.getCurrentInputMethodWindow(); + if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ false, callingUid, realCallingUid, intent, + "Active ime"); + } + } + + // This is used to block background activity launch even if the app is still + // visible to user after user clicking home button. + final int appSwitchState = mService.getBalAppSwitchesState(); + + // don't abort if the callingUid has a visible window or is a persistent system process + final int callingUidProcState = mService.mActiveUids.getUidState(callingUid); + final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid); + final boolean isCallingUidForeground = + callingUidHasAnyVisibleWindow + || callingUidProcState == ActivityManager.PROCESS_STATE_TOP + || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; + final boolean isCallingUidPersistentSystemProcess = + callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; + + // Normal apps with visible app window will be allowed to start activity if app switching + // is allowed, or apps like live wallpaper with non app visible window will be allowed. + final boolean appSwitchAllowedOrFg = + appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY; + final boolean allowCallingUidStartActivity = + ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid)) + && callingUidHasAnyVisibleWindow) + || isCallingUidPersistentSystemProcess; + if (useCallingUidState && allowCallingUidStartActivity) { + return logStartAllowedAndReturnCode(BAL_ALLOW_VISIBLE_WINDOW, + /*background*/ false, callingUid, realCallingUid, intent, + "callingUidHasAnyVisibleWindow = " + + callingUid + + ", isCallingUidPersistentSystemProcess = " + + isCallingUidPersistentSystemProcess); + } + // take realCallingUid into consideration + final int realCallingUidProcState = + (callingUid == realCallingUid) + ? callingUidProcState + : mService.mActiveUids.getUidState(realCallingUid); + final boolean realCallingUidHasAnyVisibleWindow = + (callingUid == realCallingUid) + ? callingUidHasAnyVisibleWindow + : mService.hasActiveVisibleWindow(realCallingUid); + final boolean isRealCallingUidForeground = + (callingUid == realCallingUid) + ? isCallingUidForeground + : realCallingUidHasAnyVisibleWindow + || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP; + final int realCallingAppId = UserHandle.getAppId(realCallingUid); + final boolean isRealCallingUidPersistentSystemProcess = + (callingUid == realCallingUid) + ? isCallingUidPersistentSystemProcess + : (realCallingAppId == Process.SYSTEM_UID) + || realCallingUidProcState + <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; + + // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a + // visible window. + if (Process.isSdkSandboxUid(realCallingUid)) { + int realCallingSdkSandboxUidToAppUid = + Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid)); + + if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX, + /*background*/ false, callingUid, realCallingUid, intent, + "uid in SDK sandbox has visible (non-toast) window"); + } + } + + // Legacy behavior allows to use caller foreground state to bypass BAL restriction. + final boolean balAllowedByPiSender = + PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions); + + if (balAllowedByPiSender && realCallingUid != callingUid) { + final boolean useCallerPermission = + PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions); + if (useCallerPermission + && ActivityManager.checkComponentPermission( + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, + realCallingUid, + -1, + true) + == PackageManager.PERMISSION_GRANTED) { + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, + "realCallingUid has BAL permission. realCallingUid: " + realCallingUid); + } + + // don't abort if the realCallingUid has a visible window + // TODO(b/171459802): We should check appSwitchAllowed also + if (realCallingUidHasAnyVisibleWindow) { + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, + "realCallingUid has visible (non-toast) window. realCallingUid: " + + realCallingUid); + } + // if the realCallingUid is a persistent system process, abort if the IntentSender + // wasn't allowed to start an activity + if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) { + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, + "realCallingUid is persistent system process AND intent " + + "sender allowed (allowBackgroundActivityStart = true). " + + "realCallingUid: " + realCallingUid); + } + // don't abort if the realCallingUid is an associated companion app + if (mService.isAssociatedCompanionApp( + UserHandle.getUserId(realCallingUid), realCallingUid)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT, + /*background*/ false, callingUid, realCallingUid, intent, + "realCallingUid is a companion app. " + + "realCallingUid: " + realCallingUid); + } + } + if (useCallingUidState) { + // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission + if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, + callingPid, callingUid) == PERMISSION_GRANTED) { + return logStartAllowedAndReturnCode(BAL_ALLOW_BAL_PERMISSION, + /*background*/ true, callingUid, realCallingUid, intent, + "START_ACTIVITIES_FROM_BACKGROUND permission granted"); + } + // don't abort if the caller has the same uid as the recents component + if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Recents Component"); + } + // don't abort if the callingUid is the device owner + if (mService.isDeviceOwner(callingUid)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Device Owner"); + } + // don't abort if the callingUid has companion device + final int callingUserId = UserHandle.getUserId(callingUid); + if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) { + return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT, + /*background*/ true, callingUid, realCallingUid, + intent, "Companion App"); + } + // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission + if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) { + Slog.w( + TAG, + "Background activity start for " + + callingPackage + + " allowed because SYSTEM_ALERT_WINDOW permission is granted."); + return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION, + /*background*/ true, callingUid, realCallingUid, + intent, "SYSTEM_ALERT_WINDOW permission is granted"); + } + } + // 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 if caller allows, so that we can make the decision based on its state. + int callerAppUid = callingUid; + if (callerApp == null && balAllowedByPiSender) { + callerApp = mService.getProcessController(realCallingPid, realCallingUid); + callerAppUid = realCallingUid; + } + // don't abort if the callerApp or other processes of that uid are allowed in any way + if (callerApp != null && useCallingUidState) { + // first check the original calling process + @BalCode int balAllowedForCaller = callerApp + .areBackgroundActivityStartsAllowed(appSwitchState); + if (balAllowedForCaller != BAL_BLOCK) { + return logStartAllowedAndReturnCode(balAllowedForCaller, + /*background*/ true, callingUid, realCallingUid, intent, + "callerApp process (pid = " + callerApp.getPid() + + ", uid = " + callerAppUid + ") is allowed"); + } + // only if that one wasn't allowed, check the other ones + final ArraySet uidProcesses = + mService.mProcessMap.getProcesses(callerAppUid); + if (uidProcesses != null) { + for (int i = uidProcesses.size() - 1; i >= 0; i--) { + final WindowProcessController proc = uidProcesses.valueAt(i); + int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState); + if (proc != callerApp + && balAllowedForUid != BAL_BLOCK) { + return logStartAllowedAndReturnCode(balAllowedForUid, + /*background*/ true, callingUid, realCallingUid, intent, + "process" + proc.getPid() + + " from uid " + callerAppUid + " is allowed"); + } + } + } + } + // anything that has fallen through would currently be aborted + Slog.w( + TAG, + "Background activity start [callingPackage: " + + callingPackage + + "; callingUid: " + + callingUid + + "; appSwitchState: " + + appSwitchState + + "; isCallingUidForeground: " + + isCallingUidForeground + + "; callingUidHasAnyVisibleWindow: " + + callingUidHasAnyVisibleWindow + + "; callingUidProcState: " + + DebugUtils.valueToString( + ActivityManager.class, "PROCESS_STATE_", callingUidProcState) + + "; isCallingUidPersistentSystemProcess: " + + isCallingUidPersistentSystemProcess + + "; realCallingUid: " + + realCallingUid + + "; isRealCallingUidForeground: " + + isRealCallingUidForeground + + "; realCallingUidHasAnyVisibleWindow: " + + realCallingUidHasAnyVisibleWindow + + "; realCallingUidProcState: " + + DebugUtils.valueToString( + ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState) + + "; isRealCallingUidPersistentSystemProcess: " + + isRealCallingUidPersistentSystemProcess + + "; originatingPendingIntent: " + + originatingPendingIntent + + "; allowBackgroundActivityStart: " + + allowBackgroundActivityStart + + "; intent: " + + intent + + "; callerApp: " + + callerApp + + "; inVisibleTask: " + + (callerApp != null && callerApp.hasActivityInVisibleTask()) + + "]"); + // log aborted activity start to TRON + if (mService.isActivityStartsLoggingEnabled()) { + mSupervisor + .getActivityMetricsLogger() + .logAbortedBgActivityStart( + intent, + callerApp, + callingUid, + callingPackage, + callingUidProcState, + callingUidHasAnyVisibleWindow, + realCallingUid, + realCallingUidProcState, + realCallingUidHasAnyVisibleWindow, + (originatingPendingIntent != null)); + } + return BAL_BLOCK; + } + + static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background, + int callingUid, int realCallingUid, Intent intent, int pid, String msg) { + return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent, + DEBUG_ACTIVITY_STARTS ? ("[Process(" + pid + ")]" + msg) : ""); + } + + static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background, + int callingUid, int realCallingUid, Intent intent, String msg) { + statsLogBalAllowed(code, callingUid, realCallingUid, intent); + if (DEBUG_ACTIVITY_STARTS) { + StringBuilder builder = new StringBuilder(); + if (background) { + builder.append("Background "); + } + builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". "); + builder.append("BAL Code: "); + builder.append(code); + Slog.d(TAG, builder.toString()); + } + return code; + } + + private static void statsLogBalAllowed( + @BalCode int code, int callingUid, int realCallingUid, Intent intent) { + if (code == BAL_ALLOW_PENDING_INTENT + && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) { + String activityName = + intent != null ? intent.getComponent().flattenToShortString() : ""; + FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + activityName, + code, + callingUid, + realCallingUid); + } + if (code == BAL_ALLOW_BAL_PERMISSION || code == BAL_ALLOW_FOREGROUND + || code == BAL_ALLOW_SAW_PERMISSION) { + // We don't need to know which activity in this case. + FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + /*activityName*/ "", + code, + callingUid, + realCallingUid); + } + } +} diff --git a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java index 0afd872827834..cc47528f9950c 100644 --- a/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java +++ b/services/core/java/com/android/server/wm/BackgroundLaunchProcessController.java @@ -22,6 +22,10 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW; import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_FOREGROUND; +import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_GRACE_PERIOD; +import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import android.annotation.NonNull; import android.annotation.Nullable; @@ -71,7 +75,8 @@ class BackgroundLaunchProcessController { mBackgroundActivityStartCallback = callback; } - boolean areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, + @BackgroundActivityStartController.BalCode + int areBackgroundActivityStartsAllowed(int pid, int uid, String packageName, int appSwitchState, boolean isCheckingForFgsStart, boolean hasActivityInVisibleTask, boolean hasBackgroundActivityStartPrivileges, long lastStopAppSwitchesTime, long lastActivityLaunchTime, @@ -88,12 +93,10 @@ class BackgroundLaunchProcessController { // let app to be able to start background activity even it's in grace period. if (lastActivityLaunchTime > lastStopAppSwitchesTime || lastActivityFinishTime > lastStopAppSwitchesTime) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: within " - + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); - } - return true; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_GRACE_PERIOD, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: within " + + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period"); } if (DEBUG_ACTIVITY_STARTS) { Slog.d(TAG, "[Process(" + pid + ")] Activity start within " @@ -105,39 +108,31 @@ class BackgroundLaunchProcessController { } // Allow if the proc is instrumenting with background activity starts privs. if (hasBackgroundActivityStartPrivileges) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process instrumenting with background " + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process instrumenting with background " + "activity starts privileges"); - } - return true; } // Allow if the caller has an activity in any foreground task. if (hasActivityInVisibleTask && (appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process has activity in foreground task"); - } - return true; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process has activity in foreground task"); } // Allow if the caller is bound by a UID that's currently foreground. if (isBoundByForegroundUid()) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process bound by foreground uid"); - } - return true; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_FOREGROUND, /*background*/ false, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process bound by foreground uid"); } // Allow if the flag was explicitly set. if (isBackgroundStartAllowedByToken(uid, packageName, isCheckingForFgsStart)) { - if (DEBUG_ACTIVITY_STARTS) { - Slog.d(TAG, "[Process(" + pid - + ")] Activity start allowed: process allowed by token"); - } - return true; + return BackgroundActivityStartController.logStartAllowedAndReturnCode( + BAL_ALLOW_BAL_PERMISSION, /*background*/ true, uid, uid, /*intent*/ null, + pid, "Activity start allowed: process allowed by token"); } - return false; + return BAL_BLOCK; } /** diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index 6602d29883e4a..4f506a5dd945f 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -14,3 +14,6 @@ winsonc@google.com tigerhuang@google.com lihongyu@google.com mariiasand@google.com + +per-file BackgroundActivityStartController.java = set noparent +per-file BackgroundActivityStartController.java = brufino@google.com, ogunwale@google.com, louischang@google.com, lus@google.com, rickywai@google.com diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 682918b1e7ddc..04799204322d7 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -40,6 +40,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK; import static com.android.server.wm.WindowManagerService.MY_PID; import android.Manifest; @@ -544,15 +545,17 @@ public class WindowProcessController extends ConfigurationContainer ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + "", // activity name + BackgroundActivityStartController.BAL_ALLOW_BAL_PERMISSION, + UNIMPORTANT_UID, + UNIMPORTANT_UID2)); + mockingSession.finishMocking(); + } + + /** + * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT. + */ + @Test + public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() { + doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled(); + MockitoSession mockingSession = mockitoSession() + .mockStatic(ActivityTaskManagerService.class) + .mockStatic(FrameworkStatsLog.class) + .mockStatic(PendingIntentRecord.class) + .strictness(Strictness.LENIENT) + .startMocking(); + doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( + eq(START_ACTIVITIES_FROM_BACKGROUND), + anyInt(), anyInt())); + doReturn(true).when( + () -> PendingIntentRecord.isPendingIntentBalAllowedByCaller(anyObject())); + runAndVerifyBackgroundActivityStartsSubtest( + "allowed_notAborted", false, + UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP, + Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP, + false, true, false, false, false); + verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED, + DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME, + BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT, + UNIMPORTANT_UID, + Process.SYSTEM_UID)); + mockingSession.finishMocking(); + } + private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, @@ -1491,7 +1563,7 @@ public class ActivityStarterTests extends WindowTestsBase { TaskFragment inTaskFragment) { starter.startActivityInner(target, source, null /* voiceSession */, null /* voiceInteractor */, 0 /* startFlags */, true /* doResume */, - options, inTask, inTaskFragment, false /* restrictedBgActivity */, - null /* intentGrants */); + options, inTask, inTaskFragment, + BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java index 47c217651e786..b7f8564595dfb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java @@ -188,7 +188,7 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase { /* options */null, /* inTask */null, /* inTaskFragment */ null, - /* restrictedBgActivity */false, + /* balCode */ BackgroundActivityStartController.BAL_ALLOW_DEFAULT, /* intentGrants */null); assertEquals(result, START_ABORTED);