Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ed78b23 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

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
parent fe243d08
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -286,6 +286,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"
+21 −9
Original line number Diff line number Diff line
@@ -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*/);
+8 −3
Original line number Diff line number Diff line
@@ -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());
    }