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

Commit f858b578 authored by Bryce Lee's avatar Bryce Lee
Browse files

Always send configuration to client from resize and relayout.

Previously, the server side would omit reporting new configurations
during resize and relayout if the current configuration matched the
last reported. However, if the last reported came through a resize,
the client side handling would be enqueued as a Handler message. This
leads to the possibility of the client getting a new window frame but
not a new configuration where this is synchronously handled, such as
ViewRootImpl::performTraversals.

To address this issue, we now always send the current configuration
from the server to the client. The client then identifies changes
against its own record of last reported configuration and updates as
appropriate.

This changelist also adds a call to force window relayout during
updateConfiguration, as it's possible this is called after
performTraversals is called or resize is handled, leading to a stale
window frame.

Bug: 24671393
Test: go/wm-smoke
Test: Open Camera while rotating phone to landscape. Added
      temporary logs to detect inconsistencies between measurements
      and reported rotation on draw.

Change-Id: I0d5143dfe80400f6a43ce710750f9fc9d4b93f74
parent 4bf79089
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -161,6 +161,21 @@ public class MergedConfiguration implements Parcelable {
        return "{mGlobalConfig=" + mGlobalConfig + " mOverrideConfig=" + mOverrideConfig + "}";
    }

    @Override
    public int hashCode() {
        return mMergedConfig.hashCode();
    }

    @Override
    public boolean equals(Object that) {
        if (!(that instanceof MergedConfiguration)) {
            return false;
        }

        if (that == this) return true;
        return mMergedConfig.equals(((MergedConfiguration) that).mMergedConfig);
    }

    public void dump(PrintWriter pw, String prefix) {
        pw.println(prefix + "mGlobalConfig=" + mGlobalConfig);
        pw.println(prefix + "mOverrideConfig=" + mOverrideConfig);
+17 −8
Original line number Diff line number Diff line
@@ -1904,14 +1904,16 @@ public final class ViewRootImpl implements ViewParent,
                        + " outsets=" + mPendingOutsets.toShortString()
                        + " surface=" + mSurface);

                final Configuration pendingMergedConfig =
                        mPendingMergedConfiguration.getMergedConfiguration();
                if (pendingMergedConfig.seq != 0) {
                // If the pending {@link MergedConfiguration} handed back from
                // {@link #relayoutWindow} does not match the one last reported,
                // WindowManagerService has reported back a frame from a configuration not yet
                // handled by the client. In this case, we need to accept the configuration so we
                // do not lay out and draw with the wrong configuration.
                if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
                    if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
                            + pendingMergedConfig);
                            + mPendingMergedConfiguration.getMergedConfiguration());
                    performConfigurationChange(mPendingMergedConfiguration, !mFirst,
                            INVALID_DISPLAY /* same display */);
                    pendingMergedConfig.seq = 0;
                    updatedConfiguration = true;
                }

@@ -3596,6 +3598,13 @@ public final class ViewRootImpl implements ViewParent,
                mView.setLayoutDirection(currentLayoutDirection);
            }
            mView.dispatchConfigurationChanged(config);

            // We could have gotten this {@link Configuration} update after we called
            // {@link #performTraversals} with an older {@link Configuration}. As a result, our
            // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
            // catches this.
            mForceNextWindowRelayout = true;
            requestLayout();
        }
    }

@@ -3757,10 +3766,10 @@ public final class ViewRootImpl implements ViewParent,
                    SomeArgs args = (SomeArgs) msg.obj;

                    final int displayId = args.argi3;
                    final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
                    MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
                    final boolean displayChanged = mDisplay.getDisplayId() != displayId;

                    if (mergedConfiguration != null) {
                    if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
                        // If configuration changed - notify about that and, maybe, about move to
                        // display.
                        performConfigurationChange(mergedConfiguration, false /* force */,
@@ -6094,7 +6103,7 @@ public final class ViewRootImpl implements ViewParent,
        if (params != null) {
            if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
        }
        mPendingMergedConfiguration.getMergedConfiguration().seq = 0;

        //Log.d(mTag, ">>>>>> CALLING relayout");
        if (params != null && mOrigWindowType != params.type) {
            // For compatibility with old apps, don't crash here.
+10 −5
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.os.UserHandle.USER_NULL;
@@ -50,7 +49,6 @@ import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHA
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -233,7 +231,6 @@ import com.android.server.DisplayThread;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.ThreadPriorityBooster;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
@@ -2020,8 +2017,7 @@ public class WindowManagerService extends IWindowManager.Stub
                    win.setDisplayLayoutNeeded();
                    mWindowPlacerLocked.performSurfacePlacement(true);
                }
                result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
                        oldVisibility);
                result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);

                try {
                    result = createSurfaceControl(outSurface, result, win, winAnimator);
@@ -2159,6 +2155,15 @@ public class WindowManagerService extends IWindowManager.Stub
            if (!win.isGoneForLayoutLw()) {
                win.mResizedWhileGone = false;
            }

            // We must always send the latest {@link MergedConfiguration}, regardless of whether we
            // have already reported it. The client might not have processed the previous value yet
            // and needs process it before handling the corresponding window frame. the variable
            // {@code mergedConfiguration} is an out parameter that will be passed back to the
            // client over IPC and checked there.
            win.getMergedConfiguration(mergedConfiguration);
            win.setReportedConfiguration(mergedConfiguration);

            outFrame.set(win.mCompatFrame);
            outOverscanInsets.set(win.mOverscanInsets);
            outContentInsets.set(win.mContentInsets);
+18 −22
Original line number Diff line number Diff line
@@ -2207,8 +2207,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        }
    }

    void prepareWindowToDisplayDuringRelayout(MergedConfiguration mergedConfiguration,
            boolean wasVisible) {
    void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
        // We need to turn on screen regardless of visibility.
        if ((mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0) {
            if (DEBUG_VISIBILITY) Slog.v(TAG, "Relayout window turning screen on: " + this);
@@ -2230,16 +2229,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        if (isDrawnLw() && mService.okToDisplay()) {
            mWinAnimator.applyEnterAnimationLocked();
        }
    }

        if (isConfigChanged()) {
    void getMergedConfiguration(MergedConfiguration outConfiguration) {
        final Configuration globalConfig = mService.mRoot.getConfiguration();
        final Configuration overrideConfig = getMergedOverrideConfiguration();
            mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
            if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
                    + " visible with new global config: " + globalConfig
                    + " merged override config: " + overrideConfig);
            mLastReportedConfiguration.setTo(getConfiguration());
        outConfiguration.setConfiguration(globalConfig, overrideConfig);
    }

    void setReportedConfiguration(MergedConfiguration config) {
        mLastReportedConfiguration.setTo(config.getMergedConfiguration());
    }

    void adjustStartingWindowFlags() {
@@ -3005,14 +3004,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        try {
            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                    + ": " + mCompatFrame);
            final MergedConfiguration mergedConfiguration;
            if (isConfigChanged()) {
                mergedConfiguration = new MergedConfiguration(mService.mRoot.getConfiguration(),
            final MergedConfiguration mergedConfiguration =
                    new MergedConfiguration(mService.mRoot.getConfiguration(),
                    getMergedOverrideConfiguration());
                mLastReportedConfiguration.setTo(mergedConfiguration.getMergedConfiguration());
            } else {
                mergedConfiguration = null;
            }

            setReportedConfiguration(mergedConfiguration);

            if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
                Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");

@@ -4342,8 +4339,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets);
    }

    int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges,
            int oldVisibility) {
    int relayoutVisibleWindow(int result, int attrChanges, int oldVisibility) {
        final boolean wasVisible = isVisibleLw();

        result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
@@ -4366,7 +4362,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

        mWinAnimator.mEnteringAnimation = true;

        prepareWindowToDisplayDuringRelayout(mergedConfiguration, wasVisible);
        prepareWindowToDisplayDuringRelayout(wasVisible);

        if ((attrChanges & FORMAT_CHANGED) != 0) {
            // If the format can't be changed in place, preserve the old surface until the app draws
+1 −2
Original line number Diff line number Diff line
@@ -218,8 +218,7 @@ public class WindowStateTests extends WindowTestsBase {
        root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
        root.mTurnOnScreen = false;

        root.prepareWindowToDisplayDuringRelayout(new MergedConfiguration(),
                wasVisible /*wasVisible*/);
        root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
        assertTrue(root.mTurnOnScreen);
    }
}