Android P WMS -- relayoutWindow

Android P WMS (1) -- Introduction to WMS

Android P WMS(2) -- wms initialization

Android O WMS(3) -- addwindow

Android P WMS(4) -- removewindow

Android P WMS(5) -- relayoutWindow

Android P WMS(6) -- windowanimator

Android P WMS(7) --wms Problem Types and Deug Skills

Android P WMS (8) -- Introduction to View SYstem

Android P WMS(9) --Surface

1.1 Parametric Meaning (Link Understanding android Volume 3 in-depth):

Session: Session instance of the process in which the caller is located.
client:: To relayout the window.
seq:- A serial number related to the visibility of the status bar/navigation bar
 Attrs: The new layout property of the window. The main purpose of relayoutWindow() is to provide a layout based on attrs 
Relayout a window with parameters. The client can change the attrs defined by the relayoutWindow() function 
Almost all layout attributes. However, the window type cannot be changed.
RequedWidth and RequedHeight: The window size required by the client. In the process of re-layout, 
WMS will do its best to lay out the size of the window as required by the client.
viewVisiblility: Visibility of windows.
flags: Define some layout behavior.
_outFrame: An instance of Rect type returned to the caller by the relayoutWindow() function. It saves 
Location and size of window U after being re-laid out
 UoutContentlnsets and outVisiblelnsets: These two parameters represent the rectangular boundaries of the content that a window can draw. 
The pixel difference from the visible rectangular boundary to the mFrame in four directions.
Out Configuration: WMS calculates Configuration for this window after the redesign.
outSurface: Used to receive Surface allocated by WMS for this window. After the first relayout of the window is completed 
It allows you to draw in a window.

1.2 relayoutWindow code flow

Performance Traversals calls relayout Windows; it requests WMS to calculate the relevant window size, create Surface and so on; this chapter tries to analyze this function, on the current understanding of performance Traversals mainly focuses on client-side processing of DecorView and its sub-Views, such as measure,layout,draw, and so on; and binder call s to system; _ WMS of server focuses on the processing of system side-to-window

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,
        Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
        DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
        Surface outSurface) {
    int result = 0;
    boolean configChanged;
    
    //Permission-related checks
    final boolean hasStatusBarPermission =
            mContext.checkCallingOrSelfPermission(permission.STATUS_BAR)
                    == PackageManager.PERMISSION_GRANTED;
    final boolean hasStatusBarServicePermission =
            mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
                    == PackageManager.PERMISSION_GRANTED;

    long origId = Binder.clearCallingIdentity();
    final int displayId;
    synchronized(mWindowMap) {
        WindowState win = windowForClientLocked(session, client, false);  //Get the re-layout window object
        if (win == null) {
            return 0;
        }
        displayId = win.getDisplayId();

        WindowStateAnimator winAnimator = win.mWinAnimator;
        if (viewVisibility != View.GONE) {
            win.setRequestedSize(requestedWidth, requestedHeight);  //Save width and height requesting window to window
        }

        win.setFrameNumber(frameNumber);
        int attrChanges = 0;
        int flagChanges = 0;
        if (attrs != null) {
            mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);    //Adjust window parameters
            // if they don't have the permission, mask out the status bar bits
            ...
            if (win.mAttrs.type != attrs.type) {
                throw new IllegalArgumentException(
                        "Window type can not be changed after the window is added.");
            }

            // Odd choice but less odd than embedding in copyFrom()
            if ((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)
                    != 0) {
                attrs.x = win.mAttrs.x;
                attrs.y = win.mAttrs.y;
                attrs.width = win.mAttrs.width;
                attrs.height = win.mAttrs.height;
            }

            flagChanges = win.mAttrs.flags ^= attrs.flags;
            attrChanges = win.mAttrs.copyFrom(attrs);    //Copfrom gets the changed attributes
            if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
                    | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
                win.mLayoutNeeded = true;
            }
            ...
        }

        if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
                + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
        ...

        final int oldVisibility = win.mViewVisibility;

        // If the window is becoming visible, visibleOrAdding may change which may in turn
        // change the IME target.
        
        final boolean becameVisible =
                (oldVisibility == View.INVISIBLE || oldVisibility == View.GONE)
                        && viewVisibility == View.VISIBLE;
        //Determine whether input method is needed to window
        boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
                || becameVisible;
        final boolean isDefaultDisplay = win.isDefaultDisplay();
        boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility     //Determine whether the focus has changed
                || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
                || (!win.mRelayoutCalled));

        boolean wallpaperMayMove = win.mViewVisibility != viewVisibility    //Determine whether Wallpapers need to be moved
                && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
        wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
        if ((flagChanges & FLAG_SECURE) != 0 && winAnimator.mSurfaceController != null) {
            winAnimator.mSurfaceController.setSecure(isSecureLocked(win));
        }
        ...
        // This must be called before the call to performSurfacePlacement.
        if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
            if (DEBUG_VISIBILITY) {
                Slog.i(TAG_WM,
                        "Relayout invis " + win + ": mAnimatingExit=" + win.mAnimatingExit);
            }
            result |= RELAYOUT_RES_SURFACE_CHANGED;
            if (!win.mWillReplaceWindow) {
                focusMayChange = tryStartExitingAnimation(win, winAnimator, isDefaultDisplay,
                        focusMayChange);
            }
        }

        // We may be deferring layout passes at the moment, but since the client is interested
        // in the new out values right now we need to force a layout.
        //Windows Computing and Notification Drawing of Core Method WMS
        mWindowPlacerLocked.performSurfacePlacement(true /* force */);    //Performance Layout AndPlace Surfaces Locked Inner

        if (shouldRelayout) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");

            result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);   //Destroy window surface

            try {
                result = createSurfaceControl(outSurface, result, win, winAnimator);
            } catch (Exception e) {
                mInputMonitor.updateInputWindowsLw(true /*force*/);

                Slog.w(TAG_WM, "Exception thrown when creating surface for client "
                         + client + " (" + win.mAttrs.getTitle() + ")",
                         e);
                Binder.restoreCallingIdentity(origId);
                return 0;
            }
            if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                focusMayChange = isDefaultDisplay;
            }
            if (win.mAttrs.type == TYPE_INPUT_METHOD && mInputMethodWindow == null) {
                setInputMethodWindowLocked(win);
                imMayMove = true;
            }
            win.adjustStartingWindowFlags();
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        } else {
           ...
        }

        if (focusMayChange) {
            //System.out.println("Focus may change: " + win.mAttrs.getTitle());
            if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,   //Fous Change Update window
                    false /*updateInputWindows*/)) {
                imMayMove = false;
            }
            //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
        }

        // updateFocusedWindowLocked() already assigned layers so we only need to
        // reassign them at this point if the IM window state gets shuffled
        boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;
        final DisplayContent dc = win.getDisplayContent();
        if (imMayMove) {
            dc.computeImeTarget(true /* updateImeTarget */);            //If the input method moves, recalculate the ime position
            if (toBeDisplayed) {
                // Little hack here -- we -should- be able to rely on the function to return
                // true if the IME has moved and needs its layer recomputed. However, if the IME
                // was hidden and isn't actually moved in the list, its layer may be out of data
                // so we make sure to recompute it.
                dc.assignWindowLayers(false /* setLayoutNeeded */);    //Recalculate layer
            }
        }

        if (wallpaperMayMove) {
            win.getDisplayContent().pendingLayoutChanges |=
                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
        }

        if (win.mAppToken != null) {
            mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
        }

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                "relayoutWindow: updateOrientationFromAppTokens");
        configChanged = updateOrientationFromAppTokensLocked(displayId);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);

        if (toBeDisplayed && win.mIsWallpaper) {
            DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
            dc.mWallpaperController.updateWallpaperOffset(
                    win, displayInfo.logicalWidth, displayInfo.logicalHeight, false);   //Wallpaper Moving, Wallpaper Updating
        }
        ...
        
        //Give the layout result to the caller
        outFrame.set(win.mCompatFrame);   //Location and size of the final screen of Outframe
        outOverscanInsets.set(win.mOverscanInsets);
        outContentInsets.set(win.mContentInsets);
        win.mLastRelayoutContentInsets.set(win.mContentInsets);
        outVisibleInsets.set(win.mVisibleInsets);
        outStableInsets.set(win.mStableInsets);
        outCutout.set(win.mDisplayCutout.getDisplayCutout());
        outOutsets.set(win.mOutsets);
        outBackdropFrame.set(win.getBackdropFrame(win.mFrame));
      ...
    }

    if (configChanged) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration");
        sendNewConfiguration(displayId);     //Notify ams to update configuration and print evwntlog configuration_changed
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    Binder.restoreCallingIdentity(origId);
    return result;
}

 

1.3  performSurfacePlacement

Calculate the size of windows, execute animations, update surface, etc. These key tasks were implemented by performance Layout AndPlace Surface LockedInner before version 23 of the android api (including api 23). The reason for Windows Surface Placer may be that the performance Layout AndPlace Surface LockedInner method of WMS is too bloated to affect readability (in fact, Windows Surface Placer is not good anywhere), and more importantly, to achieve multi-window functionality in 7.0.

@/frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
final void performSurfacePlacement(boolean force) {
    if (mDeferDepth > 0 && !force) {
        return;
    }
    int loopCount = 6;
    do {
        mTraversalScheduled = false;
        performSurfacePlacementLoop();
        mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
        loopCount--;
    } while (mTraversalScheduled && loopCount > 0);
    mService.mRoot.mWallpaperActionPending = false;
}

private void performSurfacePlacementLoop() {
    ...
    Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
    mInLayout = true;

    boolean recoveringMemory = false;
    if (!mService.mForceRemoves.isEmpty()) {
        recoveringMemory = true;
        // Wait a little bit for things to settle down, and off we go.
        while (!mService.mForceRemoves.isEmpty()) {
            final WindowState ws = mService.mForceRemoves.remove(0);
            Slog.i(TAG, "Force removing: " + ws);
            ws.removeImmediately();
        }
        Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
        Object tmp = new Object();
        synchronized (tmp) {
            try {
                tmp.wait(250);
            } catch (InterruptedException e) {
            }
        }
    }

    try {
        mService.mRoot.performSurfacePlacement(recoveringMemory);  //here

        mInLayout = false;

        ...
    } ...
}
    
@/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
void performSurfacePlacement(boolean recoveringMemory) {
    if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
            + Debug.getCallers(3));

    int i;
    ...
    if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
            ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
    mService.openSurfaceTransaction();
    try {
        applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);  //here
    } catch (RuntimeException e) {
        Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
    } finally {
        mService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
    }
...

    mService.scheduleAnimationLocked();  //2 Start animation
}

By adding callback to phonewindowManager layout Windows Lw, the process is as follows

Session#relayout --> Wms#relayoutWindow --> WindowSurfacePlacer.performSurfacePlacement --> PerformSurfacePlacementLoop --> RootWindowContainer.performSurfacePlacement
 --> ApplySurfacechangesTransaction --> DisplayContent.applySurfaceChangesTransaction --> DisplayContent.performlayout -->  ForAllWindow --> apply -->  PhoneWindowManager.layoutWindowLw
     
Session.remove   -->    Wms.removeWindow  --> WindowState.removeifpossible  -->    SetupWindowForRemoveOnExit   --> WindowSurfacePlacer.performSurfacePlacement --> PerformSurfacePlacementLoop --> RootWindowContainer.performSurfacePlacement
 --> ApplySurfacechangesTransaction --> DisplayContent.applySurfaceChangesTransaction --> DisplayContent.performlayout -->  ForAllWindow --> apply -->  PhoneWindowManager.layoutWindowLw

1.4 DisplayContent #performLayout (Execution Layout)

DisplayContent#performLayout
Preparatory phase: Call the Phone Windows Manager class member function beginLayoutLw to set the screen size; including status bar, navigation bar
Computing phase: Call forAll Windows to calculate the size of parent window and child window respectively. (e.g. callback above)
End phase: Call finishLayoutLw, a member function of the Phone Windows Manager class, to perform some cleanup

#performLayout

@/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
    void performLayout(boolean initial, boolean updateInputWindows) {
        if (!isLayoutNeeded()) {  //First performance Layout initial = true
            return;
        }
        clearLayoutNeeded();

        final int dw = mDisplayInfo.logicalWidth;
        final int dh = mDisplayInfo.logicalHeight;
        if (DEBUG_LAYOUT) {
            Slog.v(TAG, "-------------------------------------");
            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...
        mDisplayFrames.mRotation = mRotation;
        mService.mPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);    //Set screen size; including status bar, navigation bar
        if (isDefaultDisplay) { //mDisplayFrames maintain the size attributes of the entire screen
            // Not needed on non-default displays.
            mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
            mService.mScreenRect.set(0, 0, dw, dh);
        }

        int seq = mLayoutSeq + 1;
        if (seq < 0) seq = 0;
        mLayoutSeq = seq;

        // Used to indicate that we have processed the dream window and all additional windows are
        // behind it.
        mTmpWindow = null;
        mTmpInitial = initial;

        // First perform layout of any root windows (not attached to another window).
        forAllWindows(mPerformLayout, true /* traverseTopToBottom */);  //2 Calculate the size of all parent windows

        // Used to indicate that we have processed the dream window and all additional attached
        // windows are behind it.
        mTmpWindow2 = mTmpWindow;
        mTmpWindow = null;

        // Now perform layout of attached windows, which usually depend on the position of the
        // window they are attached to. XXX does not deal with windows that are attached to windows
        // that are themselves attached.
        forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);

        // Window frames may have changed. Tell the input dispatcher about it.
        mService.mInputMonitor.layoutInputConsumers(dw, dh);
        mService.mInputMonitor.setUpdateInputWindowsNeededLw();
        if (updateInputWindows) {
            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
        }

        mService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
    }

 

1.4.1 PhoneWindowManager#beginLayoutLw

    @Override
    public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
        displayFrames.onBeginLayout();    //Initialize the property values of DisplayFrames
        // TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
        mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
        mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
        mDockLayer = 0x10000000;
        mStatusBarLayer = -1;
        dcf.setEmpty();  // Decor frame N/A for system bars.

        if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
          ...

            boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, dcf,
                    navVisible, navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard);
            if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
            updateSysUiVisibility |= layoutStatusBar(
                    displayFrames, pf, df, of, vf, dcf, sysui, isKeyguardShowing);
            if (updateSysUiVisibility) {
                updateSystemUiVisibilityLw();
            }
        }
        layoutScreenDecorWindows(displayFrames, pf, df, dcf);

        if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
            // Make sure that the zone we're avoiding for the cutout is at least as tall as the
            // status bar; otherwise fullscreen apps will end up cutting halfway into the status
            // bar.
            displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
                    displayFrames.mStable.top);
        }
    }

1.4.2 PhoneWindowManager#beginLayoutLw

Computing window size is done in layout Windows Lw. This method does not directly calculate the window size, but first calculates the maximum space that the window can expand, and then calls the computer frame Lw of Windows State to calculate the final window size (long, for various types of window processing).

Reference: WMS-related learning-relayout Window (6)

    /** {@inheritDoc} */
    @Override
    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
        // We've already done the navigation bar, status bar, and all screen decor windows. If the
        // status bar can receive input, we need to layout it again to accommodate for the IME
        // window.

 

Reference resources:

WMS-related learning-relayout Window (6)

Android 7.0 window animation setup process

WMS Related Learning-relayout Window (5)

WMS: Calculation of Window Size

Deep Understanding of Android Volume 3

 

 

 

Tags: Windows Android Session Java

Posted on Tue, 27 Aug 2019 20:09:20 -0700 by chrisredding