From eea8d3eb91d02332f7b7b9f0f4642c63f57648b8 Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Wed, 10 Apr 2019 17:37:25 +0100 Subject: [PATCH] Tighten rules for blocking activity starts. This means we now block various cases where we failed to before, including where an app launches an activity shortly after the home button has been pressed, e.g. from within onPause() - either immediately or after some blocking call. Details: - We no longer use process state at all, since a process may remain top for a time after the user has switched away and its windows have ceased to be visible. - We no longer allow a start if callerApp.hasForegroundActivities(), because we are checking for windows visible to the user and an activity may be considered foreground even when it doesn't have such windows. - Windows are only considered visible if isNowVisible() is true, rather than isVisible(). Bug: 128688247 Test: atest BackgroundActivityLaunchTest RootWindowContainerTests \ WmTests:ActivityStarterTests \ CtsActivityManagerDeviceTestCases:ActivityStarterTests Test: Manual verification with self-restarting test app Change-Id: I9863d8637661f15828ced435ff23812a4beef78d --- .../android/server/wm/ActivityStarter.java | 15 +++------ .../wm/ActivityTaskManagerInternal.java | 2 +- .../server/wm/ActivityTaskManagerService.java | 4 +-- .../server/wm/RootWindowContainer.java | 7 ++-- .../server/wm/ActivityStarterTests.java | 32 +++++++++---------- .../server/wm/RootWindowContainerTests.java | 10 +++--- 6 files changed, 33 insertions(+), 37 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 473a8757f09fd..895744424ee1f 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -937,7 +937,7 @@ class ActivityStarter { || callingUid == Process.NFC_UID) { return false; } - // don't abort if the callingUid is in the foreground or is a persistent system process + // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid); @@ -946,7 +946,7 @@ class ActivityStarter { || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; final boolean isCallingUidPersistentSystemProcess = (callingUid == Process.SYSTEM_UID) || callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - if (isCallingUidForeground || isCallingUidPersistentSystemProcess) { + if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) { return false; } // take realCallingUid into consideration @@ -965,8 +965,8 @@ class ActivityStarter { : (realCallingUid == Process.SYSTEM_UID) || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { - // don't abort if the realCallingUid is in the foreground and callingUid isn't - if (isRealCallingUidForeground) { + // don't abort if the realCallingUid has a visible window + if (realCallingUidHasAnyVisibleWindow) { return false; } // if the realCallingUid is a persistent system process, abort if the IntentSender @@ -988,10 +988,6 @@ class ActivityStarter { callerApp = mService.getProcessController(realCallingPid, realCallingUid); } if (callerApp != null) { - // don't abort if the callerApp has any visible activity - if (callerApp.hasForegroundActivities()) { - return false; - } // don't abort if the callerApp is instrumenting with background activity starts privs if (callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) { return false; @@ -1061,8 +1057,7 @@ class ActivityStarter { final ArraySet boundClientUids = callerApp.getBoundClientUids(); for (int i = boundClientUids.size() - 1; i >= 0; --i) { final int uid = boundClientUids.valueAt(i); - if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid) - || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) { + if (mService.isUidForeground(uid)) { return true; } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d25466bf348a..48aee200ccc06 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -503,7 +503,7 @@ public abstract class ActivityTaskManagerInternal { public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution); - /** Returns true if uid has a visible window or its process is in a top state. */ + /** Returns true if uid is considered foreground for activity start purposes. */ public abstract boolean isUidForeground(int uid); /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index b4249046c1b58..22e6a35732b4b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5872,8 +5872,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } boolean isUidForeground(int uid) { - return (getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) - || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); + // A uid is considered to be foreground if it has a visible non-toast window. + return mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); } boolean isDeviceOwner(int uid) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1ca31f127b0d7..f9fd54178ca72 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -314,9 +314,10 @@ class RootWindowContainer extends WindowContainer * Returns true if the callingUid has any non-toast window currently visible to the user. */ boolean isAnyNonToastWindowVisibleForUid(int callingUid) { - return forAllWindows(w -> { - return w.getOwningUid() == callingUid && w.isVisible() && w.mAttrs.type != TYPE_TOAST; - }, true /* traverseTopToBottom */); + return forAllWindows(w -> + w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST + && w.isVisibleNow(), + true /* traverseTopToBottom */); } /** 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 44aa55d07133d..45d52195c5fde 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -577,12 +577,27 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_realCallingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_hasForegroundActivities_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + true, false, false, false, false, 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. + * The scenarios each have only one condition that makes them supported. */ @Test public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() { @@ -605,26 +620,11 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, 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); 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); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidProcessStateTop_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - 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, false); runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsRecents_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 35a8ec37c758a..263f6501bbf6e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -50,8 +50,8 @@ public class RootWindowContainerTests extends WindowTestsBase { toastyToast.mHasSurface = true; app.mHasSurface = true; - assertTrue(toastyToast.isVisible()); - assertTrue(app.isVisible()); + assertTrue(toastyToast.isVisibleNow()); + assertTrue(app.isVisibleNow()); assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -60,7 +60,7 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID); toastyToast.mHasSurface = true; - assertTrue(toastyToast.isVisible()); + assertTrue(toastyToast.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -69,8 +69,8 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID); final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID); - assertFalse(topBar.isVisible()); - assertFalse(app.isVisible()); + assertFalse(topBar.isVisibleNow()); + assertFalse(app.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); }