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

Commit aee6d8ae authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Remove dead window preservation

The logic was never executed for a long time.
At least since 2016 the condition
"mAttrs.token != mClient.asBinder()" is added in
WindowState#shouldKeepVisibleDeadAppWindow.

Because the logic only cares activity window, but the
token is ActivityRecord.Token, while mClient.asBinder()
is the IWindow from ViewRootImpl.W, the condition is never
satisfied. Also current code won't keep dead process's
ActivityRecord which doesn't have a saved state.

The original purpose is avoid thrashing to restart process
when there are multiple visible activities but the RAM is not
enough so low memory killer is triggered. Since the modern
devices are more powerful, the logic can be removed as
it's been years since no one found out that doesn't work.

Bug: 163976519
Test: CtsWindowManagerDeviceTestCases

Change-Id: I987828d278ec6fa7bb282e8a17af896e355048b8
parent fcb2bb51
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -874,15 +874,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
                    || mWindowingMode == WINDOWING_MODE_MULTI_WINDOW;
    }

    /**
     * Returns true if any visible windows belonging to apps with this window configuration should
     * be kept on screen when the app is killed due to something like the low memory killer.
     * @hide
     */
    public boolean keepVisibleDeadAppWindowOnScreen() {
        return mWindowingMode != WINDOWING_MODE_PINNED;
    }

    /**
     * Returns true if the backdrop on the client side should match the frame of the window.
     * Returns false, if the backdrop should be fullscreen.
+0 −5
Original line number Diff line number Diff line
@@ -251,11 +251,6 @@ class ActivityClientController extends IActivityClientController.Stub {
                    // {@link #restartActivityProcessIfVisible}.
                    restartingName = r.app.mName;
                    restartingUid = r.app.mUid;
                    // Make EnsureActivitiesVisibleHelper#makeVisibleAndRestartIfNeeded not skip
                    // restarting non-top activity.
                    if (r != r.getTask().topRunningActivity()) {
                        r.setVisibleRequested(false);
                    }
                }
                r.activityStopped(icicle, persistentState, description);
            }
+1 −29
Original line number Diff line number Diff line
@@ -4091,9 +4091,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        } else if (!mVisibleRequested && launchCount > 2
                && lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
            // We have launched this activity too many times since it was able to run, so give up
            // and remove it. (Note if the activity is visible, we don't remove the record. We leave
            // the dead window on the screen but the process will not be restarted unless user
            // explicitly tap on it.)
            // and remove it.
            remove = true;
        } else {
            // The process may be gone, but the activity lives on!
@@ -4115,11 +4113,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            if (DEBUG_APP) {
                Slog.v(TAG_APP, "Keeping entry during removeHistory for activity " + this);
            }
            // Set nowVisible to previous visible state. If the app was visible while it died, we
            // leave the dead window on screen so it's basically visible. This is needed when user
            // later tap on the dead window, we need to stop other apps when user transfers focus
            // to the restarted activity.
            nowVisible = mVisibleRequested;
        }
        // upgrade transition trigger to task if this is the last activity since it means we are
        // closing the task.
@@ -5237,10 +5230,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        mLastDeferHidingClient = deferHidingClient;

        if (!visible) {
            // If the app is dead while it was visible, we kept its dead window on screen.
            // Now that the app is going invisible, we can remove it. It will be restarted
            // if made visible again.
            removeDeadWindows();
            // If this activity is about to finish/stopped and now becomes invisible, remove it
            // from the unknownApp list in case the activity does not want to draw anything, which
            // keep the user waiting for the next transition to start.
@@ -6588,9 +6577,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // stop tracking
        mSplashScreenStyleSolidColor = true;

        // We now have a good window to show, remove dead placeholders
        removeDeadWindows();

        if (mStartingWindow != null) {
            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
                    + ": first real window is shown, no animation", win.mToken);
@@ -7326,20 +7312,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }

    void removeDeadWindows() {
        for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
            WindowState win = mChildren.get(winNdx);
            if (win.mAppDied) {
                ProtoLog.w(WM_DEBUG_ADD_REMOVE,
                        "removeDeadWindows: %s", win);
                // Set mDestroying, we don't want any animation or delayed removal here.
                win.mDestroying = true;
                // Also removes child windows.
                win.removeIfPossible();
            }
        }
    }

    void setWillReplaceWindows(boolean animate) {
        ProtoLog.d(WM_DEBUG_ADD_REMOVE,
                "Marking app token %s with replacing windows.", this);
+2 −10
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ class EnsureActivitiesVisibleHelper {
            }

            if (!r.attachedToProcess()) {
                makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop,
                makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges,
                        resumeTopActivity && isTop, r);
            } else if (r.isVisibleRequested()) {
                // If this activity is already visible, then there is nothing to do here.
@@ -243,15 +243,7 @@ class EnsureActivitiesVisibleHelper {
    }

    private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
            boolean isTop, boolean andResume, ActivityRecord r) {
        // We need to make sure the app is running if it's the top, or it is just made visible from
        // invisible. If the app is already visible, it must have died while it was visible. In this
        // case, we'll show the dead window but will not restart the app. Otherwise we could end up
        // thrashing.
        if (!isTop && r.isVisibleRequested() && !r.isState(INITIALIZING)) {
            return;
        }

            boolean andResume, ActivityRecord r) {
        // This activity needs to be visible, but isn't even running...
        // get it started and resume if no other root task in this root task is resumed.
        if (DEBUG_VISIBILITY) {
+6 −96
Original line number Diff line number Diff line
@@ -221,8 +221,6 @@ import android.view.IWindow;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsState;
@@ -571,12 +569,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    /** Completely remove from window manager after exit animation? */
    boolean mRemoveOnExit;

    /**
     * Whether the app died while it was visible, if true we might need
     * to continue to show it until it's restarted.
     */
    boolean mAppDied;

    /**
     * Set when the orientation is changing and this window has not yet
     * been updated for the new orientation.
@@ -760,7 +752,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
     */
    private InsetsState mFrozenInsetsState;

    private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
    private KeyInterceptionInfo mKeyInterceptionInfo;

    /**
@@ -1504,13 +1495,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                }
            }

            // If it's a dead window left on screen, and the configuration changed, there is nothing
            // we can do about it. Remove the window now.
            if (mActivityRecord != null && mAppDied) {
                mActivityRecord.removeDeadWindows();
                return;
            }

            onResizeHandled();
            mWmService.makeWindowFreezingScreenIfNeededLocked(this);

@@ -2009,7 +1993,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    boolean isInteresting() {
        final RecentsAnimationController recentsAnimationController =
                mWmService.getRecentsAnimationController();
        return mActivityRecord != null && !mAppDied
        return mActivityRecord != null
                && (!mActivityRecord.isFreezingScreen() || !mAppFreezing)
                && mViewVisibility == View.VISIBLE
                && (recentsAnimationController == null
@@ -2443,11 +2427,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

    @Override
    void removeIfPossible() {
        super.removeIfPossible();
        removeIfPossible(false /*keepVisibleDeadWindow*/);
    }

    private void removeIfPossible(boolean keepVisibleDeadWindow) {
        mWindowRemovalAllowed = true;
        ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                "removeIfPossible: %s callers=%s", this, Debug.getCallers(5));
@@ -2522,21 +2501,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                // If we are not currently running the exit animation, we need to see about starting one
                wasVisible = isVisible();

                if (keepVisibleDeadWindow) {
                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
                            "Not removing %s because app died while it's visible", this);

                    mAppDied = true;
                    setDisplayLayoutNeeded();
                    mWmService.mWindowPlacerLocked.performSurfacePlacement();

                    // Set up a replacement input channel since the app is now dead.
                    // We need to catch tapping on the dead window to restart the app.
                    openInputChannel(null);
                    displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
                    return;
                }

                // Remove immediately if there is display transition because the animation is
                // usually unnoticeable (e.g. covered by rotation animation) and the animation
                // bounds could be inconsistent, such as depending on when the window applies
@@ -2710,19 +2674,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                || (isVisible() && mActivityRecord != null && mActivityRecord.isVisible());
    }

    private final class DeadWindowEventReceiver extends InputEventReceiver {
        DeadWindowEventReceiver(InputChannel inputChannel) {
            super(inputChannel, mWmService.mH.getLooper());
        }
        @Override
        public void onInputEvent(InputEvent event) {
            finishInputEvent(event, true);
        }
    }
    /** Fake event receiver for windows that died visible. */
    private DeadWindowEventReceiver mDeadWindowEventReceiver;

    void openInputChannel(InputChannel outInputChannel) {
    void openInputChannel(@NonNull InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
@@ -2731,14 +2683,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        mInputChannelToken = mInputChannel.getToken();
        mInputWindowHandle.setToken(mInputChannelToken);
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        if (outInputChannel != null) {
        mInputChannel.copyTo(outInputChannel);
        } else {
            // If the window died visible, we setup a fake input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create fake event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
        }
    }

    /**
@@ -2749,10 +2694,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    }

    void disposeInputChannel() {
        if (mDeadWindowEventReceiver != null) {
            mDeadWindowEventReceiver.dispose();
            mDeadWindowEventReceiver = null;
        }
        if (mInputChannelToken != null) {
            // Unregister server channel first otherwise it complains about broken channel.
            mWmService.mInputManager.removeInputChannel(mInputChannelToken);
@@ -3079,11 +3020,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                            .windowForClientLocked(mSession, mClient, false);
                    Slog.i(TAG, "WIN DEATH: " + win);
                    if (win != null) {
                        final DisplayContent dc = getDisplayContent();
                        if (win.mActivityRecord != null && win.mActivityRecord.findMainWindow() == win) {
                            mWmService.mTaskSnapshotController.onAppDied(win.mActivityRecord);
                        }
                        win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
                        win.removeIfPossible();
                    } else if (mHasSurface) {
                        Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
                        WindowState.this.removeIfPossible();
@@ -3095,32 +3035,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        }
    }

    /**
     * Returns true if this window is visible and belongs to a dead app and shouldn't be removed,
     * because we want to preserve its location on screen to be re-activated later when the user
     * interacts with it.
     */
    private boolean shouldKeepVisibleDeadAppWindow() {
        if (!isVisible() || mActivityRecord == null || !mActivityRecord.isClientVisible()) {
            // Not a visible app window or the app isn't dead.
            return false;
        }

        if (mAttrs.token != mClient.asBinder()) {
            // The window was add by a client using another client's app token. We don't want to
            // keep the dead window around for this case since this is meant for 'real' apps.
            return false;
        }

        if (mAttrs.type == TYPE_APPLICATION_STARTING) {
            // We don't keep starting windows since they were added by the window manager before
            // the app even launched.
            return false;
        }

        return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
    }

    /** Returns {@code true} if this window desires key events. */
    boolean canReceiveKeys() {
        return canReceiveKeys(false /* fromUserTouch */);
@@ -3967,7 +3881,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    @Override
    public void notifyInsetsControlChanged() {
        ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsControlChanged for %s ", this);
        if (mAppDied || mRemoved) {
        if (mRemoved) {
            return;
        }
        final InsetsStateController stateController =
@@ -4273,7 +4187,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
            pw.println(prefix + "mToken=" + mToken);
            if (mActivityRecord != null) {
                pw.println(prefix + "mActivityRecord=" + mActivityRecord);
                pw.print(prefix + "mAppDied=" + mAppDied);
                pw.print(prefix + "drawnStateEvaluated=" + getDrawnStateEvaluated());
                pw.println(prefix + "mightAffectAllDrawn=" + mightAffectAllDrawn());
            }
@@ -5402,10 +5315,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    }

    private void applyDims() {
        if (!mAnimatingExit && mAppDied) {
            mIsDimming = true;
            getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
        if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
                   && isVisibleNow() && !mHidden) {
            // Only show the Dimmer when the following is satisfied:
            // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested