From aee6d8ae83c182814fbd34e829625007af39fd31 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 23 Feb 2023 19:59:45 +0800 Subject: [PATCH] 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 --- .../java/android/app/WindowConfiguration.java | 9 -- .../server/wm/ActivityClientController.java | 5 - .../com/android/server/wm/ActivityRecord.java | 30 +----- .../wm/EnsureActivitiesVisibleHelper.java | 12 +-- .../com/android/server/wm/WindowState.java | 102 ++---------------- 5 files changed, 9 insertions(+), 149 deletions(-) diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 39d77c49eea95..5b955031a098c 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -874,15 +874,6 @@ public class WindowConfiguration implements Parcelable, Comparable 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); diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java index dde89e9bca2e3..9cc311dc6c8e6 100644 --- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -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) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 87e87b95fdfd5..0b86a9fddf967 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -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 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 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 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 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 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 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 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 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); - } + mInputChannel.copyTo(outInputChannel); } /** @@ -2749,10 +2694,6 @@ class WindowState extends WindowContainer 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 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 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 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 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 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