Window Manager spring cleaning

Our performance for wmLayout + prepareSurfaces regressed over
time, because we added a lot of functionality, but didn't have
fine grained perf tests enough to catch it.

This CL tries to attempt to undo that damage by optimizing various
things that regressed or didn't regress, but could still be
optimized.

Test: Presubmit tests + capture trace during wmRelayout
Bug: 129389526
Change-Id: I352a3213f074377bd10721d16535c1e27fb2e746
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index c1b9bba..bc28d7e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1976,7 +1976,7 @@
         final boolean surfaceReady = w.isDrawnLw()  // Regular case
                 || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
                 || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
-        final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady;
+        final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
         if (needsLetterbox) {
             if (mLetterbox == null) {
                 mLetterbox = new Letterbox(() -> makeChildSurface(null));
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 9bc8462..3bbe28d 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -173,8 +173,9 @@
         }
         final boolean wasVis = mWin.isVisibleLw();
         final boolean wasAnim = mWin.isAnimatingLw();
-        final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnimation())
-                : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnimation());
+        final boolean skipAnim = skipAnimation();
+        final boolean change = show ? mWin.showLw(!mNoAnimationOnNextShow && !skipAnim)
+                : mWin.hideLw(!mNoAnimationOnNextShow && !skipAnim);
         mNoAnimationOnNextShow = false;
         final int state = computeStateLw(wasVis, wasAnim, mWin, change);
         final boolean stateChanged = updateStateLw(state);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0c34e25..4e444a9 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -28,6 +28,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
@@ -3094,7 +3095,7 @@
 
     /** Updates the layer assignment of windows on this display. */
     void assignWindowLayers(boolean setLayoutNeeded) {
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers");
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "assignWindowLayers");
         assignChildLayers(getPendingTransaction());
         if (setLayoutNeeded) {
             setLayoutNeeded();
@@ -3105,7 +3106,7 @@
         // prepareSurfaces. This allows us to synchronize Z-ordering changes with
         // the hiding and showing of surfaces.
         scheduleAnimation();
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     // TODO: This should probably be called any time a visual change is made to the hierarchy like
@@ -3659,9 +3660,14 @@
             // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
             pendingLayoutChanges = 0;
 
-            mDisplayPolicy.beginPostLayoutPolicyLw();
-            forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
-            pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
+            try {
+                mDisplayPolicy.beginPostLayoutPolicyLw();
+                forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+                pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
+            } finally {
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            }
             if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
                     "after finishPostLayoutPolicyLw", pendingLayoutChanges);
                 mInsetsStateController.onPostLayout();
@@ -3670,7 +3676,13 @@
         mTmpApplySurfaceChangesTransactionState.reset();
 
         mTmpRecoveringMemory = recoveringMemory;
-        forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
+
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
+        try {
+            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
         prepareSurfaces();
 
         mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
@@ -3720,11 +3732,6 @@
         out.set(left, top, left + width, top + height);
     }
 
-    @Override
-    public void getBounds(Rect out) {
-        calculateBounds(mDisplayInfo, out);
-    }
-
     private void getBounds(Rect out, int orientation) {
         getBounds(out);
 
@@ -3746,6 +3753,15 @@
     }
 
     void performLayout(boolean initial, boolean updateInputWindows) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
+        try {
+            performLayoutNoTrace(initial, updateInputWindows);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
         if (!isLayoutNeeded()) {
             return;
         }
@@ -3755,13 +3771,14 @@
         final int dh = mDisplayInfo.logicalHeight;
         if (DEBUG_LAYOUT) {
             Slog.v(TAG, "-------------------------------------");
-            Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
+            Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw
+                    + " dh=" + dh);
         }
 
         mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
-        // TODO: Not sure if we really need to set the rotation here since we are updating from the
-        // display info above...
+        // TODO: Not sure if we really need to set the rotation here since we are updating from
+        // the display info above...
         mDisplayFrames.mRotation = mRotation;
         mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
 
@@ -4801,20 +4818,25 @@
 
     @Override
     void prepareSurfaces() {
-        final ScreenRotationAnimation screenRotationAnimation =
-                mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
-        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-            screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
-            mPendingTransaction.setMatrix(mWindowingLayer,
-                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
-                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            mPendingTransaction.setPosition(mWindowingLayer,
-                    mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
-            mPendingTransaction.setAlpha(mWindowingLayer,
-                    screenRotationAnimation.getEnterTransformation().getAlpha());
-        }
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
+        try {
+            final ScreenRotationAnimation screenRotationAnimation =
+                    mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+                screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
+                mPendingTransaction.setMatrix(mWindowingLayer,
+                        mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+                        mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+                mPendingTransaction.setPosition(mWindowingLayer,
+                        mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
+                mPendingTransaction.setAlpha(mWindowingLayer,
+                        screenRotationAnimation.getEnterTransformation().getAlpha());
+            }
 
-        super.prepareSurfaces();
+            super.prepareSurfaces();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
     }
 
     void assignStackOrdering() {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5d38a69..16ded98 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -103,13 +103,16 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.localLOGV;
 
+import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Px;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
@@ -255,6 +258,9 @@
     private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
     private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
 
+    /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
+    @Px private int mWindowOutsetBottom;
+
     private final StatusBarController mStatusBarController = new StatusBarController();
 
     private final BarController mNavigationBarController = new BarController("NavigationBar",
@@ -731,6 +737,11 @@
         return true;
     }
 
+    private boolean hasStatusBarServicePermission(int pid, int uid) {
+        return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
     /**
      * Sanitize the layout parameters coming from a client.  Allows the policy
      * to do things like ensure that windows of a specific type can't take
@@ -740,7 +751,7 @@
      * are modified in-place.
      */
     public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
-            boolean hasStatusBarServicePermission) {
+            int callingPid, int callingUid) {
 
         final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
         if (mScreenDecorWindows.contains(win)) {
@@ -748,7 +759,7 @@
                 // No longer has the flag set, so remove from the set.
                 mScreenDecorWindows.remove(win);
             }
-        } else if (isScreenDecor && hasStatusBarServicePermission) {
+        } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
             mScreenDecorWindows.add(win);
         }
 
@@ -1159,7 +1170,7 @@
 
         final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
         if (useOutsets) {
-            int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+            int outset = mWindowOutsetBottom;
             if (outset > 0) {
                 if (displayRotation == Surface.ROTATION_0) {
                     outOutsets.bottom += outset;
@@ -1479,12 +1490,13 @@
         }
         // apply any navigation bar insets
         sTmpRect.setEmpty();
-        mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
+        final WindowFrames windowFrames = mStatusBar.getWindowFrames();
+        windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
                 displayFrames.mUnrestricted /* displayFrame */,
                 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
                 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
                 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
-        mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+        windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
 
         // Let the status bar determine its size.
         mStatusBar.computeFrameLw();
@@ -1524,8 +1536,9 @@
                     "dock=%s content=%s cur=%s", dockFrame.toString(),
                     displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
 
-            if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
-                    && !mStatusBarController.wasRecentlyTranslucent()) {
+            if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
+                    && !mStatusBar.isAnimatingLw()) {
+
                 // If the opaque status bar is currently requested to be visible, and not in the
                 // process of animating on or off, then we can tell the app that it is covered by
                 // it.
@@ -2180,7 +2193,7 @@
             final Rect osf = windowFrames.mOutsetFrame;
             osf.set(cf.left, cf.top, cf.right, cf.bottom);
             windowFrames.setHasOutsets(true);
-            int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+            int outset = mWindowOutsetBottom;
             if (outset > 0) {
                 int rotation = displayFrames.mRotation;
                 if (rotation == Surface.ROTATION_0) {
@@ -2599,6 +2612,7 @@
         // EXPERIMENT END
 
         updateConfigurationAndScreenSizeDependentBehaviors();
+        mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
     }
 
     void updateConfigurationAndScreenSizeDependentBehaviors() {
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index ab95e4b..8dae016 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.IBinder;
@@ -43,6 +44,9 @@
 
     final SurfaceControl mInputSurface;
     Rect mTmpClipRect = new Rect();
+    private final Rect mTmpRect = new Rect();
+    private final Point mOldPosition = new Point();
+    private final Rect mOldWindowCrop = new Rect();
 
     InputConsumerImpl(WindowManagerService service, IBinder token, String name,
             InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) {
@@ -112,16 +116,22 @@
     }
 
     void layout(SurfaceControl.Transaction t, int dw, int dh) {
-        t.setPosition(mInputSurface, 0, 0);
-
-        mTmpClipRect.set(0, 0, dw, dh);
-        t.setWindowCrop(mInputSurface, mTmpClipRect);
+        mTmpRect.set(0, 0, dw, dh);
+        layout(t, mTmpRect);
     }
 
     void layout(SurfaceControl.Transaction t, Rect r) {
-        t.setPosition(mInputSurface, r.left, r.top);
         mTmpClipRect.set(0, 0, r.width(), r.height());
+
+        if (mOldPosition.equals(r.left, r.top) && mOldWindowCrop.equals(mTmpClipRect)) {
+            return;
+        }
+
+        t.setPosition(mInputSurface, r.left, r.top);
         t.setWindowCrop(mInputSurface, mTmpClipRect);
+
+        mOldPosition.set(r.left, r.top);
+        mOldWindowCrop.set(mTmpClipRect);
     }
 
     void hide(SurfaceControl.Transaction t) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 5669451..835b9b1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -190,8 +191,13 @@
     }
 
     void layoutInputConsumers(int dw, int dh) {
-        for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
-            mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer");
+            for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
+                mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+            }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
 
@@ -401,7 +407,7 @@
         final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, null, mDisplayId);
 
         private void updateInputWindows(boolean inDrag) {
-            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
 
             navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION);
             pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
@@ -429,7 +435,7 @@
 
             mDisplayContent.scheduleAnimation();
 
-            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ed5f665..1ca31f1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
@@ -65,6 +66,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -551,18 +553,26 @@
         return leakedSurface || killedApps;
     }
 
+    void performSurfacePlacement(boolean recoveringMemory) {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
+        try {
+            performSurfacePlacementNoTrace(recoveringMemory);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
     // "Something has changed!  Let's make it correct now."
     // TODO: Super crazy long method that should be broken down...
-    void performSurfacePlacement(boolean recoveringMemory) {
+    void performSurfacePlacementNoTrace(boolean recoveringMemory) {
         if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
                 + Debug.getCallers(3));
 
         int i;
-        boolean updateInputWindowsNeeded = false;
 
         if (mWmService.mFocusMayChange) {
             mWmService.mFocusMayChange = false;
-            updateInputWindowsNeeded = mWmService.updateFocusedWindowLocked(
+            mWmService.updateFocusedWindowLocked(
                     UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
         }
 
@@ -586,6 +596,7 @@
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
         mWmService.openSurfaceTransaction();
         try {
             applySurfaceChangesTransaction(recoveringMemory);
@@ -593,6 +604,7 @@
             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
             mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
         }
@@ -621,10 +633,8 @@
 
         if (mWmService.mFocusMayChange) {
             mWmService.mFocusMayChange = false;
-            if (mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                    false /*updateInputWindows*/)) {
-                updateInputWindowsNeeded = true;
-            }
+            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/);
         }
 
         if (isLayoutNeeded()) {
@@ -679,12 +689,6 @@
             }
         }
 
-        // Finally update all input windows now that the window changes have stabilized.
-        forAllDisplays(dc -> {
-            dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
-            dc.updateSystemGestureExclusion();
-        });
-
         mWmService.setHoldScreenLocked(mHoldScreen);
         if (!mWmService.mDisplayFrozen) {
             final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
@@ -710,7 +714,7 @@
 
         if (mWmService.mWaitingForDrawnCallback != null
                 || (mOrientationChangeComplete && !isLayoutNeeded()
-                        && !mUpdateRotation)) {
+                && !mUpdateRotation)) {
             mWmService.checkDrawnWindowsLocked();
         }
 
@@ -742,12 +746,11 @@
             mChildren.get(displayNdx).checkCompleteDeferredRemoval();
         }
 
-        if (updateInputWindowsNeeded) {
-            forAllDisplays(dc -> {
-                dc.getInputMonitor().updateInputWindowsLw(false /*force*/);
-            });
-        }
-        forAllDisplays(DisplayContent::updateTouchExcludeRegion);
+        forAllDisplays(dc -> {
+            dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
+            dc.updateSystemGestureExclusion();
+            dc.updateTouchExcludeRegion();
+        });
 
         // Check to see if we are now in a state where the screen should
         // be enabled, because the window obscured flags have changed.
@@ -776,7 +779,7 @@
                 }
             }
 
-            if (!curDisplay.isAppAnimating() && curDisplay.mAppTransition.isRunning()) {
+            if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppAnimating()) {
                 // We have finished the animation of an app transition. To do this, we have
                 // delayed a lot of operations like showing and hiding apps, moving apps in
                 // Z-order, etc.
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 20a874b..9fe4760 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -244,8 +244,6 @@
     void calculateOutsets() {
         if (mHasOutsets) {
             InsetUtils.insetsBetweenFrames(mOutsetFrame, mContentFrame, mOutsets);
-        } else {
-            mOutsets.setEmpty();
         }
     }
 
@@ -373,7 +371,13 @@
      * Sets whether the frame has outsets.
      */
     public void setHasOutsets(boolean hasOutsets) {
+        if (mHasOutsets == hasOutsets) {
+            return;
+        }
         mHasOutsets = hasOutsets;
+        if (!hasOutsets) {
+            mOutsets.setEmpty();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index d3f3711..9d80425 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -414,7 +414,7 @@
         OnHardKeyboardStatusChangeListener listener);
 
     /** Returns true if a stack in the windowing mode is currently visible. */
-    public abstract boolean isStackVisible(int windowingMode);
+    public abstract boolean isStackVisibleLw(int windowingMode);
 
     /**
      * Requests the window manager to resend the windows for accessibility.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9e421c1..20d02ee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1392,11 +1392,9 @@
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
 
-            final boolean hasStatusBarServicePermission =
-                    mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
-                            == PackageManager.PERMISSION_GRANTED;
             final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
-            displayPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
+            displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
+                    Binder.getCallingUid());
             win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
             res = displayPolicy.prepareAddWindowLw(win, attrs);
@@ -1932,6 +1930,11 @@
         }
     }
 
+    private boolean hasStatusBarPermission(int pid, int uid) {
+        return mContext.checkPermission(permission.STATUS_BAR, pid, uid)
+                        == PackageManager.PERMISSION_GRANTED;
+    }
+
     public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility, int flags,
             long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
@@ -1940,13 +1943,8 @@
             SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         int result = 0;
         boolean configChanged;
-        final boolean hasStatusBarPermission =
-                mContext.checkCallingOrSelfPermission(permission.STATUS_BAR)
-                        == PackageManager.PERMISSION_GRANTED;
-        final boolean hasStatusBarServicePermission =
-                mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
-                        == PackageManager.PERMISSION_GRANTED;
-
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
         long origId = Binder.clearCallingIdentity();
         final int displayId;
         synchronized (mGlobalLock) {
@@ -1973,13 +1971,13 @@
             int attrChanges = 0;
             int flagChanges = 0;
             if (attrs != null) {
-                displayPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
+                displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
                 // if they don't have the permission, mask out the status bar bits
                 if (seq == win.mSeq) {
                     int systemUiVisibility = attrs.systemUiVisibility
                             | attrs.subtreeSystemUiVisibility;
                     if ((systemUiVisibility & DISABLE_MASK) != 0) {
-                        if (!hasStatusBarPermission) {
+                        if (!hasStatusBarPermission(pid, uid)) {
                             systemUiVisibility &= ~DISABLE_MASK;
                         }
                     }
@@ -2050,7 +2048,6 @@
                             && viewVisibility == View.VISIBLE;
             boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
                     || becameVisible;
-            final boolean isDefaultDisplay = win.isDefaultDisplay();
             boolean focusMayChange = win.mViewVisibility != viewVisibility
                     || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
                     || (!win.mRelayoutCalled);
@@ -7215,11 +7212,9 @@
         }
 
         @Override
-        public boolean isStackVisible(int windowingMode) {
-            synchronized (mGlobalLock) {
-                final DisplayContent dc = getDefaultDisplayContentLocked();
-                return dc.isStackVisible(windowingMode);
-            }
+        public boolean isStackVisibleLw(int windowingMode) {
+            final DisplayContent dc = getDefaultDisplayContentLocked();
+            return dc.isStackVisible(windowingMode);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b5f7a85..e7ba8b4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2298,11 +2298,6 @@
     void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         // We need to turn on screen regardless of visibility.
         boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
-        boolean allowTheaterMode =
-                mWmService.mAllowTheaterModeWakeFromLayout || Settings.Global.getInt(
-                        mWmService.mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0)
-                        == 0;
-        boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
 
         // The screen will turn on if the following conditions are met
         // 1. The window has the flag FLAG_TURN_SCREEN_ON
@@ -2316,6 +2311,11 @@
         // be occurring while turning off the screen. This would lead to the screen incorrectly
         // turning back on.
         if (hasTurnScreenOnFlag) {
+            boolean allowTheaterMode = mWmService.mAllowTheaterModeWakeFromLayout
+                    || Settings.Global.getInt(mWmService.mContext.getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 0) == 0;
+            boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+
             if (allowTheaterMode && canTurnScreenOn && !mPowerManagerWrapper.isInteractive()) {
                 if (DEBUG_VISIBILITY || DEBUG_POWER) {
                     Slog.v(TAG, "Relayout window turning screen on: " + this);
@@ -3511,7 +3511,10 @@
     }
 
     void transformClipRectFromScreenToSurfaceSpace(Rect clipRect) {
-         if (mHScale >= 0) {
+        if (mHScale == 1 && mVScale == 1) {
+            return;
+        }
+        if (mHScale >= 0) {
             clipRect.left = (int) (clipRect.left / mHScale);
             clipRect.right = (int) Math.ceil(clipRect.right / mHScale);
         }
@@ -4367,7 +4370,7 @@
         // scale function because we want to round things to make the crop
         // always round to a larger rect to ensure we don't crop too
         // much and hide part of the window that should be seen.
-        if (inSizeCompatMode() && mInvGlobalScale != 1.0f) {
+        if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
             final float scale = mInvGlobalScale;
             systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
             systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
@@ -4422,7 +4425,12 @@
 
         mWinAnimator.mEnteringAnimation = true;
 
-        prepareWindowToDisplayDuringRelayout(wasVisible);
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareToDisplay");
+        try {
+            prepareWindowToDisplayDuringRelayout(wasVisible);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
 
         if ((attrChanges & FORMAT_CHANGED) != 0) {
             // If the format can't be changed in place, preserve the old surface until the app draws
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index acb9823..bef0f81 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -56,6 +56,7 @@
     private float mSurfaceY = 0;
     private int mSurfaceW = 0;
     private int mSurfaceH = 0;
+    private Rect mSurfaceCrop = new Rect(0, 0, -1, -1);
 
     // Initialize to the identity matrix.
     private float mLastDsdx = 1;
@@ -171,26 +172,15 @@
         }
     }
 
-    void disconnectInTransaction() {
-        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-            Slog.i(TAG, "Disconnecting client: " + this);
-        }
-
-        try {
-            if (mSurfaceControl != null) {
-                mSurfaceControl.disconnect();
-            }
-        } catch (RuntimeException e) {
-            Slog.w(TAG, "Error disconnecting surface in: " + this, e);
-        }
-    }
-
     void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
         if (SHOW_TRANSACTIONS) logSurface(
                 "CROP " + clipRect.toShortString(), null);
         try {
             if (clipRect.width() > 0 && clipRect.height() > 0) {
-                mSurfaceControl.setWindowCrop(clipRect);
+                if (!clipRect.equals(mSurfaceCrop)) {
+                    mSurfaceControl.setWindowCrop(clipRect);
+                    mSurfaceCrop.set(clipRect);
+                }
                 mHiddenForCrop = false;
                 updateVisibility();
             } else {
@@ -212,7 +202,11 @@
                 "CLEAR CROP", null);
         try {
             Rect clipRect = new Rect(0, 0, -1, -1);
+            if (mSurfaceCrop.equals(clipRect)) {
+                return;
+            }
             mSurfaceControl.setWindowCrop(clipRect);
+            mSurfaceCrop.set(clipRect);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error setting clearing crop of " + this, e);
             if (!recoveringMemory) {
@@ -221,12 +215,6 @@
         }
     }
 
-    void setLayerStackInTransaction(int layerStack) {
-        if (mSurfaceControl != null) {
-            mSurfaceControl.setLayerStack(layerStack);
-        }
-    }
-
     void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
         setPosition(null, left, top, recoveringMemory);
     }
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
index 98bad93..3be5d31 100644
--- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -81,11 +81,24 @@
      * @hide
      */
     public WmDisplayCutout calculateRelativeTo(Rect frame) {
+        if (mFrameSize == null) {
+            return this;
+        }
+        final int insetRight = mFrameSize.getWidth() - frame.right;
+        final int insetBottom = mFrameSize.getHeight() - frame.bottom;
+        if (frame.left == 0 && frame.top == 0 && insetRight == 0 && insetBottom == 0) {
+            return this;
+        }
+        if (frame.left >= mInner.getSafeInsetLeft()
+                && frame.top >= mInner.getSafeInsetTop()
+                && insetRight >= mInner.getSafeInsetRight()
+                && insetBottom >= mInner.getSafeInsetBottom()) {
+            return NO_CUTOUT;
+        }
         if (mInner.isEmpty()) {
             return this;
         }
-        return inset(frame.left, frame.top,
-                mFrameSize.getWidth() - frame.right, mFrameSize.getHeight() - frame.bottom);
+        return inset(frame.left, frame.top, insetRight, insetBottom);
     }
 
     /**