Add temporary packageName-based whitelist for allowing
background activity launches
Necessary for early stages of enabling the feature in
enforcing mode - we'll need to temporarily whitelist
apps like Duo, so dogfooders can still use them.
Bug: 123354556
Test: atest WmTests:ActivityStarterTests
Test: adb shell settings put global background_activity_starts_package_names_whitelist com.ejc.bbc:com.whatever.dude
Change-Id: I2515b8ba334e87e7f201569ba5a6bb1b79395354
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7d828d8..92db23b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -276,6 +276,7 @@
public abstract boolean isActivityStartsLoggingEnabled();
/** Returns true if the background activity starts is enabled. */
public abstract boolean isBackgroundActivityStartsEnabled();
+ public abstract boolean isPackageNameWhitelistedForBgActivityStarts(String packageName);
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 45219d6..027525b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11453,6 +11453,15 @@
"background_activity_starts_enabled";
/**
+ * The packages temporarily whitelisted to be able so start activities from background.
+ * The list of packages is {@code ":"} colon delimited.
+ *
+ * @hide
+ */
+ public static final String BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST =
+ "background_activity_starts_package_names_whitelist";
+
+ /**
* @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 ebc6be7..ad1403d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -132,6 +132,7 @@
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BROADCAST_BG_CONSTANTS,
Settings.Global.BROADCAST_FG_CONSTANTS,
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 415a892..f9fcef6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -27,6 +27,8 @@
import android.provider.DeviceConfig.OnPropertyChangedListener;
import android.provider.Settings;
import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -235,6 +237,8 @@
// Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED
volatile boolean mFlagBackgroundActivityStartsEnabled;
+ volatile ArraySet<String> mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>();
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -273,6 +277,10 @@
Settings.Global.getUriFor(
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED);
+ private static final Uri BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI =
+ Settings.Global.getUriFor(
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
+
private final OnPropertyChangedListener mOnDeviceConfigChangedListener =
new OnPropertyChangedListener() {
@Override
@@ -293,9 +301,12 @@
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);
+ mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI,
+ false, this);
updateConstants();
updateActivityStartsLoggingEnabled();
updateBackgroundActivityStartsEnabled();
+ updateBackgroundActivityStartsPackageNamesWhitelist();
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(),
mOnDeviceConfigChangedListener);
@@ -325,6 +336,8 @@
updateActivityStartsLoggingEnabled();
} else if (BACKGROUND_ACTIVITY_STARTS_ENABLED_URI.equals(uri)) {
updateBackgroundActivityStartsEnabled();
+ } else if (BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI.equals(uri)) {
+ updateBackgroundActivityStartsPackageNamesWhitelist();
}
}
@@ -414,6 +427,21 @@
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, 1) == 1;
}
+ private void updateBackgroundActivityStartsPackageNamesWhitelist() {
+ final String setting = Settings.Global.getString(mResolver,
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
+ if (TextUtils.isEmpty(setting)) {
+ return;
+ }
+ ArraySet<String> newSet = new ArraySet<>();
+ SimpleStringSplitter splitter = new SimpleStringSplitter(':');
+ splitter.setString(setting);
+ while (splitter.hasNext()) {
+ newSet.add(splitter.next());
+ }
+ mPackageNamesWhitelistedForBgActivityStarts = newSet;
+ }
+
private void updateMaxCachedProcesses() {
String maxCachedProcessesFlag = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MAX_CACHED_PROCESSES);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ccb9d82..0a68ce0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17862,6 +17862,10 @@
return mConstants.mFlagActivityStartsLoggingEnabled;
}
+ public boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) {
+ return mConstants.mPackageNamesWhitelistedForBgActivityStarts.contains(packageName);
+ }
+
public boolean isBackgroundActivityStartsEnabled() {
return mConstants.mFlagBackgroundActivityStartsEnabled;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 9f04166..23bed7b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1009,6 +1009,12 @@
if (mService.isDeviceOwner(callingPackage)) {
return false;
}
+ // don't abort if the callingPackage is temporarily whitelisted
+ if (mService.isPackageNameWhitelistedForBgActivityStarts(callingPackage)) {
+ Slog.w(TAG, "Background activity start for " + callingPackage
+ + " temporarily whitelisted. This will not be supported in future Q builds.");
+ return false;
+ }
// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index d747198..3255bc6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5210,6 +5210,10 @@
return mAmInternal.isBackgroundActivityStartsEnabled();
}
+ boolean isPackageNameWhitelistedForBgActivityStarts(String packageName) {
+ return mAmInternal.isPackageNameWhitelistedForBgActivityStarts(packageName);
+ }
+
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 606ab31..d02db7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -561,7 +561,7 @@
runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
}
/**
@@ -576,7 +576,7 @@
"disallowed_unsupportedUsecase_aborted", true,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
}
/**
@@ -591,61 +591,66 @@
runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callingUidHasVisibleWindow_notAborted", false,
UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callingUidProcessStateTop_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_realCallingUidHasVisibleWindow_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_realCallingUidProcessStateTop_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
- false, false, false, false, false);
+ false, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_hasForegroundActivities_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- true, false, false, false, false);
+ true, false, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callerIsRecents_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, true, false, false, false);
+ false, true, false, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callerIsWhitelisted_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, true, false, false);
+ false, false, true, false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, true, false);
+ false, false, false, true, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false, false, false, true);
+ false, false, false, false, true, false);
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "disallowed_callingPackageNameIsTempWhitelisted_notAborted", false,
+ UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+ UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+ false, false, false, false, false, true);
}
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
@@ -654,7 +659,7 @@
boolean hasForegroundActivities, boolean callerIsRecents,
boolean callerIsTempWhitelisted,
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
- boolean isCallingPackageNameDeviceOwner) {
+ boolean isCallingPackageNameDeviceOwner, boolean isCallingPackageTempWhitelisted) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
@@ -680,11 +685,15 @@
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
- // calling package name is whitelisted
+ // calling package name is the device owner
doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any());
+ // calling package name is temporarily whitelisted
+ doReturn(isCallingPackageTempWhitelisted).when(mService)
+ .isPackageNameWhitelistedForBgActivityStarts("com.whatever.dude");
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
+ .setCallingPackage("com.whatever.dude")
.setCaller(caller)
.setCallingUid(callingUid)
.setRealCallingUid(realCallingUid)