summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2025-03-13 12:21:27 +0800
committer Riddle Hsu <riddlehsu@google.com> 2025-03-13 15:10:36 +0800
commit0ed78b237430f85c150b54f658904133d0c43428 (patch)
tree1d030c5ece2c6a80926e0da40baa63c00e49cf94
parentfe243d087df459c25bef5f8c2c1e1a6229fdcef2 (diff)
Do not count closing activity as visible process
Previously, VisibleActivityProcessTracker#hasVisibleActivity can still return true when the only activity of a process is in a playing transition animation (since shell transition only commits invisible until transition is done). That may lead to a timing that background launch check still allows the process with visible window to launch activity. For example, after pressing home key, the closing app may still be able to launch activity at a specific timing after APP_SWITCH_DISALLOW updates to APP_SWITCH_FG_ONLY but the transition is not finished yet. Bug: 396653764 Flag: com.android.window.flags.use_visible_requested_for_process_tracker Test: WindowProcessControllerTests#testComputeProcessActivityState Change-Id: I064ce5cbb140c68d3e1a482980df52ee5d37f361
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig11
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java11
3 files changed, 40 insertions, 12 deletions
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 816270235446..8dd0457248a4 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -287,6 +287,17 @@ flag {
}
flag {
+ name: "use_visible_requested_for_process_tracker"
+ namespace: "windowing_frontend"
+ description: "Do not count closing activity as visible process"
+ bug: "396653764"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "ensure_wallpaper_in_transitions"
namespace: "windowing_frontend"
description: "Ensure that wallpaper window tokens are always present/available for collection in transitions"
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bdd13722aba4..d356128205df 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -337,6 +337,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
public static final int ACTIVITY_STATE_FLAG_VISIBLE_MULTI_WINDOW_MODE = 1 << 25;
public static final int ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER = 0x0000ffff;
+ private static final int ACTIVITY_STATE_VISIBLE =
+ com.android.window.flags.Flags.useVisibleRequestedForProcessTracker()
+ ? ACTIVITY_STATE_FLAG_IS_VISIBLE
+ : ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE;
+
/**
* The state for oom-adjustment calculation. The higher 16 bits are the activity states, and the
* lower 16 bits are the task layer rank (see {@link Task#mLayerRank}). This field is written by
@@ -1260,8 +1265,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
int nonOccludedRatio = 0;
long perceptibleTaskStoppedTimeMillis = Long.MIN_VALUE;
final boolean wasResumed = hasResumedActivity();
- final boolean wasAnyVisible = (mActivityStateFlags
- & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
+ final boolean wasAnyVisible = (mActivityStateFlags & ACTIVITY_STATE_VISIBLE) != 0;
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
if (r.isVisible()) {
@@ -1275,8 +1279,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (task.mLayerRank != Task.LAYER_RANK_INVISIBLE) {
stateFlags |= ACTIVITY_STATE_FLAG_HAS_ACTIVITY_IN_VISIBLE_TASK;
}
+ final ActivityRecord.State state = r.getState();
if (r.isVisibleRequested()) {
- if (r.isState(RESUMED)) {
+ if (state == RESUMED) {
stateFlags |= ACTIVITY_STATE_FLAG_HAS_RESUMED;
final int windowingMode = r.getWindowingMode();
if (windowingMode == WINDOWING_MODE_MULTI_WINDOW
@@ -1301,13 +1306,21 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// this process, we'd find out the one with the minimal layer, thus it'll
// get a higher adj score.
} else if (!visible && bestInvisibleState != PAUSING) {
- if (r.isState(PAUSING, PAUSED)) {
+ if (state == PAUSING) {
bestInvisibleState = PAUSING;
- } else if (r.isState(STOPPING)) {
+ // Treat PAUSING as visible in case the next activity in the same process has
+ // not yet been set as visible-requested.
+ if (com.android.window.flags.Flags.useVisibleRequestedForProcessTracker()
+ && r.isVisible()) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
+ }
+ } else if (state == PAUSED) {
+ bestInvisibleState = PAUSED;
+ } else if (state == STOPPING) {
bestInvisibleState = STOPPING;
// Not "finishing" if any of activity isn't finishing.
allStoppingFinishing &= r.finishing;
- } else if (bestInvisibleState == DESTROYED && r.isState(STOPPED)) {
+ } else if (bestInvisibleState == DESTROYED && state == STOPPED) {
if (task.mIsPerceptible) {
perceptibleTaskStoppedTimeMillis =
Long.max(r.mStoppedTime, perceptibleTaskStoppedTimeMillis);
@@ -1340,7 +1353,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
stateFlags |= minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
if (visible) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
- } else if (bestInvisibleState == PAUSING) {
+ } else if (bestInvisibleState == PAUSING || bestInvisibleState == PAUSED) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
} else if (bestInvisibleState == STOPPING) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING;
@@ -1351,8 +1364,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mActivityStateFlags = stateFlags;
mPerceptibleTaskStoppedTimeMillis = perceptibleTaskStoppedTimeMillis;
- final boolean anyVisible = (stateFlags
- & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
+ final boolean anyVisible = (stateFlags & ACTIVITY_STATE_VISIBLE) != 0;
if (!wasAnyVisible && anyVisible) {
mAtm.mVisibleActivityProcessTracker.onAnyActivityVisible(this);
mAtm.mWindowManager.onProcessActivityVisibilityChanged(mUid, true /*visible*/);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 9dc70266bf3d..5347f9a36652 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -382,12 +382,17 @@ public class WindowProcessControllerTests extends WindowTestsBase {
assertFalse(tracker.hasResumedActivity(mWpc.mUid));
assertTrue(mWpc.hasForegroundActivities());
- activity.setVisibility(false);
activity.setVisibleRequested(false);
- activity.setState(STOPPED, "test");
-
+ if (com.android.window.flags.Flags.useVisibleRequestedForProcessTracker()) {
+ assertTrue("PAUSING is visible", mWpc.hasVisibleActivities());
+ activity.setState(PAUSED, "test");
+ } else {
+ activity.setVisible(false);
+ }
verify(tracker).onAllActivitiesInvisible(mWpc);
assertFalse(mWpc.hasVisibleActivities());
+
+ activity.setState(STOPPED, "test");
assertFalse(mWpc.hasForegroundActivities());
}