diff options
| author | 2025-03-13 12:21:27 +0800 | |
|---|---|---|
| committer | 2025-03-13 15:10:36 +0800 | |
| commit | 0ed78b237430f85c150b54f658904133d0c43428 (patch) | |
| tree | 1d030c5ece2c6a80926e0da40baa63c00e49cf94 | |
| parent | fe243d087df459c25bef5f8c2c1e1a6229fdcef2 (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
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()); } |