From 07cb272a507047eb5f2eca90590a3f65cb8d863d Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Mon, 16 Mar 2020 23:19:24 +0800 Subject: Surface should not be created for WindowContext initially. Client may create a WindowContext, but without adding a window using the corresponding WindowToken, initially creating a surface for the token is very wasteful. To avoid this, we should only create surfaces when the client is needed. Bug: 150813033 Test: atest WindowTokenTests Test: No system crash when running FocusHandlingTest. Change-Id: I0def6a436ad9d60948bfb029b3a7b6b44466d068 --- .../com/android/server/wm/WindowContainer.java | 12 +++++++---- .../java/com/android/server/wm/WindowToken.java | 15 ++++++++++++++ .../com/android/server/wm/WindowTokenTests.java | 24 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a1902bbd6764..f2b796fd5f26 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -378,10 +378,7 @@ class WindowContainer extends ConfigurationContainer< if (mSurfaceControl == null) { // If we don't yet have a surface, but we now have a parent, we should // build a surface. - setSurfaceControl(makeSurface().build()); - getPendingTransaction().show(mSurfaceControl); - onSurfaceShown(getPendingTransaction()); - updateSurfacePosition(); + createSurfaceControl(false /*force*/); } else { // If we have a surface but a new parent, we just need to perform a reparent. Go through // surface animator such that hierarchy is preserved when animating, i.e. @@ -399,6 +396,13 @@ class WindowContainer extends ConfigurationContainer< scheduleAnimation(); } + void createSurfaceControl(boolean force) { + setSurfaceControl(makeSurface().build()); + getPendingTransaction().show(mSurfaceControl); + onSurfaceShown(getPendingTransaction()); + updateSurfacePosition(); + } + /** * Called when the surface is shown for the first time. */ diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index b7c6af2f7a0d..203b968cebd9 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -100,6 +100,9 @@ class WindowToken extends WindowContainer { private Configuration mLastReportedConfig; private int mLastReportedDisplay = INVALID_DISPLAY; + /** + * When set to {@code true}, this window token is created from {@link android.app.WindowContext} + */ @VisibleForTesting final boolean mFromClientToken; @@ -278,6 +281,11 @@ class WindowToken extends WindowContainer { // Child windows are added to their parent windows. return; } + // This token is created from WindowContext and the client requests to addView now, create a + // surface for this token. + if (mSurfaceControl == null) { + createSurfaceControl(true /* force */); + } if (!mChildren.contains(win)) { ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this); addChild(win, mWindowComparator); @@ -286,6 +294,13 @@ class WindowToken extends WindowContainer { } } + @Override + void createSurfaceControl(boolean force) { + if (!mFromClientToken || force) { + super.createSurfaceControl(force); + } + } + /** Returns true if the token windows list is empty. */ boolean isEmpty() { return mChildren.isEmpty(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index 38f643daec27..7a347cb050be 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static org.junit.Assert.assertEquals; @@ -155,4 +156,27 @@ public class WindowTokenTests extends WindowTestsBase { assertTrue(token.mRoundedCornerOverlay); assertTrue(token.mFromClientToken); } + + /** + * Test that {@link android.view.SurfaceControl} should not be created for the + * {@link WindowToken} which was created for {@link android.app.WindowContext} initially, the + * surface should be create after addWindow for this token. + */ + @Test + public void testSurfaceCreatedForWindowToken() { + final WindowToken fromClientToken = new WindowToken(mDisplayContent.mWmService, + mock(IBinder.class), TYPE_APPLICATION_OVERLAY, true /* persistOnEmpty */, + mDisplayContent, true /* ownerCanManageAppTokens */, + true /* roundedCornerOverlay */, true /* fromClientToken */); + assertNull(fromClientToken.mSurfaceControl); + + createWindow(null, TYPE_APPLICATION_OVERLAY, fromClientToken, "window"); + assertNotNull(fromClientToken.mSurfaceControl); + + final WindowToken nonClientToken = new WindowToken(mDisplayContent.mWmService, + mock(IBinder.class), TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent, + true /* ownerCanManageAppTokens */, true /* roundedCornerOverlay */, + false /* fromClientToken */); + assertNotNull(nonClientToken.mSurfaceControl); + } } -- cgit v1.2.3-59-g8ed1b