summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java56
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java51
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java76
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java2
10 files changed, 195 insertions, 32 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1edd7f5e429d..af3da0cbf5ee 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -243,6 +243,8 @@ public abstract class ActivityManagerInternal {
public abstract void ensureBootCompleted();
public abstract void updateOomLevelsForDisplay(int displayId);
public abstract boolean isActivityStartsLoggingEnabled();
+ /** Returns true if the background activity starts is enabled. */
+ public abstract boolean isBackgroundActivityStartsEnabled();
public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);
/** Input dispatch timeout to a window, start the ANR process. */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 848b041007c2..83be63c6cb22 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11035,6 +11035,16 @@ public final class Settings {
= "activity_starts_logging_enabled";
/**
+ * Feature flag to enable or disable the background activity starts.
+ * When disabled, apps aren't allowed to start activities unless they're in the foreground.
+ * Type: int (0 for false, 1 for true)
+ * Default: 1
+ * @hide
+ */
+ public static final String BACKGROUND_ACTIVITY_STARTS_ENABLED =
+ "background_activity_starts_enabled";
+
+ /**
* @hide
* @see com.android.server.appbinding.AppBindingConstants
*/
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8f583307adab..21e7b9c64c5c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -126,6 +126,7 @@ public class SettingsBackupTest {
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 5c77f0a3ad47..8571ae6b07f6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
@@ -26,8 +28,6 @@ import android.util.Slog;
import java.io.PrintWriter;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
-
/**
* Settings constants that can modify the activity manager's behavior.
*/
@@ -222,6 +222,10 @@ final class ActivityManagerConstants extends ContentObserver {
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
+ // Indicates whether the background activity starts is enabled.
+ // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED
+ volatile boolean mFlagBackgroundActivityStartsEnabled;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -256,6 +260,10 @@ final class ActivityManagerConstants extends ContentObserver {
private static final Uri ACTIVITY_STARTS_LOGGING_ENABLED_URI = Settings.Global.getUriFor(
Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED);
+ private static final Uri BACKGROUND_ACTIVITY_STARTS_ENABLED_URI =
+ Settings.Global.getUriFor(
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED);
+
public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
super(handler);
mService = service;
@@ -266,8 +274,10 @@ final class ActivityManagerConstants extends ContentObserver {
mResolver = resolver;
mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this);
mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
+ mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_ENABLED_URI, false, this);
updateConstants();
updateActivityStartsLoggingEnabled();
+ updateBackgroundActivityStartsEnabled();
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -290,6 +300,8 @@ final class ActivityManagerConstants extends ContentObserver {
updateConstants();
} else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) {
updateActivityStartsLoggingEnabled();
+ } else if (BACKGROUND_ACTIVITY_STARTS_ENABLED_URI.equals(uri)) {
+ updateBackgroundActivityStartsEnabled();
}
}
@@ -373,6 +385,11 @@ final class ActivityManagerConstants extends ContentObserver {
Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 0) == 1;
}
+ private void updateBackgroundActivityStartsEnabled() {
+ mFlagBackgroundActivityStartsEnabled = Settings.Global.getInt(mResolver,
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, 1) == 1;
+ }
+
private void updateMaxCachedProcesses() {
CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 80e73132f542..b62f648956dd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19204,6 +19204,10 @@ public class ActivityManagerService extends IActivityManager.Stub
return mConstants.mFlagActivityStartsLoggingEnabled;
}
+ public boolean isBackgroundActivityStartsEnabled() {
+ return mConstants.mFlagBackgroundActivityStartsEnabled;
+ }
+
public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
synchronized(ActivityManagerService.this) {
ActivityManagerService.this.reportGlobalUsageEventLocked(keyguardShowing
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 1c08d039207b..7c7553f34a3a 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -850,9 +850,10 @@ class ActivityMetricsLogger {
builder.addTaggedData(FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW,
targetUidHasAnyVisibleWindow ? 1 : 0);
builder.addTaggedData(FIELD_TARGET_WHITELIST_TAG, targetWhitelistTag);
- builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME, r.shortComponentName);
builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
- builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
+ if (intent != null) {
+ builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
+ }
if (callerApp != null) {
builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.mName);
builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE,
@@ -881,29 +882,34 @@ class ActivityMetricsLogger {
(nowUptime - callerApp.getWhenUnimportant()));
}
}
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY, r.info.targetActivity);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_FLAGS, r.info.flags);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_REAL_ACTIVITY, r.realActivity.toShortString());
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME, r.shortComponentName);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_PROCESS_NAME, r.processName);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_FULLSCREEN, r.fullscreen ? 1 : 0);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY, r.noDisplay ? 1 : 0);
- if (r.lastVisibleTime != 0) {
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE,
- (nowUptime - r.lastVisibleTime));
- }
- if (r.resultTo != null) {
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME, r.resultTo.packageName);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME,
- r.resultTo.shortComponentName);
- }
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE, r.visible ? 1 : 0);
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD,
- r.visibleIgnoringKeyguard ? 1 : 0);
- if (r.lastLaunchTime != 0) {
- builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH,
- (nowUptime - r.lastLaunchTime));
+ if (r != null) {
+ builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME, r.shortComponentName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY, r.info.targetActivity);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_FLAGS, r.info.flags);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_REAL_ACTIVITY,
+ r.realActivity.toShortString());
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME, r.shortComponentName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_PROCESS_NAME, r.processName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_FULLSCREEN, r.fullscreen ? 1 : 0);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY, r.noDisplay ? 1 : 0);
+ if (r.lastVisibleTime != 0) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE,
+ (nowUptime - r.lastVisibleTime));
+ }
+ if (r.resultTo != null) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME,
+ r.resultTo.packageName);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME,
+ r.resultTo.shortComponentName);
+ }
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE, r.visible ? 1 : 0);
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD,
+ r.visibleIgnoringKeyguard ? 1 : 0);
+ if (r.lastLaunchTime != 0) {
+ builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH,
+ (nowUptime - r.lastLaunchTime));
+ }
}
mMetricsLogger.write(builder);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 90f3ff84a027..1735ef89918a 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -98,6 +98,7 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -108,6 +109,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
+import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -731,6 +733,12 @@ class ActivityStarter {
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
+ // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
+ // on START_ABORTED
+ if (!abort) {
+ abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, callerApp);
+ }
+
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
@@ -774,6 +782,8 @@ class ActivityStarter {
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(checkedOptions);
+ maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp,
+ /* r= */ null, originatingPendingIntent, /* abortedStart= */ true);
return START_ABORTED;
}
@@ -866,19 +876,50 @@ class ActivityStarter {
mController.doPendingActivityLaunches(false);
maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r,
- originatingPendingIntent);
+ originatingPendingIntent, /* abortedStart= */ false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}
+ private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
+ WindowProcessController callerApp) {
+ if (mService.isBackgroundActivityStartsEnabled()) {
+ return false;
+ }
+ // don't abort for the most important UIDs
+ if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+ return false;
+ }
+ // don't abort if the callerApp has any visible activity
+ if (callerApp != null && callerApp.hasForegroundActivities()) {
+ return false;
+ }
+ // don't abort if the callingUid's process is important enough
+ if (mService.getUidStateLocked(callingUid) <= ActivityManager.PROCESS_STATE_TOP) {
+ return false;
+ }
+ // don't abort if the callingUid has any visible window
+ if (mService.mWindowManager.isAnyWindowVisibleForUid(callingUid)) {
+ return false;
+ }
+ // anything that has fallen through will currently be aborted
+ // TODO: remove this toast after feature development is done
+ mService.mUiHandler.post(() -> {
+ Toast.makeText(mService.mContext,
+ "Blocking background activity start for " + callingPackage,
+ Toast.LENGTH_SHORT).show();
+ });
+ return true;
+ }
+
private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
Intent intent, WindowProcessController callerApp, ActivityRecord r,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
boolean callerAppHasForegroundActivity =
callerApp != null && callerApp.hasForegroundActivities();
if (!mService.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity
- || r == null) {
+ || (!abortedStart && r == null)) {
// skip logging in this case
return;
}
@@ -894,8 +935,8 @@ class ActivityStarter {
final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
? callingUidHasAnyVisibleWindow
: mService.mWindowManager.isAnyWindowVisibleForUid(realCallingUid);
- final String targetPackage = r.packageName;
- final int targetUid = (r.appInfo != null) ? r.appInfo.uid : -1;
+ final String targetPackage = (r != null) ? r.packageName : null;
+ final int targetUid = (r!= null) ? ((r.appInfo != null) ? r.appInfo.uid : -1) : -1;
final int targetUidProcState = mService.getUidStateLocked(targetUid);
final boolean targetUidHasAnyVisibleWindow = (targetUid != -1)
? mService.mWindowManager.isAnyWindowVisibleForUid(targetUid)
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index d0e3fb47730e..054b105fbfa4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5016,6 +5016,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mAmInternal.isActivityStartsLoggingEnabled();
}
+ boolean isBackgroundActivityStartsEnabled() {
+ return mAmInternal.isBackgroundActivityStartsEnabled();
+ }
+
void enableScreenAfterBoot(boolean booted) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 50aa541a9549..f6ff05b077d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
@@ -69,6 +70,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
@@ -110,6 +112,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
private static final int FAKE_CALLING_UID = 666;
private static final int FAKE_REAL_CALLING_UID = 667;
private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
+ private static final int UNIMPORTANT_UID = 12345;
@Before
public void setUp() throws Exception {
@@ -551,6 +554,79 @@ public class ActivityStarterTests extends ActivityTestsBase {
}
/**
+ * This test ensures that unsupported usecases aren't aborted when background starts are
+ * allowed.
+ */
+ @Test
+ public void testBackgroundActivityStartsAllowed_noStartsAborted() {
+ doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
+
+ runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted",
+ false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false);
+ }
+
+ /**
+ * This test ensures that unsupported usecases are aborted when background starts are
+ * disallowed.
+ */
+ @Test
+ public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
+ doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_unsupportedUsecase_aborted",
+ true, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, false);
+ }
+
+ /**
+ * This test ensures that supported usecases aren't aborted when background starts are
+ * disallowed.
+ * The scenarios each have only one condidion that makes them supported.
+ */
+ @Test
+ public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
+ doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
+
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted",
+ false, Process.ROOT_UID, false, PROCESS_STATE_TOP + 1, false);
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted",
+ false, Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1, false);
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasVisibleWindow_notAborted",
+ false, UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, false);
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_processStateTop_notAborted",
+ false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP, false);
+ runAndVerifyBackgroundActivityStartsSubtest("disallowed_hasForegroundActivities_notAborted",
+ false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, true);
+ }
+
+ private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
+ int testCallingUid, boolean hasVisibleWindow, int procState,
+ boolean hasForegroundActivities) {
+ // window visibility
+ doReturn(hasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
+ testCallingUid);
+ // process importance
+ doReturn(procState).when(mService).getUidStateLocked(testCallingUid);
+ // foreground activities
+ final IApplicationThread caller = mock(IApplicationThread.class);
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.uid = testCallingUid;
+ final WindowProcessController callerApp =
+ new WindowProcessController(mService, ai, null, testCallingUid, -1, null, null);
+ callerApp.setHasForegroundActivities(hasForegroundActivities);
+ doReturn(callerApp).when(mService).getProcessController(caller);
+
+ final ActivityOptions options = spy(ActivityOptions.makeBasic());
+ ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK).setCaller(caller)
+ .setCallingUid(testCallingUid).setActivityOptions(new SafeActivityOptions(options));
+
+ final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
+
+ assertEquals(ActivityStarter.getExternalResult(
+ shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
+ verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
+ }
+
+ /**
* This test ensures that when starting an existing single task activity on secondary display
* which is not the top focused display, it should deliver new intent to the activity and not
* create a new stack.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index c2ab3acd4933..cc0ae948b054 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -402,6 +402,8 @@ class ActivityTestsBase {
spyOn(getLifecycleManager());
spyOn(getLockTaskController());
doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
+ // allow background activity starts by default
+ doReturn(true).when(this).isBackgroundActivityStartsEnabled();
}
void setActivityManagerService(IntentFirewall intentFirewall,