Android T WMS window related processes

1. Introduction

What is a window
? A window is a rectangular area on the screen that is used to draw various UI elements and respond to user input. In principle, the concept of a window is to occupy the display area of ​​a Surface instance alone (the graphics we see on the screen need to be drawn on the Surface).
Window is an abstract class and its implementation class is PhoneWindow.
You can first learn about hierarchical structure trees, which will help you understand this article.
Android T window level one - Container class
Android T window level two - Construction of hierarchical tree
Android T window level three - Adding hierarchical tree window

2. Brief description of the process

After Activity.onResume() is called, the client will communicate with WMS to display our layout on the screen. It mainly involves the following processes:
the client notifies WMS to create a window and adds it to WindowToken. That is the addToDisplayAsUser stage.
The client notifies WMS to create a Surface and calculate the window size. That is the relayoutWindow stage.
After the client obtains the window size calculated by WMS, it further measures the width and height of the View under the window. That is the performMeasure stage.
The client determines the size and position of the View under the window. That is the performLayout stage.
After determining the size and position of the View, draw the View. That is, performDraw stage.
Notify WMS that the client has completed drawing. WMS performs status refresh and animation processing of the system window, and finally displays the Surface. That is the reportDrawFinished stage.
Insert image description here
Here we start after Activity.onResume() is called.

1.Client

WindowManager: is an interface class responsible for window management (adding, deleting, and modifying).

WindowManagerImpl: The implementation class of WindowManager, but it leaves the specific management operations of the window to WindowManagerGlobal.

WindowManagerGlobal: is a singleton class that implements the logic of adding, deleting, and updating windows, but

ViewRootImpl: communicates with WMS through IWindowSession. Its internal class W implements the communication between WMS and ViewRootImpl.
Insert image description here

ActivityThread.java

  • handleResumeActivity
    adds view through the WindowManager interface, that is wm.addView(decor, l);, wm is the ViewManager object, that isViewManager wm = a.getWindowManager();

WindowManagerImpl.java

  • addView
    mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());mGlobal is the WindowManagerGlobal object.

WindowManagerGlobal.java

  • addView
    root.setView(view, wparams, panelParentView, userId);root is ViewRootImpl object.
    parentWindow.adjustLayoutParamsForSubWindow(wparams);parentWindow is Window (Window is an abstract class, PhoneWindow inherits from Window), that is, adjustLayoutParamsForSubWindow is called in Window to assign the token and title of the parameter layout.

ViewRootImpl.java

  • setView
    1.addToDisplayAsUser
    client notifies WMS to create a window and add it to WindowToken
    res = mWindowSession.addToDisplayAsUser(mWindow,mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,mTempControls);
    2.requestLayout
    schedules the first layout before adding to the window manager to ensure we relayout before receiving any other events from the system
    scheduleTraversals->doTraversal ->performTraversals
    Five key methods are called in performTraversals:
    relayoutWindow
    client notifies WMS to create a Surface and calculates the window size. After the
    performMeasure
    client obtains the window size calculated by WMS, it further measures the width and height of the View under the window.
    performLayout
    client Determine the size and position of the View under the window . After
    performDraw
    determines the size and position of the View, it draws the View.
    createSyncIfNeeded->reportDrawFinished
    notifies WMS that the client has completed drawing. WMS performs status refresh and animation processing of the system window, and finally displays the Surface

2. Communication methods

Session represents an interactive session between the client and the server. Generally speaking, different applications interact with WindowManagerService through different sessions, but different applications in the same process interact through the same Session.


  • Call the server through this interface in IWindowSession.aidl ViewRootImpl
    1.addToDisplayAsUser
    2.relayout
    3.finishDrawing

  • The implementation of Session.java
    IWindowSession is here, and it is finally called to WMS
    1.addToDisplayAsUser->addWindow
    2.relayout->relayoutWindow
    3.finishDrawing->finishDrawingWindow

3. Server

WindowManagerService: Responsible for allocating Surface to the window corresponding to the Activity, managing the display order and position size of the Surface, controlling window animation, and is also an important transfer station for the input system.

WindowState: corresponds to the client window one-to-one. When adding a window to WMS, WMS will create a WindowState for it to represent all properties of the window. WindowState is equivalent to property window management (such as providing external operation interfaces, which belongs to the hierarchical structure The bottom container), the window screen related aspects are all stripped to WindowStateAnimator, and WindowState is also the de facto window in WMS.

WindowStateAnimator: Mainly used to manage the WindowState related screen surface, and describe the state of the Surface through the mDrawState parameter.

WindowToken: Saves all WindowState with the same token, and organizes windows belonging to the same activity together. When the activity needs to update the window, it must provide the WindowToken to WMS to identify itself, and the type of the window must be the same as the one held. Some WindowToken types are the same.
Supplement: One WindowToken can correspond to multiple WindowStates. WindowToken is an identifier used to represent a window in the window hierarchy. Each Window has a WindowToken associated with it, which is used to help the system manage the display and interaction of the window.
A WindowToken can have multiple WindowStates representing the windows associated with it. This is because in the Android system, there may be some special cases, such as PopupWindow, Dialog, etc., which belong to the same WindowToken but are displayed on different windows.
Therefore, a WindowToken can be associated with multiple WindowStates, so that the operation and management of multiple windows can be achieved.

WindowSurfaceController: used to create SurfaceControl.

DisplayContent: represents a single screen. Windows belonging to the same DisplayContent will be displayed on the same screen. Each DisplayContent corresponds to a unique id. When adding a window, you can determine which screen it will be displayed on by specifying this ID.

WindowSurfacePlacer: The entry point for refreshing the entire window hierarchy.

RootWindowContainer: is the top-level container of the window container, which directly manages DisplayContent.

WindowManagerService.java

3.1.addWindow

Insert image description here
1. Obtain WindowToken or create WindowToken based on the token sent from the client, and mount it on the corresponding hierarchical node.
WindowToken token = displayContent.getWindowToken(hasParent ? parentWindow.mAttrs.token : attrs.token);
Determine whether the WindowToken has a parent, that is, whether the parentWindow is not empty
final boolean hasParent = parentWindow != null;
. Note: The previous code determines whether it is a child window, yes A value will be assigned to parentWindow; otherwise, parentWindow will still be the initial value, that is, empty. Regarding
Insert image description here
the window type, see the summary of common window parameters
. When Activity starts, new Token() will be used in the construction method of ActivityRecord.
Adding a window directly through addView on the application side will not have ActivityRecord, so there will be no new Token() in the construction method of ActivityRecord.
Windows (status bar, navigation bar, etc.) added directly on the system side are added through new WindowToken.Builder. That is, if you
actively use ViewManager.addView to add a window, new Token() will not be used in the construction method of ActivityRecord, otherwise through Added using new WindowToken.Builder.
The attrs.token parameter can be set on the application side. If the application does not set a token, it will be empty. The token is an IBinder type object and the default value is empty. public IBinder token = null;
For example:
the value can be set on the application side through mLayoutParams.token.
private WindowManager.LayoutParams mLayoutParams;
mLayoutParams.token = null;

Later, we will continue to judge whether the token is empty, and finally create the token in the final else.
Insert image description here
2. Create WindowState
final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);
. 3. Verify whether the current window can be added to WMS.
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
This method will judge the window TYPE, FLAG and other aspects. Only when ADD_OKAY is returned, the addition of the current window is allowed, otherwise the addition of the window is not allowed. If you want to prohibit certain applications from adding windows, you can filter the application by its package name, or you can directly filter the windows that the application wants to add in the addView() method of WindowManagerGlobal.java.
Note: ADD_OKAYDefined in WindowManagerGlobal, there are some other return values ​​in this class. All resconstants returned will eventually be judged in the setView method of ViewRootImpl.
4. Call openInputChannel to initialize the input-related channels (not discussed in this article)
final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) { win.openInputChannel(outInputChannel); }
5. After WindowState is added to the WindowToken
win.mToken.addWindow(win);
WMS window, the Surface has not been created yet. At this time, the mDrawState status is NO_SURFACE.

3.2 relayoutWindow

Insert image description here
1. Get the WindowState created during the window addition phase based on the mWindowMap of IWindow passed by the client.
final WindowState win = windowForClientLocked(session, client, false);
2. Set DisplayContent.mLayoutNeeded and shouldRelayout flag
win.setDisplayLayoutNeeded();win as the WindowState object. The actual operation of this method is in DisplayContent.
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING || win.mActivityRecord.isClientVisible());
3. Create SurfaceControl and
call it in layoutWindow(). The createSurfaceControl method creates a SurfaceControl.
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);The implementation of this method is still in WMS.
Here, the createSurfaceControl method is used as the starting point.
Insert image description here
In createSurfaceControl(), the WindowStateAnimator is called to perform the specific creation of the SurfaceControl. surfaceController = winAnimator.createSurfaceLocked();
After the Surface is created, the Surface has not yet been drawn. At this time, the mDrawState state is DRAW_PENDING, which
will be created. SurfaceControl is assigned to the client's outSurfaceControl
surfaceController.getSurfaceControl(outSurfaceControl);
4. Window size calculation and Surface status update.
PerformSurfacePlacement is called in layoutWindow().
mWindowPlacerLocked.performSurfacePlacement(true /* force */);mWindowPlacerLocked is the WindowSurfacePlacer object, so here we use WindowSurfacePlacer's performSurfacePlacement() as the starting point
Insert image description here
to process the window layout loop
WindowSurfacePlacer.performSurfacePlacementLoop()
Process the status change of Surface and call LayoutWindowLw process
RootWindowContainer.performSurfacePlacementNoTrace()
to calculate the window position and size
DisplayPolicy.layoutWindowLw()

3.3 finishDrawingWindow

Insert image description here
Insert image description here

1. WMS accepts the client request, updates mDrawState to COMMIT_DRAW_PEDING win.finishDrawing(postDrawTransaction, seqId), and requests the window layout. mWindowPlacerLocked.requestTraversal();
2. Through the callback of mApplySurfaceChangesTransaction,

Insert image description here
Call commitFinishDrawingLocked() Insert image description here
to change the mDrawState state and update mDrawState to READY_TO_SHOW.
Finally, after mDrawState is updated to HAS_DRAW, request the window layout again
Insert image description here
3. Execute show Surface
showSurfaceRobustlyLocked(t)
Note: In the commitFinishDrawingLocked() method of WindowStateAnimator, if the application creates the window through addView, then If there is no ActivityRecord , or the window type is a startup window, it will be called directly result = mWin.performShowLocked();, that is, the performShowLocked() method of WindowState changes the window state to HAS_DRAW, otherwise it will be gradually called from the checkAppTransitionReady method of RootWindowContainer to performShowLocked()
Insert image description here

4. Summary of window status changes

In order to manage the display progress of the window, WMS defines mDrawState in WindowStateAnimator to describe the state of the Surface. There are mainly five states as follows:
NO_SURFACE: WMS adds a window, that is, after calling addWindow, the Surface has not been created, and mDrawState is in this state.
DRAW_PENDING: After the app calls relayoutWindow to create the Surface, but the Surface has not yet been drawn, mDrawState is in this state.
COMMIT_DRAW_PENDING: The app finishes drawing the Surface, calls finishDrawing, and sets mDrawState to this state.
READY_TO_SHOW: During the performSurfacePlacement process, all mDrawState in the COMMIT_DRAW_PENDING state will be changed to READY_TO_SHOW.
HAS_DRAW: If the window is ready to be displayed, WMS executes performShowLocked and sets mDrawState to this state.
Insert image description here

Window display related methods Explanation of work content
addWindow The App requests WMS to add a window record and will create a new WindowState (NO_SURFACE) in WMS.
relayoutWindow App applies for a surface from WMS for drawing. After execution, the window owns the surface (NO_SURFACE->DRAW_PENDING)
finishDrawingWindow After the App completes drawing on the surface, it notifies WMS (DRAW_PENDING->COMMIT_DRAW_PENDING)
commitFinishDrawingLocked WMS traverses the window, for the window that has completed drawing (COMMIT_DRAW_PENDING->READY_TO_SHOW)
performShowLocked Determine whether the system allows the window to be displayed isReadyForDisplay(READY_TO_SHOW->HAS_DRAWN)
showSurfaceRobustlyLocked For the window in the HAS_DRAWN state, use SurfaceControl to notify SurfaceFlinger to display it.

5. Brief description of removal process

Window removal is initiated from the App side. When the Activity executes destroy(), that is, starting from handleDestroyActivity(), execute wm.removeViewImmediate() to open it;
call WindowState through removeWindow() of WindowManagerGlobal–>ViewRootImpl–>Session–>WindowManagerService. removeIfPossible()–>removeImmediately(), then call destroySurfaceLocked()–>destroySurface() of WindowStateAnimator, gradually call destroy() that changes the drawing state to NO_SURFACE–>WindowSurfaceController, and finally call remove() of SurfaceControl to notify SurfaceFlinger. Remove layer ;

3. Detailed explanation of code process

1.Client

1.1 Activity goes after onresume

From the ActivityThread.handleResumeActivity method,
1. Call performResumeActivity and execute onResume.
2. Obtain an instance of WindowManager's implementation class WindowManagerImpl.
3. Call WindowManagerImpl.addView and pass in DecorView and the current layout parameters WindowManager.LayoutParams.
Code path: framework/core/java/android/app/ActivityThread.java

@Override
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
            boolean isForward, String reason) {
    
    
			......
        // TODO Push resumeArgs into the activity for consideration
        // skip below steps for double-resume and r.mFinish = true case.
        /*1.执行onResume*/
        if (!performResumeActivity(r, finalStateRequest, reason)) {
    
    
            return;
        }
		......
		//获取Activity实例
        final Activity a = r.activity;
		......
        // If the window hasn't yet been added to the window manager,
        // and this guy didn't finish itself or start another activity,
        // then go ahead and add the window.
        //mStartedActivity在performLaunchActivity和performResumeActivity方法中被置为false
        boolean willBeVisible = !a.mStartedActivity;
		......
        if (r.window == null && !a.mFinished && willBeVisible) {
    
    
        	//获取当前Activity的PhoneWindow
            r.window = r.activity.getWindow();
            //从PhoneWindow中获取DecorView
            View decor = r.window.getDecorView();
            //将view的可见性状态设置为INVISIBLE,view不可见但是仍然占用布局空间
            decor.setVisibility(View.INVISIBLE);
            /*2.获取WindowManager的实现类WindowManagerImpl的实例*/
            ViewManager wm = a.getWindowManager();
            //获取布局参数
            WindowManager.LayoutParams l = r.window.getAttributes();
            //将phoneWindow的DecorView赋值给mDecor
            a.mDecor = decor;
            //设置窗口类型为TYPE_BASE_APPLICATION
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
    
    
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up callbacks with the Activity
                // in addView->ViewRootImpl#setView. If we are instead reusing
                // the decor view we have to notify the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
    
    
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
    
    
                if (!a.mWindowAdded) {
    
    
                    a.mWindowAdded = true;
                    /*3.传入DecorView和当前布局参数WindowManager.LayoutParams*/
                    wm.addView(decor, l);
                } else {
    
    
                    // The activity will get a callback for this {@link LayoutParams} change
                    // earlier. However, at that time the decor will not be set (this is set
                    // in this method), so no action will be taken. This call ensures the
                    // callback occurs with the decor set.
                    a.onWindowAttributesChanged(l);
                }
            }
        }
		......
    }

wm.addView(decor, l);The implementation of the WindowManager interface is WindowManagerImpl, that is, the addView method in WindowManagerImpl is actually called.
Code path: framework/core/java/android/view/WindowManagerImpl.java

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    
    
        applyTokens(params);
        //转交给windowManagerGlobal,添加view
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }

WindowManagerImpl hands over the management of the window to WindowManagerGlobal, and calls the addView method of WindowManagerGlobal.
The processing of windows in WindowManagerGlobal mainly involves the following steps:
1. Check the parameters passed in by WindowManagerImpl.
2. Set token, title and other related properties in WindowManager.LayoutParams. See "[ 1.2 Creation and Transfer of Token ]".
3. Create a ViewRootImpl object and obtain the Session used by the client to communicate with WMS. See "[ 1.3 Creation of ViewRootImpl ]".
4. Back up DecorView, WindowManager.LayoutParams and ViewRootImpl in WindowManagerGlobal.
5. Call ViewRootImpl to communicate with WMS to add a window. See "[ 1.4 Communication between ViewRootImpl and WMS ]".
Code path: framework/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
    
    
        /*1.对WindowManagerImpl传进来的参数进行检查*/
        if (view == null) {
    
    
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
    
    
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
    
    
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //此处的ParentWindow即当Activity的PhoneWindow
        if (parentWindow != null) {
    
    
        	/*2.为wparams的token进行赋值*/
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
    
    
        	......
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
    
    
			......
            IWindowSession windowlessSession = null;
			......
            if (windowlessSession == null) {
    
    
           		/*3.新建ViewRootImpl,在新建时会通过WindowManagerGlobal获取session*/
                root = new ViewRootImpl(view.getContext(), display);
            } else {
    
    
                root = new ViewRootImpl(view.getContext(), display,
                        windowlessSession);
            }

            view.setLayoutParams(wparams);
			/*4.在WindowManagerGlobal中备份DecorView,WindowManager.LayoutParams以及ViewRootImpl。*/
			//当前view加入到view列表中
            mViews.add(view);
            //将新建的viewRootImpl加入到root列表中
            mRoots.add(root);
            //将当前布局参数加入到布局参数列表中
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
    
    
            	/*5.调用ViewRootImpl,设置view,panelParentView为null,与WMS通信添加窗口*/
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
    
    
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
    
    
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

1.2 Creation and transfer of Token

parentWindow.adjustLayoutParamsForSubWindow(wparams);Calling the Window's adjustLayoutParamsForSubWindow() method
in adjustLayoutParamsForSubWindow will assign values ​​to the token and title in WindowManager.LayoutParams respectively.
1. First, different processing is done for sub-windows, system windows and application windows. Here we only focus on the processing of application windows.
2. Secondly, assign the current PhoneWindow.mAppToken to WindowManager.LayoutParams.token.
Code path: framework/core/java/android/view/Window.java

    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
    
    
        CharSequence curTitle = wp.getTitle();
        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
    
    
                //对子窗口的Token以及Title赋值
                ......
        } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
    
    
                //对子窗口的Token以及Title赋值
                ......
        } else {
    
    
        	//对应用窗口的Token以及Title赋值
            if (wp.token == null) {
    
    
            	//将当前PhoneWindow的mAppToken赋值给wp.Token
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
            }
            //将Title设置为mAppName
            if ((curTitle == null || curTitle.length() == 0)
                    && mAppName != null) {
    
    
                wp.setTitle(mAppName);
            }
        }
        //设置为packageName 
        if (wp.packageName == null) {
    
    
            wp.packageName = mContext.getPackageName();
        }
        ......
    }

The mAppToken here is the Token created on the ATMS side when the Activity starts.
Next, let’s see how the Token is passed from the ATMS side and assigned to PhoneWindow.mAppToken
Insert image description here

1. When creating a new ActivityRecord on the ATMS side, a new Token is created. And assign it to ActivityRecord.token
ActivityRecord inherits WindowToken
code path: framework/services/core/java/com/android/server/wm/ActivityRecord.java

 private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
            int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
            @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
            String _resultWho, int _reqCode, boolean _componentSpecified,
            boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
            ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
            TaskDescription _taskDescription, long _createTime) {
    
    
        //新建Token
        super(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,
                null /* displayContent */, false /* ownerCanManageAppTokens */);
        ......
}

2. Encapsulate ActivityRecord.token in clientTransaction and pass this to the client.
Code path: framework/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
            boolean andResume, boolean checkConfig) throws RemoteException {
    
    
        ......
        final Task task = r.getTask();
        final Task rootTask = task.getRootTask();
        ......

        try {
    
    
            ......

            try {
    
    
            	......
                // Create activity launch transaction.
                /*将ActivityRecord.token封装在clientTransaction中*/
                final ClientTransaction clientTransaction = ClientTransaction.obtain(
                        proc.getThread(), r.token);

                final boolean isTransitionForward = r.isTransitionForward();
                final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
                        proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
                        results, newIntents, r.takeOptions(), isTransitionForward,
                        proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                        r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
                ......

                // Schedule transaction.
                /*将clientTransaction传递给客户端*/
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                ......

            } catch (RemoteException e) {
    
    
                ......
            }
        } finally {
    
    
            ......
        }
        ......
        return true;
    }

final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.token);
Call the obtain method in ClientTransaction and save ActivityRecord.token to the mActivityToken
code path: framework/core/java/android/app/servertransaction/ClientTransaction.java

    /** Obtain an instance initialized with provided params. */
    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
    
    
        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
        if (instance == null) {
    
    
        //创建ClientTransaction
            instance = new ClientTransaction();
        }
        instance.mClient = client;
        /*把ActivityRecord.token存到mActivityToken*/
        //private IBinder mActivityToken;
        instance.mActivityToken = activityToken;

        return instance;
    }

3. The client obtains the Token from the ATMS side from ClientTransaction and passes it to LaunchActivityItem.
Code path: framework/core/java/android/app/servertransaction/TransactionExecutor.java

   /** Cycle through all states requested by callbacks and execute them at proper times. */
    @VisibleForTesting
    public void executeCallbacks(ClientTransaction transaction) {
    
    
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ......
        /*从ClientTransaction中获取ATMS端传来的Token*/
        final IBinder token = transaction.getActivityToken();
        ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
        ......

        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
    
    
            final ClientTransactionItem item = callbacks.get(i);
            ......
            /*将Token传递到LaunchActivityItem中*/
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            ......
        }
    }

4. In LaunchActivityItem, save the Token passed by the client in ActivityClientRecord.token.
Code path: framework/core/java/android/app/servertransaction/LaunchActivityItem.java

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
    
    
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        //将客户端传过来的Token保存在ActivityClientRecord的token中
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
                mTaskFragmentToken);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

client.handleLaunchActivity(r, pendingActions, null /* customIntent */);ClientTransactionHandler calls the handleLaunchActivity method. ClientTransactionHandler is an abstract class and its subclass is ActivityThread. That is, handleLaunchActivity() in this class is actually called, and performLaunchActivity() is called from this method. 5. Client ActivityThread will ActivityClientRecord and its
corresponding The token is saved in the ActivityThread.mActivities array, and Activity.attach is called to pass the Token to the Activity.
Code path: framework/core/java/android/app/ActivityThread.java

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    
    	......
        try {
    
    
            Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
            ......
            synchronized (mResourcesManager) {
    
    
            	/*将ActivityClientRecord以及其对应的Token保存在mActivities中*/
            	//mActivities的类型为ArrayMap<IBinder, ActivityClientRecord>
                mActivities.put(r.token, r);
            }

            if (activity != null) {
    
    
                ......
                /*将Token赋值给Activity.mToken*/
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
                        r.assistToken, r.shareableActivityToken);
                ......

        } catch (SuperNotCalledException e) {
    
    
            throw e;

        } catch (Exception e) {
    
    
        	......
        }

        return activity;
    }

6. Assign the Token sent from the client to Activity.mToken in the Activity. In addition, a new PhoneWindow is also created in this method, and PhoneWindow.mAppToken is also set to the Token passed by the client.
Code path: framework/core/java/android/app/Activity.java

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
            IBinder shareableActivityToken) {
    
    
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        /*新建PhoneWindow*/
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ......
        /*将客户端传过来的Token赋值给mToken*/
        mToken = token;
        ......
        /*PhoneWindow.mAppToken设置为当前客户端传递过来的Token*/
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ......
    }


PhoneWindow inherits Window, and setWindowManager actually calls its parent class method, setting mAppToken to the mToken code path passed by the current client : framework/core/java/android/view/Window.java

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
    
    
    	//传递客户端的mToken给appToken
        setWindowManager(wm, appToken, appName, false);
    }

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
    
    
        /*把appToken赋值给mAppToken*/
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated;
        if (wm == null) {
    
    
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

1.3 Creation of ViewRootImpl

root = new ViewRootImpl(view.getContext(), display);Previously, in the process of [ 1.1 Activity after onresume ], there was a call to create ViewRootImpl. Here we look at the construction method of ViewRootImpl.
Code path: framework/core/java/android/view/ViewRootImpl.java

    public ViewRootImpl(Context context, Display display) {
    
    
        this(context, display, WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }

    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
    
    
        this(context, display, session, false /* useSfChoreographer */);
    }

    public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
    
    
        mContext = context;
        mWindowSession = session;
        ......
    }

From this construction method, we can see that the IWindowSession, the bridge between the client and WMS, is obtained through WindowManagerGlobal.getWindowSession and assigned to ViewRootImpl.mWindowSession.

Next we look at how to obtain the Session in WindowManagerGlobal.
1. Obtain IWindowManager through getWindowManagerService, and WindowManagerService implements this Binder interface.
2. Call the IWindowManager.openSession method, that is, WMS.openSession, and a new Session will be created on the WMS side. At this point, the bridge for communication between the client and WMS has been established.
Code path: framework/core/java/android/view/WindowManagerGlobal.java

    @UnsupportedAppUsage
    public static IWindowSession getWindowSession() {
    
    
        synchronized (WindowManagerGlobal.class) {
    
    
            if (sWindowSession == null) {
    
    
                try {
    
    
                    // Emulate the legacy behavior.  The global instance of InputMethodManager
                    // was instantiated here.
                    // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    /*1.获取Binder*/
                    IWindowManager windowManager = getWindowManagerService();
                    /*2.调用WMS的openSession*/
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
    
    
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
    
    
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
    
    
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

It can be seen from the code that if sWindowSession is not empty, it will be returned directly. sWindowSession is the current WindowManagerGlobal property, and WindowManagerGloba is a singleton, so there is only one IWindowSession in a client process to communicate with WMS. If sWindowSession is empty, an IWindowSession is created.

Call openSession in WindowManagerService and create a new Session
code path: framework/services/core/java/com/android/server/wm/WindowManagerService.java

    @Override
    public IWindowSession openSession(IWindowSessionCallback callback) {
    
    
    	/*新建Session*/
        return new Session(this, callback);
    }

1.4 Communication between ViewRootImpl and WMS

root.setView(view, wparams, panelParentView, userId);Previously, in the process of [ 1.1 Activity after onresume ], ViewRootImpl was called to communicate with WMS. Let’s continue to see.
The current method is to communicate with WMS to add the entrance to the window. Here we only focus on two points:
1.requestLayout() This method will call doTraversal(), then call performTraversals(), and finally call the relayoutWindow() and reportDrawFinished() processes. 2.mWindowSession.addToDisplayAsUser communicates with the server through the Session, communicates with the server through Binder, and calls the Session
's addToDisplayAsUser method.

   /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    
    
        setView(view, attrs, panelParentView, UserHandle.myUserId());
    }

    /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
    
    
        synchronized (this) {
    
    
            if (mView == null) {
    
    
                mView = view;
                ......
                //将布局参数拷贝纸mWindowAttributes
                mWindowAttributes.copyFrom(attrs);
                //设置包名
                if (mWindowAttributes.packageName == null) {
    
    
                    mWindowAttributes.packageName = mBasePackageName;
                }
                mWindowAttributes.privateFlags |=
                        WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;

                attrs = mWindowAttributes;
                ......
                // Keep track of the actual window flags supplied by the client.
                //获取当前布局的flags
                mClientWindowLayoutFlags = attrs.flags;
                ......
                int res; /* = WindowManagerImpl.ADD_OKAY; */

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                /*请求布局,对应服务端layoutWindow流程*/
                requestLayout();
                InputChannel inputChannel = null;
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
    
    
                    inputChannel = new InputChannel();
                }
                ......

                try {
    
    
                	......
                	/*与服务端进行Binder通信,调用Session的addToDisplayAsUser方法*/
                	//执行addWindow的相关流程
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
                            mTempControls);
                    ......
                } catch (RemoteException e) {
    
    
                	......
                } finally {
    
    
                    if (restore) {
    
    
                        attrs.restore();
                    }
                }
                ......
                if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                if (res < WindowManagerGlobal.ADD_OKAY) {
    
    
                    mAttachInfo.mRootView = null;
                    mAdded = false;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    switch (res) {
    
    
                        case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                        case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not valid; is your activity running?");
                        case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not for an application");
                        case WindowManagerGlobal.ADD_APP_EXITING:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- app for token " + attrs.token
                                    + " is exiting");
                        case WindowManagerGlobal.ADD_DUPLICATE_ADD:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- window " + mWindow
                                    + " has already been added");
                        case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                            // Silently ignore -- we would have just removed it
                            // right away, anyway.
                            return;
                        case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
                            throw new WindowManager.BadTokenException("Unable to add window "
                                    + mWindow + " -- another window of type "
                                    + mWindowAttributes.type + " already exists");
                        case WindowManagerGlobal.ADD_PERMISSION_DENIED:
                            throw new WindowManager.BadTokenException("Unable to add window "
                                    + mWindow + " -- permission denied for window type "
                                    + mWindowAttributes.type);
                        case WindowManagerGlobal.ADD_INVALID_DISPLAY:
                            throw new WindowManager.InvalidDisplayException("Unable to add window "
                                    + mWindow + " -- the specified display can not be found");
                        case WindowManagerGlobal.ADD_INVALID_TYPE:
                            throw new WindowManager.InvalidDisplayException("Unable to add window "
                                    + mWindow + " -- the specified window type "
                                    + mWindowAttributes.type + " is not valid");
                        case WindowManagerGlobal.ADD_INVALID_USER:
                            throw new WindowManager.BadTokenException("Unable to add Window "
                                    + mWindow + " -- requested userId is not valid");
                    }
                    throw new RuntimeException(
                            "Unable to add window -- unknown error code " + res);
                }
                ......
            }
        }
    }

The key added code is

res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
        getHostVisibility(), mDisplay.getDisplayId(), userId,
        mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
        mTempControls);

addToDisplayAsUser()The method will eventually go to the addWindow method of WindowManagerService.java. The return value of the addWindow method will finally be returned resto ViewRootImpl's setView method. If the return value meets if (res < WindowManagerGlobal.ADD_OKAY)the conditions, switch (res)an exception will be thrown according to the corresponding case.
At this point, the client process ends, and then enters the server process.

2. Server

2.1 Window addition

WMS accepts the client's request to add a window through Session, so WMS will create a new WindowState, add WindowState to WindowToken, and update the z-order of all WindowState under WindowToken.
The client calls Session.addToDisplayAsUser on the WMS side through Binder communication to enter the addWindow process.
Mainly do these three things:
1. Receive client request
2. Initialize WindowState
3. Add WindowState to WIndowToken

2.1.1 Receive client request

The parameter IWindow window passed by the client to the Session
is the handle used by WMS to communicate with the client.
WindowManager.LayoutParams arrts: Window layout parameters.
viewVisibility: The visibility of the rootView attached to the window.
displayId: As the name suggests, display id represents DisplayContent, which is the id of the screen.
InsetsVisibilities requestedVisibilities: mVisibilities of the current object records the visibility of insets.
InputChannel outInputChannel: InputDispatcher receives the events read by InputReader and distributes them to the corresponding window. InputDispatcher belongs to the system_server process and is not in the same process as each application. The connection between them relies on InputChannel.
InsetsState outInsetsState: used to save the status of all Insets in the system. This object is only created on the client side, and the internal properties need to be assigned on the WMS side.
InsetsSourceControl[] outActiveControls: InSetsSourceControl array. This object is only created on the client side, and the internal properties need to be assigned on the WMS side.
Session calls WMS.addWindow to pass the parameters passed in by the client to WMS.
Code path: framework/services/core/java/com/android/server/wm/Session.java

    @Override
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
    
    
        return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
                requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
    }
2.1.2 addWindow

The main logic of adding a window is executed in WMS.addWindow. This method mainly implements the following functions:
1. First, perform permission verification and various condition judgments.
2. Obtain the windowToken based on the token sent from the client.
3. Use the parameters passed by the client to create a WindowState instance and add it to WMS.mWindowMap.
4. Add the newly created WindowState to the corresponding WindowToken, and assign a z-order to each window.
Code path: framework/services/core/java/com/android/server/wm/WindowManagerService.java

    public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
            int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls) {
    
    
		......
		
		/*1.进行权限验证以及各种条件判断*/
		//判断调用者是否有权限add window
        int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
                appOp);
        if (res != ADD_OKAY) {
    
    
            return res;
        }

        WindowState parentWindow = null;
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
        //获取将要添加的窗口类型
        final int type = attrs.type;

        synchronized (mGlobalLock) {
    
    
			......
			//根据displayId以及客户端传过来的token获取相应的displayContent
            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
			......
			//判断mWindowMap中是否已经存在当前客户端的key,如果有则已经将当前客户端的window添加了,无需重复添加
            if (mWindowMap.containsKey(client.asBinder())) {
    
    
                ProtoLog.w(WM_ERROR, "Window %s is already added", client);
                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
            }
			//判断是否是子窗口
            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
    
    
                parentWindow = windowForClientLocked(null, attrs.token, false);
                if (parentWindow == null) {
    
    
                    ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
                            + "%s.  Aborting.", attrs.token);
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
    
    
                    ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
                            + "%s.  Aborting.", attrs.token);
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
            }
			//判断当前DisplayContent是否是私有的,只拥有该display或者display已经的应用才可以在其上创建
            if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
    
    
                ProtoLog.w(WM_ERROR,
                        "Attempted to add private presentation window to a non-private display.  "
                                + "Aborting.");
                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
            }
			......
            ActivityRecord activity = null;
            //设置是否有父窗口的标志位
            final boolean hasParent = parentWindow != null;
            // Use existing parent window token for child windows since they go in the same token
            // as there parent window so we can apply the same policy on them.
           
         	/*2.根据客户端传来的token获取windowToken*/
			//attrs.token去DisplayContent.mTokenMap中去取WindowToken
        	//那么WindowToken是什么时候加入到mTokenMap中的呢
       	 	//这就要追溯到Activity的启动时,加入到DisplayContent中
        	//在ActivityStarter.startActivityInner中调用addOrReparentStartingActivity通过addChild一步步调用到WindowContainert中。
        	//在调用setParent,最终通过onDisplayChanged将ActivityRecord加入到DisplayContent.mTokenMap中
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);
            // If this is a child window, we want to apply the same type checking rules as the
            // parent window type.
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;

            boolean addToastWindowRequiresToken = false;

            final IBinder windowContextToken = attrs.mWindowContextToken;

            if (token == null) {
    
    
            ......
             }else if (rootType >= FIRST_APPLICATION_WINDOW
                    && rootType <= LAST_APPLICATION_WINDOW) {
    
    
                //当前窗口为应用窗口,通过token,获取ActivityRecord
                activity = token.asActivityRecord();
            ......
            } else if (token.asActivityRecord() != null) {
    
    
                ProtoLog.w(WM_ERROR, "Non-null activity for system window of rootType=%d",
                        rootType);
                // It is not valid to use an app token with other system types; we will
                // instead make a new token for it (as if null had been passed in for the token).
                attrs.token = null;
                token = new WindowToken.Builder(this, client.asBinder(), type)
                        .setDisplayContent(displayContent)
                        .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                        .build();
            }
			/*3.创建WindowState*/
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
            //将客户端传过来的Insets可见性赋值给WindowState的requestedVisibilities
            win.setRequestedVisibilities(requestedVisibilities);
			//验证当前窗口是否可以添加到WMS
            res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
            if (res != ADD_OKAY) {
    
    
                return res;
            }
			//调用openInputChannel,初始化input相关通路
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
    
    
                win.openInputChannel(outInputChannel);
            }
			//创建SufaceSession用于SurfaceFlinger通信
            win.attach();
            //将客户端与WindowState加入到mWindowMap中
            mWindowMap.put(client.asBinder(), win);
            win.initAppOpsState();
			......
			/*4.将WindowState加入到WindowToken*/
            win.mToken.addWindow(win);
			......
        return res;
    }

mWindowMap saves the mapping relationship between each WindowState and the client window. When the client application requests a window operation, the corresponding WindowState is queried through mWindowMap.

2.1.3 Creation of WindowToken
token = new WindowToken.Builder(this, client.asBinder(), type)
        .setDisplayContent(displayContent)
        .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
        .build();

What is called here is the build method of its WindowToken itself.
Code path: frameworks/base/services/core/java/com/android/server/wm/WindowToken.java

WindowToken build() {
    
    
    return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent,
            mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions);
}

protected WindowToken(WindowManagerService service, IBinder _token, int type,
        boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens,
        boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
    
    
    super(service);
    token = _token;
    windowType = type;
    mOptions = options;
    mPersistOnEmpty = persistOnEmpty;
    mOwnerCanManageAppTokens = ownerCanManageAppTokens;
    mRoundedCornerOverlay = roundedCornerOverlay;
    mFromClientToken = fromClientToken;
    if (dc != null) {
    
    
        dc.addWindowToken(token, this);
    }
}

dc.addWindowToken(token, this);In the WindowToken construction method, call DisplayContent.addWindowToken to add the WindowToken to the WindowContainer hierarchy with DisplayContent as the root node.
Code path: frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void addWindowToken(IBinder binder, WindowToken token) {
    
    
        final DisplayContent dc = mWmService.mRoot.getWindowTokenDisplay(token);
        if (dc != null) {
    
    
            // We currently don't support adding a window token to the display if the display
            // already has the binder mapped to another token. If there is a use case for supporting
            // this moving forward we will either need to merge the WindowTokens some how or have
            // the binder map to a list of window tokens.
            throw new IllegalArgumentException("Can't map token=" + token + " to display="
                    + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
        }
        if (binder == null) {
    
    
            throw new IllegalArgumentException("Can't map token=" + token + " to display="
                    + getName() + " binder is null");
        }
        if (token == null) {
    
    
            throw new IllegalArgumentException("Can't map null token to display="
                    + getName() + " binder=" + binder);
        }

        mTokenMap.put(binder, token);

        if (token.asActivityRecord() == null) {
    
    
            // Set displayContent for non-app token to prevent same token will add twice after
            // onDisplayChanged.
            // TODO: Check if it's fine that super.onDisplayChanged of WindowToken
            //  (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned.
            token.mDisplayContent = this;
            // Add non-app token to container hierarchy on the display. App tokens are added through
            // the parent container managing them (e.g. Tasks).
            //1.调用DisplayContent.findAreaForToken为当前WindowToken寻找一个合适的父容器,DisplayArea.Tokens对象。
            final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
            //2.将WindowToken添加到父容器中。
            da.addChild(token);
        }
    }

Here we look at it in two steps:
1. final DisplayArea.Tokens da = findAreaForToken(token).asTokens();Call DisplayContent.findAreaForToken to find a suitable parent container for the current WindowToken, the DisplayArea.Tokens object.

    /**
     * Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
     * <p>
     * Note that the differences between this API and
     * {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
     * {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
     * from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
     * hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
     * {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
     * </p>
     *
     * @see DisplayContent#findAreaForTokenInLayer(WindowToken)
     */
    DisplayArea findAreaForToken(WindowToken windowToken) {
    
    
        return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
                windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
    }

Find a DisplayArea object for the incoming WindowToken and add it.

    DisplayArea findAreaForWindowType(int windowType, Bundle options,
            boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
    
    
        // TODO(b/159767464): figure out how to find an appropriate TDA.
        //1.如果是App窗口,那么返回默认的TaskDisplayArea对象。
        if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
    
    
            return getDefaultTaskDisplayArea();
        }

        // Return IME container here because it could be in one of sub RootDisplayAreas depending on
        // the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
        // the server side, but not mSelectRootForWindowFunc customized by OEM.
        //2.如果是输入法窗口,那么返回ImeContainer。
        if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
    
    
            return getImeContainer();
        }
        //3.如果是其他类型,继续寻找。
        return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
                ownerCanManageAppToken, roundedCornerOverlay);
    }

If it is an App window, the default TaskDisplayArea object is returned.
If it is an input method window, return ImeContainer.
If it's another type, keep looking.
mDisplayAreaPolicy.findAreaForWindowType(windowType, options, ownerCanManageAppToken, roundedCornerOverlay);What is called is the findAreaForWindowType method in DisplayAreaPolicy. DisplayAreaPolicy is an abstract class. Result in DisplayAreaPolicyBuilder inherits this class.
Code path: frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java

static class Result extends DisplayAreaPolicy {
    
    
    ......
       @Override
       public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
               boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
    
    
           return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
                   ownerCanManageAppTokens, roundedCornerOverlay);
       }
       ......

Code path: frameworks/base/services/core/java/com/android/server/wm/RootDisplayArea.java

  DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
           boolean roundedCornerOverlay) {
    
    
       //通过getWindowLayerFromTypeLw方法获取对应的窗口类型
       int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
               ownerCanManageAppTokens, roundedCornerOverlay);
       if (windowLayerFromType == APPLICATION_LAYER) {
    
    
           throw new IllegalArgumentException(
                   "There shouldn't be WindowToken on APPLICATION_LAYER");
       }
       return mAreaForLayer[windowLayerFromType];
   }

Calculate the level value windowLayerFromType corresponding to the window type through the getWindowLayerFromTypeLw method, and then find the DisplayArea.Tokens object corresponding to windowLayerFromType from the mAreaForLayer array.
2. da.addChild(token);Add WindowToken to the parent container (leaf node).
Code path: frameworks/base/services/core/java/com/android/server/wm/DisplayArea.java

    /**
     * DisplayArea that contains WindowTokens, and orders them according to their type.
     */
    public static class Tokens extends DisplayArea<WindowToken> {
    
    
        ......
        void addChild(WindowToken token) {
    
    
            addChild(token, mWindowComparator);
        }
        ......

addChild(token, mWindowComparator);Finally, the WindowContainer.addChild method is called to add WindowToken to the leaf node.

2.1.4 WindowState initialization

Initialize WindowState in addWindow

final WindowState win = new WindowState(this, session, client, token, parentWindow,
        appOp[0], attrs, viewVisibility, session.mUid, userId,
        session.mCanAddInternalSystemWindow);

Let's take a look at what is done during the instantiation of WindowState.
1. Assign relevant attributes according to the parameters passed by the client.
2. Obtain mBaseLayer according to the type of the current window. When adding WindowState to WindowToken, this value is used to determine the position of the added window in the WindowToken array.
3. Instantiate WindowStateAnimator, which will track the current WIndowState animation and surface operations.
Code path: framework/services/core/java/com/android/server/wm/WindowState.java

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
            int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
            PowerManagerWrapper powerManagerWrapper) {
    
    
        /*1.根据客户端传递过来的参数,对相关属性进行赋值*/
        //调用WindowState的父类WindowContainer构造方法,将WMS赋值给其父类属性mWmService
        super(service);
        //获取事务
        mTmpTransaction = service.mTransactionFactory.get();
        //将Session赋值给mSession
        mSession = s;
        //将与客户端通信的Binder赋值给mClient
        mClient = c;
        mAppOp = appOp;
        //将当前activity的token赋值给mToken
        mToken = token;
        //通过token,获取当前窗口对的ActivityRecord
        mActivityRecord = mToken.asActivityRecord();
        //赋值id
        mOwnerUid = ownerId;
        mShowUserId = showUserId;
        //是否可以添加系统窗口的标志位
        mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
        mWindowId = new WindowId(this);
        //布局参数赋值给mAttrs
        mAttrs.copyFrom(a);
        //将surfaceInsets赋值给mLastSurfaceInsets
        mLastSurfaceInsets.set(mAttrs.surfaceInsets);
        //将窗口可见性赋值给mViewVisibility 
        mViewVisibility = viewVisibility;
        //将窗口WindowManagerPolicy赋值给mPolicy 
        mPolicy = mWmService.mPolicy;
        mContext = mWmService.mContext;
        ......
        /*2.获取当前窗口的BaseLayer*/
        if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
    
    
        	......
        } else {
    
    
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            //当前为应用窗口所以mPolicy.getWindowLayerLw(this)获取值为2,即应用层级
            //TYPE_LAYER_MULTIPLIER为同一类型的多窗口保留空间
            //TYPE_LAYER_OFFSET将同一组窗口移动到同一层中其他窗口的上方或者下方
            mBaseLayer = mPolicy.getWindowLayerLw(this)
                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
            mSubLayer = 0;
            mIsChildWindow = false;
            mLayoutAttached = false;
            mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                    || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
            mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
        }
        ......
        /*3.新建windowStateAnimator,该类会跟踪当前WindowState的动画以及surface操作*/
        mWinAnimator = new WindowStateAnimator(this);
        //将透明度alpha赋值给mAlpha 
        mWinAnimator.mAlpha = a.alpha;
		......
    }
2.1.5 Add WindowState to WindowToken

In addWindow, add WindowState to WindowToken.
win.mToken.addWindow(win);
The specific process of adding WindowState to WindowToken:
1. Compare the WindowState.mBaseLayer to be added with the existing WindowState.mBaseLayer in WindowToken, and store it in the array from small to large mBaseLayer. If mBaseLayer If equal, the WindowState added later is placed at the end of the array.
Code path: framework/services/core/java/com/android/server/wm/WindowToken.java

 void addWindow(final WindowState win) {
    
    
        ProtoLog.d(WM_DEBUG_FOCUS,
                "addWindow: win=%s Callers=%s", win, Debug.getCallers(5));

        if (win.isChildWindow()) {
    
    
            // 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 */);

            // Layers could have been assigned before the surface was created, update them again
            reassignLayer(getSyncTransaction());
        }
        if (!mChildren.contains(win)) {
    
    
            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
            //调用WindowContainer.addChild方法
            addChild(win, mWindowComparator);
            mWmService.mWindowsChanged = true;
            // TODO: Should we also be setting layout needed here and other places?
        }
    }
 /**
   * Compares two child window of this token and returns -1 if the first is lesser than the
   * second in terms of z-order and 1 otherwise.
   */
  private final Comparator<WindowState> mWindowComparator =
          (WindowState newWindow, WindowState existingWindow) -> {
    
    
      final WindowToken token = WindowToken.this;
	  ......
	  //如果新窗口的mBaseLayer 不小于(大于等于)已经存在的WindowState的BaseLayer,则返回1,否则返回-1
      return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
  };
	/**
	 * Returns true if the new window is considered greater than the existing window in terms of
	 * z-order.
	 */
	protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
	        WindowState existingWindow) {
    
    
	    // New window is considered greater if it has a higher or equal base layer.
	    //此处可以发现比较的是两个窗口的mBaseLayer
	    return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
	}

Let’s take a look at the WindowContainer.addChild method.
Code path: framework/services/core/java/com/android/server/wm/WindowContainer.java

   /**
     * Adds the input window container has a child of this container in order based on the input
     * comparator.
     * @param child The window container to add as a child of this window container.
     * @param comparator Comparator to use in determining the position the child should be added to.
     *                   If null, the child will be added to the top.
     */
    @CallSuper
    protected void addChild(E child, Comparator<E> comparator) {
    
    
    	......
    	//记录插入数组的位置,若为-1则将windowState加入到后面
        int positionToAdd = -1;
        if (comparator != null) {
    
    
        	//判断当前WindowToken中WindowState的数量
        	//依次比较将要加入的窗口与已经存在的WindowState的BaseLayer
        	//mChildren越大放到数组最前面WindowToken
            final int count = mChildren.size();
            for (int i = 0; i < count; i++) {
    
    
            	//比较baseLayer,如果child大于列表中已经存在的,则需要返回1,否则返回-1
            	//新加入的的child大于mChildren.get(i)则返回1,小于则返回-1
            	//注:comparator比较器的逻辑见上面代码的mWindowComparator 
                if (comparator.compare(child, mChildren.get(i)) < 0) {
    
    
                	//记录当前要插入的位置
                    positionToAdd = i;
                    break;
                }
            }
        }
		//如果新加入的窗口大于现在所有窗口
        if (positionToAdd == -1) {
    
    
        	//将该窗口加入到列表最后
            mChildren.add(child);
        } else {
    
    
            mChildren.add(positionToAdd, child);
        }

        // Set the parent after we've actually added a child in case a subclass depends on this.
        //此处将child的mParent设置为this
        child.setParent(this);
    }

2. Set the mParent of WindowState to the WindowToken just now, and update the mTreeWeight of its Parent. mTreeWeight records the number of its child nodes.
Continue to look at WindowContainer.setParent, the parent class of WindowState.

    final protected void setParent(WindowContainer<WindowContainer> parent) {
    
    
    	//将当前WindowState的mParent设置为相应的WindowToken
        final WindowContainer oldParent = mParent;
        mParent = parent;

        if (mParent != null) {
    
    
        	//更新parent中的mTreeWeight属性
        	//mTreeWeight代表以parent的根节点的子树中的元素的数量
            mParent.onChildAdded(this);
        } else if (mSurfaceAnimator.hasLeash()) {
    
    
            mSurfaceAnimator.cancelAnimation();
        }
        if (!mReparenting) {
    
    
            onSyncReparent(oldParent, mParent);
            if (mParent != null && mParent.mDisplayContent != null
                    && mDisplayContent != mParent.mDisplayContent) {
    
    
                onDisplayChanged(mParent.mDisplayContent);
            }
            //计算显示layer
            onParentChanged(mParent, oldParent);
        }
    }

3. After adding WindowState to WindowToken, call the parent's assignChildLayers method to adjust the z-order of all its children. It mainly goes through the following steps:
initialize layer=0, which represents z-order.
Traverse the mChildren array and determine whether Children need to be raised to the top (determine the flag mNeedsZBoost). If not needed, call Children's assignLayer method to adjust its z-order to layer and set layer++. If necessary, execute the next cycle.
Traverse the mChildren array again to determine whether Children needs to be raised to the top. If necessary, call Children's assignLayer method to adjust its z-order to layer and set layer++. If not required, execute the next loop.
Continue to look at the onParentChanged method

/**
     * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
     * Supposed to be overridden and contain actions that should be executed after parent was set.
     */
    @Override
    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
    
    
        onParentChanged(newParent, oldParent, null);
    }

    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent,
            PreAssignChildLayersCallback callback) {
    
    
        ......
        if (mSurfaceControl == null) {
    
    
            // If we don't yet have a surface, but we now have a parent, we should
            // build a surface.
            //创建一个SurfaceControl来调整窗口的z-order
            createSurfaceControl(false /*force*/);
        } else {
    
    
       		......
        }
        ......
        // Either way we need to ask the parent to assign us a Z-order.
        //进入WindowToken的父类WindowContainer中,调整窗口的z-order
        mParent.assignChildLayers();
        scheduleAnimation();
    }
    
    void assignChildLayers() {
    
    
        assignChildLayers(getSyncTransaction());
        scheduleAnimation();
    }
    
    void assignChildLayers(Transaction t) {
    
    
    //分配给当前窗口的z-order,初始化为0
        int layer = 0;

        // We use two passes as a way to promote children which
        // need Z-boosting to the end of the list.
        //此处会以parent为根节点向下遍历到子节点,再从下到上依次进行处理
        for (int j = 0; j < mChildren.size(); ++j) {
    
    
            final WindowContainer wc = mChildren.get(j);
            wc.assignChildLayers(t);
            //needsZBoot是用来判断当前窗口是否应该提升到容器的顶部
            //若不需要提升到容器的顶部
            if (!wc.needsZBoost()) {
    
    
            	//调用WindowState的父类WindowContainer中的assignLayer
                wc.assignLayer(t, layer++);
            }
        }
        //处理需要提升到容器顶部的窗口
        for (int j = 0; j < mChildren.size(); ++j) {
    
    
            final WindowContainer wc = mChildren.get(j);
            if (wc.needsZBoost()) {
    
    
                wc.assignLayer(t, layer++);
            }
        }
        if (mOverlayHost != null) {
    
    
            mOverlayHost.setLayer(t, layer++);
        }
    }

4. In Children's assignLayer, it will first determine whether the layer to be adjusted this time is equal to its last layer. If it is not equal, nativeSetLayer will eventually be called to adjust its z-order.

    void assignLayer(Transaction t, int layer) {
    
    
        // Don't assign layers while a transition animation is playing
        // TODO(b/173528115): establish robust best-practices around z-order fighting.
        //如果正在执行Transaction,则不需要进行assignLayer
        if (mTransitionController.isPlaying()) return;
        //layer为此次要调整的z-order
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
        //如果需要调整
        if (mSurfaceControl != null && changed) {
    
    
        	//调用setLayer调整窗口的z-order
            setLayer(t, layer);
            //将mLastLayer调整为新的z-order
            mLastLayer = layer;
            mLastRelativeToLayer = null;
        }
    }
    
    protected void setLayer(Transaction t, int layer) {
    
    
        if (mSurfaceFreezer.hasLeash()) {
    
    
       		......
        } else {
    
    
            // Route through surface animator to accommodate that our surface control might be
            // attached to the leash, and leash is attached to parent container.
            //调用SurfaceAnimator中的setLayer
            mSurfaceAnimator.setLayer(t, layer);
        }
    }

Code path: framework/services/core/java/com/android/server/wm/SurfaceAnimator.java

    /**
     * Sets the layer of the surface.
     * <p>
     * When the layer of the surface needs to be adjusted, we need to set it on the leash if the
     * surface is reparented to the leash. This method takes care of that.
     */
    void setLayer(Transaction t, int layer) {
    
    
      	//调用SurfaceControl中的setlayer方法
        t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer);
    }

Code path: framework/core/java/android/view/SurfaceControl.java

        /**
         * Set the Z-order for a given SurfaceControl, relative to it's siblings.
         * If two siblings share the same Z order the ordering is undefined. Surfaces
         * with a negative Z will be placed below the parent surface.
         *
         * @param sc The SurfaceControl to set the Z order on
         * @param z The Z-order
         * @return This Transaction.
         */
        @NonNull
        public Transaction setLayer(@NonNull SurfaceControl sc,
                @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
    
    
            //调用调整layer
            checkPreconditions(sc);
            nativeSetLayer(mNativeObject, sc.mNativeObject, z);
            return this;
        }

2.2 Window position calculation

After WindowState is added to WindowToken and z-order is adjusted, the client will call WMS again to perform window layout.
Mainly do these three things:
1. Receive client request
2. Create SurfaceControl
3. Calculate window size and position

2.2.1 Receive client request

Similar to the calling process of the addWindow process, WindowManagerService.relayoutWindow is also called by the client through the Session.
First, let's take a look at what parameters the client passed to us.
window: It is the Binder for WMS to communicate with the client.
attrs: Layout attributes of the window. Layout the window based on the attributes provided by attrs.
requestWidth, requestHeight: window size requested by the client.
viewFlags: Visibility of the window. Including VISIBLE (0, view is visible), INVISIBLE (4, view is not visible, but still occupies layout space) GONE (8, view is not visible, does not occupy layout space) flags: Define some layout behaviors
.
outFrames: returned to the client, saving the position and size after relayout.
mergedConfiguration: related configuration information.
outSurfaceControl: surfaceControl returned to the client.
outInsetsState: used to save the status of all Insets in the system.
outActiveControls: InSetsSourceControl array.
outSyncSeqIdBundle: related to layout synchronization.
Session calls WMS.relayoutWindow to pass the parameters passed in by the client to WMS.
Code path: framework/services/core/java/com/android/server/wm/Session.java

    @Override
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags,
            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
    
    
        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                + Binder.getCallingPid());
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
        int res = mService.relayoutWindow(this, window, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                outActiveControls, outSyncSeqIdBundle);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                + Binder.getCallingPid());
        return res;
    }
2.2.2 relayoutWindow

In WMS.relayoutWindow, the following things are mainly done:
1. Obtain the WindowState created in the window addition stage from mWindowMap according to the IWindow passed by the client.
2. Set DisplayContent.mLayoutNeeded and shouldRelayout flags
3.Surface creation process.
4. Calculation of window size and status change of Surface.
Code path: framework/services/core/java/com/android/server/wm/WindowManagerService.java

    public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
    
    
		......
        synchronized (mGlobalLock) {
    
    
        	/*1.根据客户端传过来的Iwindow从mWindowMap中获取对应的WindowState*/
            final WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
    
    
                return 0;
            }
            //获取DisplayContent、DisplayPolicy以及WindowStateAnimator 
            final DisplayContent displayContent = win.getDisplayContent();
            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();

            WindowStateAnimator winAnimator = win.mWinAnimator;
            if (viewVisibility != View.GONE) {
    
    
            	//根据客户端请求的窗口大小设置WindowState的requestedWidth, requestedHeight
            	//并设置WindowState.mLayoutNeeded为true
                win.setRequestedSize(requestedWidth, requestedHeight);
            }
            ......
            //根据请求的宽带和高度窗口缩放比例
            win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);
            ......
            //获取原来window的可见性,此时为INVISIBLE
            final int oldVisibility = win.mViewVisibility;
            ......
            //代表现在没有surface但应该很快就有标志位
            win.mRelayoutCalled = true;
            win.mInRelayout = true;
            //将当前窗口的可见性有原来的INVISIBLE调整为VISIBLE
            win.setViewVisibility(viewVisibility);
            ProtoLog.i(WM_DEBUG_SCREEN_ON,
                    "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
                            viewVisibility, new RuntimeException().fillInStackTrace());
            /*2.1.将displayContent中的布局标志为mLayoutNeeded置为true*/
            win.setDisplayLayoutNeeded();
            win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;

            // We should only relayout if the view is visible, it is a starting window, or the
            // associated appToken is not hidden.
            /*2.2.判断是否允许relayout,此时为true*/
            //判断条件:view可见且(activityRecord不为空,或者布局类型为TYPE_APPLICATION_STARTING,或者窗口已经告诉客户端可以显示)
            final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
                    (win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                            || win.mActivityRecord.isClientVisible());
            ......
            // Create surfaceControl before surface placement otherwise layout will be skipped
            // (because WS.isGoneForLayout() is true when there is no surface.
            /*3.surface的创建流程*/
            if (shouldRelayout) {
    
    
                try {
    
    
                	//进入creatSurfaceControl开始创建SurfaceControl
                    result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                } catch (Exception e) {
    
    
                	......
                    return 0;
                }
            }

            // 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.
            /*4.窗口尺寸的计算以及Surface的状态变更*/
            //WindowSurfacePlacer在WMS初始化的时候创建
            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
            ......
            //填充计算好的frame返回给客户端,更新mergedConfiguration对象
            win.fillClientWindowFramesAndConfiguration(outFrames, mergedConfiguration,
                    false /* useLatestConfig */, shouldRelayout);

            // Set resize-handled here because the values are sent back to the client.
            win.onResizeHandled();
            ......
        }

        Binder.restoreCallingIdentity(origId);
        //返回result
        return result;
    }
2.2.3 Create SurfaceControl

Create SurfaceControl in relayoutWindow
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
There are two main things to do in WMS regarding the creation of SurfaceControl:
1. Call WindwoStateAnimator to perform the creation of specific SurfaceControl.
2. Assign the created SurfaceControl to the client's outSurfaceControl.
Code path: framework/services/core/java/com/android/server/wm/WindowManagerService.java

    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
    
    
        ......
        WindowSurfaceController surfaceController;
        try {
    
    
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
            /*
             * WindowStateAnimator用来帮助WindowState管理animator和surface基本操作的
             * 1.WMS将创建的surfaceContorl的操作交给windowAnimator来处理
             */
            surfaceController = winAnimator.createSurfaceLocked();
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        if (surfaceController != null) {
    
    
        	/*2.将WMS的SurfaceControl赋值给客户端的outSurfaceControl*/
            surfaceController.getSurfaceControl(outSurfaceControl);
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);

        } else {
    
    
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win);
            outSurfaceControl.release();
        }

        return result;
    }

Creating a SurfaceControl in WindowStateAnimator mainly goes through the following three steps:
1. Reset the Surface flag and change the mDrawState state to DRAW_PENDING.
2. Create a SurfaceControl by instantiating WindowSurfaceController.
3. Process the Surface flag and set it to true, indicating that the current WindowState already has a surface.
Code path: framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

   WindowSurfaceController createSurfaceLocked() {
    
    
        final WindowState w = mWin;
        
        //首先判断是否存在mSurfaceController
        if (mSurfaceController != null) {
    
    
            return mSurfaceController;
        }
		/*1.1.设置WindowState的mHasSurface设置为false*/
        w.setHasSurface(false);

        ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
		/*1.2.将WindowStateAnimator中的DrawState设置为DRAW_PENDING*/
        resetDrawState();

        mService.makeWindowFreezingScreenIfNeededLocked(w);

		/*1.3.将surface创建flag设置为hidden*/
        int flags = SurfaceControl.HIDDEN;
        //获取windowState的布局参数
        final WindowManager.LayoutParams attrs = w.mAttrs;

        // Set up surface control with initial size.
        try {
    
    
       	 	......
       	 	/*2.创建WindowSurfaceController*/
       	 	//attrs.getTitle().toString()为当前activity的全路径名
       	 	//format为位图格式
       	 	//flags为surface创建的标志位(如:HIDDED(0x04,surface创建为隐藏),SKIP_SCREENSHOT(0x040,截屏时跳过此图层将不会包含在非主显示器上),SECURE(0X080,禁止复制表面的内容,屏幕截图和次要的非安全显示将呈现黑色内容而不是surface内容)等)
       	 	//attrs.type为窗口类型
            mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
                    flags, this, attrs.type);
            mSurfaceController.setColorSpaceAgnostic((attrs.privateFlags
                    & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);

			/*3.将WindowState的hasSurface标志设置为true,标志着道歉WindowState已经有surface了*/
            w.setHasSurface(true);
            ......
		} catch (OutOfResourcesException e) {
    
    
			......
		} catch (Exception e) {
    
    
			......
        }
		......
        return mSurfaceController;
    }

The creation process of SurfaceControl is a typical builder mode.
Next, let’s take a look at the construction method of WindowSurfaceController.
Code path: framework/services/core/java/com/android/server/wm/WindowSurfaceController.java

WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
            int windowType) {
    
    
        //设置WindowStateAnimator
        mAnimator = animator;
		//窗口名
        title = name;
		//WMS对象
        mService = animator.mService;
        //WindowState对象
        final WindowState win = animator.mWin;
        //窗口类型
        mWindowType = windowType;
        //IWindowSession对象
        mWindowSession = win.mSession;

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
        //makeSurface最终会调用到DisplayContent的makeChildSurface方法,返回SurfaceControl.Builder
        final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl())
                .setName(name)
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
                .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
                .setCallsite("WindowSurfaceController");
        ......
        //获取SurfaceControl实例对象
        mSurfaceControl = b.build();

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }

Two key methods win.makeSurface() and b.build()
1. final SurfaceControl.Builder b = win.makeSurface()
Let’s take a look at win.makeSurface() first. There is no makeSurface() method in windowState, so the
code path of the makeSurface() method of its parent class WindowContainer is called: framework/services/core/java/com/android/server/wm/WindowContainer.java

    SurfaceControl.Builder makeSurface() {
    
    
        final WindowContainer p = getParent();
        return p.makeChildSurface(this);
    }
        /**
     * @param child The WindowContainer this child surface is for, or null if the Surface
     *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
     */
    SurfaceControl.Builder makeChildSurface(WindowContainer child) {
    
    
        final WindowContainer p = getParent();
        // Give the parent a chance to set properties. In hierarchy v1 we rely
        // on this to set full-screen dimensions on all our Surface-less Layers.
        return p.makeChildSurface(child)
                .setParent(mSurfaceControl);
    }

The makeChildSurface code path of DisplayContent will eventually be called
: framework/services/core/java/com/android/server/wm/DisplayContent.java

    @Override
    SurfaceControl.Builder makeChildSurface(WindowContainer child) {
    
    
    	//此时child为WindowState
    	//获取SurfaceSession,SurfaceSession的创建在Session.windowAddedLocked中,其最开始调用在WindowManagerService.addWindow中win.attach()中创建
        SurfaceSession s = child != null ? child.getSession() : getSession();
        //返回SurfaceControl.Builder
        final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(s).setContainerLayer();
        if (child == null) {
    
    
            return b;
        }
		//设置SurfaceControl.Builder的name以及parent
        return b.setName(child.getName())
                .setParent(mSurfaceControl);
    }

2. mSurfaceControl = b.build();
Let’s look at b.build() again, calling the build code path in SurfaceControl
: framework/core/java/android/view/SurfaceControl.java

	/**
	  * Construct a new {@link SurfaceControl} with the set parameters. The builder
	  * remains valid.
	  */
	 @NonNull
	 public SurfaceControl build() {
    
    
	 	//检查width以及height,初始都应该为0
	     if (mWidth < 0 || mHeight < 0) {
    
    
	         throw new IllegalStateException(
	                 "width and height must be positive or unset");
	     }
	     if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
    
    
	         throw new IllegalStateException(
	                 "Only buffer layers can set a valid buffer size.");
	     }
	
	     if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) {
    
    
	         setBLASTLayer();
	     }
	//创建SurfaceControl的实例
	     return new SurfaceControl(
	             mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
	             mLocalOwnerView, mCallsite);
	 }
	
   /**
	* @param session  The surface session, must not be null.
	* @param name     The surface name, must not be null.
	* @param w        The surface initial width.
	* @param h        The surface initial height.
	* @param flags    The surface creation flags.
	* @param metadata Initial metadata.
	* @param callsite String uniquely identifying callsite that created this object. Used for
	*                 leakage tracking.
	* @throws throws OutOfResourcesException If the SurfaceControl cannot be created.
	*/
	private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
	     SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
	     String callsite)
	             throws OutOfResourcesException, IllegalArgumentException {
    
    
	 if (name == null) {
    
    
	     throw new IllegalArgumentException("name must not be null");
	 }
	
	 mName = name;
	 mWidth = w;
	 mHeight = h;
	 mLocalOwnerView = localOwnerView;
	 //创建Parcel用来传递数据
	 Parcel metaParcel = Parcel.obtain();
	 try {
    
    
	   	......
	   	//调用native层
	     mNativeObject = nativeCreate(session, name, w, h, format, flags,
	             parent != null ? parent.mNativeObject : 0, metaParcel);
	 } finally {
    
    
	     metaParcel.recycle();
	 }
	 if (mNativeObject == 0) {
    
    
	     throw new OutOfResourcesException(
	             "Couldn't allocate SurfaceControl native object");
	 }
	 mNativeHandle = nativeGetHandle(mNativeObject);
	 mCloseGuard.openWithCallSite("release", callsite);
	}

After the constructor method of SurfaceControl is called, return to the previous page.
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);

2.2.4 Calculate window size and position

Calculating the window size and position in relayoutWindow
mWindowPlacerLocked.performSurfacePlacement(true /* force */);
This process is divided into three parts:
1. This part deals with the logic of the window layout loop.
2. This part handles the state change of Surface and the process of calling layoutWindowLw.
3. Calculate the window position size.

1. Handling window layout loops

performSurfacePlacement is an entry method that determines how the Surface of all windows is placed, how it is displayed, where it is displayed, and how large the display area is.
This method mainly sets the loop condition of the layout. When the mTraversalScheduled flag is true and loopCount is greater than 0. performSurfacePlacementLoop will be called to perform layout operations.
Code path: framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

    final void performSurfacePlacement(boolean force) {
    
    
        if (mDeferDepth > 0 && !force) {
    
    
            mDeferredRequests++;
            return;
        }
        //将循环的最大次数设置为6次
        int loopCount = 6;
        do {
    
    
        	//将该标志为设置为false
            mTraversalScheduled = false;
            //执行窗口布局操作
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        //只有当mTraversalScheduled为true且循环次数大于0时,才会再次循环执行布局
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

The performSurfacePlacementLoop method mainly does two things:
1. Call RootWindowContainer to perform layout operations on all windows,
2. Process the logic of whether to layout again. If the DisplayContent.mLayoutNeeded flag is true and the number of layout loops is less than 6, the mTraversalScheduled flag will be set to true, and performSurfacePlacementLoop will be called again in performSurfacePlacement.

    private void performSurfacePlacementLoop() {
    
    
    	//若当前已经进行布局操作,则无需重复调用直接返回
        if (mInLayout) {
    
    
            ......
            return;
        }
        ......
        //将该标志位置为true,表示正在处于布局过程中
        mInLayout = true;
        ......
        try {
    
    
        	/*1.调用RootWindowContainer的performSurfacePlacement()方法对所有窗口执行布局操作*/
            mService.mRoot.performSurfacePlacement();

            mInLayout = false;

            if (mService.mRoot.isLayoutNeeded()) {
    
    
            	/*2.若需要布局,且布局次数小于6次,则需要再次请求布局*/
                if (++mLayoutRepeatCount < 6) {
    
    
                	//该方法中会将mTraversalScheduled标志位设置位true
                    requestTraversal();
                } else {
    
    
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
    
    
                mLayoutRepeatCount = 0;
            }

            if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
    
    
                mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
                mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
            }
        } catch (RuntimeException e) {
    
    
            mInLayout = false;
            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
        }
    }
2. Handle all Surface state changes and the process of calling layoutWindowLw

mService.mRoot.performSurfacePlacement();
As mentioned above, the performSurfaceNoTrace() method is called in RootWindowContainer.performSurfacePlacement(). This method is the actual layout processing method. It mainly handles the following processes: 1.
If there is a focus change, update the focus.
2. Perform window size calculation, surface state change and other operations.
3. Change the Surface state to HAS_DRAWN to trigger the App to trigger the animation. This process will be analyzed in detail in finishingdrawing().
4. If the wallpaper changes, update the wallpaper.
5. Handle focus changes again.
6. If the size or position changes during the process, notify the client to relayout.
7. Destroy the invisible window
Code path: framework/services/core/java/com/android/server/wm/RootWindowContainer.java

    void performSurfacePlacement() {
    
    
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
    
    
        	//调用performSurfacePlacementNoTrace()
            performSurfacePlacementNoTrace();
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    // "Something has changed!  Let's make it correct now."
    // TODO: Super long method that should be broken down...
    void performSurfacePlacementNoTrace() {
    
    
    	......
    	/*1.如果有焦点变化,更新焦点*/
        if (mWmService.mFocusMayChange) {
    
    
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }
        ......
        
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        //开启事务,获取GlobalTransactionWrapper对象
        mWmService.openSurfaceTransaction();
        try {
    
    
        	/*2.执行窗口尺寸计算,surface状态变更等操作*/
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
    
    
            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");
            }
        }
		......
		/*3.将Surface状态变更为HAS_DRAWN,触发App触发动画。该过程在“2.3.3mDrawState变更为HAS_DRAW”流程中再详细分析*/
        checkAppTransitionReady(surfacePlacer);
        ......
        /*4.遍历所有DisplayContent,如果壁纸有变化,更新壁纸*/
        for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
    
    
            final DisplayContent displayContent = mChildren.get(displayNdx);
            //判断DisplayContent的壁纸是否需要改变
            if (displayContent.mWallpaperMayChange) {
    
    
                ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper may change!  Adjusting");
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                if (DEBUG_LAYOUT_REPEATS) {
    
    
                    surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
                            displayContent.pendingLayoutChanges);
                }
            }
        }
        /*5.在此处理焦点变化*/
        if (mWmService.mFocusMayChange) {
    
    
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                    false /*updateInputWindows*/);
        }
        ......
        /*6.如果过程中size或者位置变化,则通知客户端重新relayout*/
        handleResizingWindows();

        if (mWmService.mDisplayFrozen) {
    
    
            ProtoLog.v(WM_DEBUG_ORIENTATION,
                    "With display frozen, orientationChangeComplete=%b",
                    mOrientationChangeComplete);
        }
        if (mOrientationChangeComplete) {
    
    
            if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
    
    
                mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
                mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
            }
            mWmService.stopFreezingDisplayLocked();
        }

        // Destroy the surface of any windows that are no longer visible.
        /*7.销毁不可见的窗口*/
        i = mWmService.mDestroySurface.size();
        if (i > 0) {
    
    
            do {
    
    
                i--;
                WindowState win = mWmService.mDestroySurface.get(i);
                win.mDestroying = false;
                final DisplayContent displayContent = win.getDisplayContent();
                if (displayContent.mInputMethodWindow == win) {
    
    
                    displayContent.setInputMethodWindowLocked(null);
                }
                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
    
    
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
                win.destroySurfaceUnchecked();
            } while (i > 0);
            mWmService.mDestroySurface.clear();
        }
        ......
    }

In applySurfaceChangesTransaction();the method, its main execution is:
1. Watermark, StrictMode warning box and layout displayed by the simulator.
2. Traverse all DisplayContents and execute their applySurfaceChangesTransaction.
Let’s take a look at this method.

    private void applySurfaceChangesTransaction() {
    
    
        mHoldScreenWindow = null;
        mObscuringWindow = null;

        // TODO(multi-display): Support these features on secondary screens.
        /*1.水印、StrictMode警告框以及模拟器显示的布局*/
        //获取手机默认DisplayContent的信息
        final DisplayContent defaultDc = mWmService.getDefaultDisplayContentLocked();
        final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
        final int defaultDw = defaultInfo.logicalWidth;
        final int defaultDh = defaultInfo.logicalHeight;
        //布局水印
        if (mWmService.mWatermark != null) {
    
    
            mWmService.mWatermark.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
        }
        //布局StrictMode警告框
        if (mWmService.mStrictModeFlash != null) {
    
    
            mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction);
        }
        //布局模拟器显示覆盖
        if (mWmService.mEmulatorDisplayOverlay != null) {
    
    
            mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
                    mWmService.getDefaultDisplayRotation(), mDisplayTransaction);
        }
        /*2.遍历RootWindowContainer下所有DisplayContent执行其applySurfaceChangesTransaction()*/
        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
    
    
            final DisplayContent dc = mChildren.get(j);
            dc.applySurfaceChangesTransaction();
        }

        // Give the display manager a chance to adjust properties like display rotation if it needs
        // to.
        mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
        SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
    }

Next, continue tracking. dc.applySurfaceChangesTransaction();
This method mainly
1. Traverses all windows and calculates the layout size of the window. For the specific process, see performLayoutNoTrace. (Main tracking point)
2.The state of the surface changes. (See " 2.3.3mDrawState changed to HAS_DRAW" process ")
3. Process the position, size and display of the surface. (See " 2.3.4 show Surface" process ")
Code path: framework/services/core/java/com/ android/server/wm/DisplayContent.java

    void applySurfaceChangesTransaction() {
    
    
    	//获取WindowSurfacePlacer 
        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
        ......
        // Perform a layout, if needed.
        /*1.执行布局,该方法最终会调用performLayoutNoTrace,计算窗口的布局参数*/
        performLayout(true /* initial */, false /* updateInputWindows */);
        ......
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
        try {
    
    
        	/*2.遍历所有窗口,主要是改变surface的状态。见“2.3.3mDrawState变更为HAS_DRAW”流程*/
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        /*3.处理各个surface的位置、大小以及是否要在屏幕上显示等。后面finishDrawing()流程中再跟踪*/
        prepareSurfaces();
        ......
    }

Continue tracking. performLayout(true /* initial */, false /* updateInputWindows */);
This method mainly calls the performLayoutNoTrace() method. First, it determines the layout flag mLayoutNeeded, which is set to true in WMS.relayoutWindow.
If false, it will be returned directly and no layout operation will be performed.
If true, it traverses the parent window and child window for layout. For now, we only analyze the layout operation of the parent window and view mPerformLayout.

    void performLayout(boolean initial, boolean updateInputWindows) {
    
    
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
        try {
    
    
        	//调用performLayoutNoTrace
            performLayoutNoTrace(initial, updateInputWindows);
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
    
    
   		 /*1.判断是否需要布局,不需要则直接返回,即判断布局标志位mLayoutNeeded是否为true*/
        if (!isLayoutNeeded()) {
    
    
            return;
        }
        //将DisplayContent.mLayoutNeeded属性置为false
        clearLayoutNeeded();
        ......
        // First perform layout of any root windows (not attached to another window).
        /*2.对所有顶级窗口进行布局*/
        //最终会回调mPerformLayout
        forAllWindows(mPerformLayout, true /* traverseTopToBottom */);

        // 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.
        /*3.处理子窗口的布局*/
        //最终会回调mPerformLayoutAttached
        forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);
        ......
    }

forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);
mPerformLayout will be executed when each window under DisplayContent is traversed. This method will set the WindowState.mLayoutNeeded flag to false and hand over the specific layout operation to DisplayPolicy for processing. See "3. Calculate the window position and size ".

    private final Consumer<WindowState> mPerformLayout = w -> {
    
    
    	//如果当前窗口为子窗口则直接返回
        if (w.mLayoutAttached) {
    
    
            return;
        }

        // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
        // wasting time and funky changes while a window is animating away.
        //先判断当前窗口是否会不可见
        final boolean gone = w.isGoneForLayout();
        ......

        // If this view is GONE, then skip it -- keep the current frame, and let the caller know
        // so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,
        // since that means "perform layout as normal, just don't display").
        if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {
    
    
            if (mTmpInitial) {
    
    
            	//设置窗口布局WindowFrames.mContentChanged为false
                w.resetContentChanged();
            }
            w.mSurfacePlacementNeeded = true;
            //此处将WindowState.mLayoutNeeded标志位置为false
            w.mLayoutNeeded = false;
            //判断当前窗口是否是第一次布局
            final boolean firstLayout = !w.isLaidOut();
            //调用DisplayPolicy.layoutWindowLw进行布局,根据DisplayFrames对象对WindowState.mWindowFrames中的各个Rect对象属性进行确定
            getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
            w.mLayoutSeq = mLayoutSeq;

            // If this is the first layout, we need to initialize the last frames and inset values,
            // as otherwise we'd immediately cause an unnecessary resize.
            if (firstLayout) {
    
    
                // The client may compute its actual requested size according to the first layout,
                // so we still request the window to resize if the current frame is empty.
                if (!w.getFrame().isEmpty()) {
    
    
                    w.updateLastFrames();
                }
                w.onResizeHandled();
            }

            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
    };
3. Calculate window position size

getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
layoutWindowLw mainly does the following three things
: 1. First, it will obtain DisplayFrames: DisplayContent is created when it is newly created, and the internal data is provided by the screen.
2. Secondly, call WindowLayout.computeFrames to calculate the window layout size.
3. Finally, call WindowState.setFrames to assign the calculated layout parameters to the windowFrames of the current window.
Code path: framework/services/core/java/com/android/server/wm/DisplayPolicy.java

    /**
     * Called for each window attached to the window manager as layout is proceeding. The
     * implementation of this function must take care of setting the window's frame, either here or
     * in finishLayout().
     *
     * @param win The window being positioned.
     * @param attached For sub-windows, the window it is attached to; this
     *                 window will already have had layoutWindow() called on it
     *                 so you can use its Rect.  Otherwise null.
     * @param displayFrames The display frames.
     */
    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
    
    
    	//判断是否需要跳过布局
        if (win.skipLayout()) {
    
    
            return;
        }

        // This window might be in the simulated environment.
        // We invoke this to get the proper DisplayFrames.
        /*1.获取DisplayFrames*/
        displayFrames = win.getDisplayFrames(displayFrames);
        //获取某个方向的窗口布局参数
        final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
        //null
        final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;

        // If this window has different LayoutParams for rotations, we cannot trust its requested
        // size. Because it might have not sent its requested size for the new rotation.
        final boolean trustedSize = attrs == win.mAttrs;
        final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
        final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
        /*2.调用WindowLayout.computeFrames计算窗口布局大小*/
        mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
                sTmpClientFrames);
        /*3.将计算的布局参数赋值给windowFrames*/
        win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
    }

Let’s take a look at computeFrames first

mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
                sTmpClientFrames);

Leave a hole

Let’s take a look at setFrames again

 win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);

Leave a hole

2.3 Window status refresh

After the application side executes measure-layout-draw, it will call WMS.finishDrawingWindow to process the status change of the Surface and show the Surface.
First, let’s take a look at the flow chart of this stage to have a preliminary understanding of the entire process.
Divide the entire process into three parts:
1. WMS accepts the client request, updates mDrawState to COMMIT_DRAW_PENDING, and requests the window layout.
2.mDrawState is updated to HAS_DRAW and the window layout is requested again.
3. Execute show Surface.

2.3.1 Accept client requests

Code path: framework/services/core/java/com/android/server/wm/Session.java

    @Override
    public void finishDrawing(IWindow window,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
    
    
        if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
        //调用WMS中的finishDrawingWindow处理
        mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
    }
2.3.2 finishDrawingWindow

1. In WMS, obtain the corresponding WindowState in mWindowMap according to the client's Binder.
2. Call WindowState.finishDrawing to perform the state change of mDrawState.
3. Set the WindowState.mLayoutNeeded flag to true.
4. Request a layout refresh.
Code path: framework/services/core/java/com/android/server/wm/WindowManagerService.java

    void finishDrawingWindow(Session session, IWindow client,
            @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
    
    
        if (postDrawTransaction != null) {
    
    
            postDrawTransaction.sanitize();
        }

        final long origId = Binder.clearCallingIdentity();
        try {
    
    
            synchronized (mGlobalLock) {
    
    
            	/*1.根据客户端的Binder在mWindowMap中获取对应的WindowState*/
                WindowState win = windowForClientLocked(session, client, false);
                ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
                        win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
                /*2.finishDrawing执行mDrawState的状态更变*/
                if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
    
    
                    if (win.hasWallpaper()) {
    
    
                        win.getDisplayContent().pendingLayoutChanges |=
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                    /*3.将当前WindowState.mLayoutNeeded置为true*/
                    //该标志位是判断是否进行窗口大小尺寸计算的条件之一
                    win.setDisplayLayoutNeeded();
                    /*4.请求进行布局刷新*/
                    mWindowPlacerLocked.requestTraversal();
                }
            }
        } finally {
    
    
            Binder.restoreCallingIdentity(origId);
        }
    }
1.mDrawState state change

Call the finishDrawing method of WindowState in finishDrawingWindow.
win.finishDrawing(postDrawTransaction, seqId)
This method mainly calls finishDrawingLocked of WindowStateAnimator to change the state.
Code path: framework/services/core/java/com/android/server/wm/WindowState.java

   boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
    
    
   		......
   		//调用WindowStateAnimator.finishDrawingLocked,会将mDrawState的状态更改为COMMIT_DRAW_PENDING
        final boolean layoutNeeded =
                mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
        mClientWasDrawingForSync = false;
        // We always want to force a traversal after a finish draw for blast sync.
        return !skipLayout && (hasSyncHandlers || layoutNeeded);
    }

Let's continue to look at the finishDrawingLocked() method in WindowStateAnimator.
First, determine whether the state of mDrawState is DRAW_PENDING. When we create the SurfaceControl, we will update the mDrawState state to DRAW_PENDING. So next adjust the status to COMMIT_DRAW_PENDING.
Code path: framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

    boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction,
            boolean forceApplyNow) {
    
    
        ......
        boolean layoutNeeded = false;

        if (mDrawState == DRAW_PENDING) {
    
    
        	......
        	//如果当前状态为DRAW_PENDING,则将mDrawState更变为COMMIT_DRAW_PENDING
            mDrawState = COMMIT_DRAW_PENDING;
            layoutNeeded = true;
        }
        ......
        return layoutNeeded;
    }
2. Request layout refresh

When requesting layout refresh in finishDrawingWindow,
mWindowPlacerLocked.requestTraversal();
requestTraversal mainly does two things:
1. First, set the traversal flag mTraversalSchedule to true.
2. Secondly send the handle message mPerformSurfacePlacement

    void requestTraversal() {
    
    
    	//判断遍历标志mTraversalScheduled是否为true
        if (mTraversalScheduled) {
    
    
            return;
        }

        // Set as scheduled even the request will be deferred because mDeferredRequests is also
        // increased, then the end of deferring will perform the request.
        //将遍历标志位置为true
        mTraversalScheduled = true;
        if (mDeferDepth > 0) {
    
    
            mDeferredRequests++;
            if (DEBUG) Slog.i(TAG, "Defer requestTraversal " + Debug.getCallers(3));
            return;
        }
        //发送handle消息,处理消息会调用mPerformSurfacePlacement
        mService.mAnimationHandler.post(mPerformSurfacePlacement);
    }

mPerformSurfacePlacement will create a new thread to call performSurfacePlacement.
We talked about the performSurfacePlacement method when we talked about relayoutWindow-related processes. This is the entrance to perform layout traversal. You can review [ 2.2.4 "1. Processing window layout loop" in Calculating window size and position ]

    private class Traverser implements Runnable {
    
    
        @Override
        public void run() {
    
    
            synchronized (mService.mGlobalLock) {
    
    
            	//调用执行performSurfacePlacement
                performSurfacePlacement();
            }
        }
    }

    private final Traverser mPerformSurfacePlacement = new Traverser();
    
    final void performSurfacePlacement(boolean force) {
    
    
    	//当mDeferDepth大于0且force为false时,则将延迟布局请求数+1,并直接返回
        if (mDeferDepth > 0 && !force) {
    
    
            mDeferredRequests++;
            return;
        }
        //将循环的最大次数设置为6次
        int loopCount = 6;
        do {
    
    
        	//将该标志为设置为false
            mTraversalScheduled = false;
            //执行窗口布局操作
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        //只有当mTraversalScheduled为true且循环次数大于0时,才会再次循环执行布局
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

    private void performSurfacePlacementLoop() {
    
    
    	//若当前已经进行布局操作,则无需重复调用直接返回
        if (mInLayout) {
    
    
            ......
            return;
        }
        ......
        //将该标志位置为true,表示正在处于布局过程中
        mInLayout = true;
        ......
        try {
    
    
        	/*1.调用RootWindowContainer的performSurfacePlacement()方法对所有窗口执行布局操作*/
            mService.mRoot.performSurfacePlacement();

            mInLayout = false;

            if (mService.mRoot.isLayoutNeeded()) {
    
    
            	/*2.若需要布局,且布局次数小于6次,则需要再次请求布局*/
                if (++mLayoutRepeatCount < 6) {
    
    
                	//该方法中会将mTraversalScheduled标志位设置位true
                    requestTraversal();
                } else {
    
    
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
    
    
                mLayoutRepeatCount = 0;
            }

            if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
    
    
                mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
                mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
            }
        } catch (RuntimeException e) {
    
    
            mInLayout = false;
            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
        }
    }

Code path: framework/services/core/java/com/android/server/wm/RootWindowContainer.java

    void performSurfacePlacement() {
    
    
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
    
    
        	//调用performSurfacePlacementNoTrace()
            performSurfacePlacementNoTrace();
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    // "Something has changed!  Let's make it correct now."
    // TODO: Super long method that should be broken down...
    void performSurfacePlacementNoTrace() {
    
    
    	......
    	/*1.如果有焦点变化,更新焦点*/
        if (mWmService.mFocusMayChange) {
    
    
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }
        ......
        
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        //开启事务,获取GlobalTransactionWrapper对象
        mWmService.openSurfaceTransaction();
        try {
    
    
        	/*2.执行窗口尺寸计算,surface状态变更等操作*/
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
    
    
            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");
            }
        }
		......
		/*3.将Surface状态变更为HAS_DRAWN,触发App触发动画。该过程在“2.3.3mDrawState变更为HAS_DRAW”流程中再详细分析*/
        checkAppTransitionReady(surfacePlacer);
        ......
        /*4.遍历所有DisplayContent,如果壁纸有变化,更新壁纸*/
        for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
    
    
            final DisplayContent displayContent = mChildren.get(displayNdx);
            //判断DisplayContent的壁纸是否需要改变
            if (displayContent.mWallpaperMayChange) {
    
    
                ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper may change!  Adjusting");
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                if (DEBUG_LAYOUT_REPEATS) {
    
    
                    surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
                            displayContent.pendingLayoutChanges);
                }
            }
        }
        /*5.在此处理焦点变化*/
        if (mWmService.mFocusMayChange) {
    
    
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                    false /*updateInputWindows*/);
        }
        ......
        /*6.如果过程中size或者位置变化,则通知客户端重新relayout*/
        handleResizingWindows();

        if (mWmService.mDisplayFrozen) {
    
    
            ProtoLog.v(WM_DEBUG_ORIENTATION,
                    "With display frozen, orientationChangeComplete=%b",
                    mOrientationChangeComplete);
        }
        if (mOrientationChangeComplete) {
    
    
            if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
    
    
                mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
                mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
            }
            mWmService.stopFreezingDisplayLocked();
        }

        // Destroy the surface of any windows that are no longer visible.
        /*7.销毁不可见的窗口*/
        i = mWmService.mDestroySurface.size();
        if (i > 0) {
    
    
            do {
    
    
                i--;
                WindowState win = mWmService.mDestroySurface.get(i);
                win.mDestroying = false;
                final DisplayContent displayContent = win.getDisplayContent();
                if (displayContent.mInputMethodWindow == win) {
    
    
                    displayContent.setInputMethodWindowLocked(null);
                }
                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
    
    
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
                win.destroySurfaceUnchecked();
            } while (i > 0);
            mWmService.mDestroySurface.clear();
        }
        ......
    }

Here we mainly focus on applySurfaceChangesTransaction();andcheckAppTransitionReady(surfacePlacer);

* The difference between window position calculation and window status refresh process

It can be found that both the window position calculation process and the window status refresh process call performSurfacePlacement. The main differences between the two calls are: 1. The window status refresh process
calls mApplySurfaceChangesTransaction in DisplayContent.applySurfaceChangesTransaction to process the mDrawState state.
2. The window state refresh process calls checkAppTransitionReady in RootWindowContainer.performSurfacePlacementNoTrace, processes the mDrawState state change to HAS_DRAWN, and triggers the Activity transition animation.
3. The window status refresh process will call requestTraversal in WindowSurfacePlacementLoop.performSurfacePlacementLoop to request layout again.
4. The window status refresh process calls prepareSurfaces() in DisplayContent.applySurfaceChangesTransaction to handle the position, size and display of the surface.

2.3.3 mDrawState changed to HAS_DRAW
1.mApplySurfaceChangesTransaction

RootWindowContainer's applySurfaceChangesTransaction() method will eventually call the applySurfaceChangesTransaction() method called in DisplayContent, and we then track mApplySurfaceChangesTransaction in this method.
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
If there is a surfaceControl in the current WindowState, enter the WindowStateAnimator to change the state of mDrawState.
Code path: framework/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
    
    
	    ......
        //首先判断当前windowState的是否有surfaceControl
        if (w.mHasSurface) {
    
    
            // Take care of the window being ready to display.
            //调用WindowStateAnimator的commitFinishDrawingLocked()方法
            final boolean committed = winAnimator.commitFinishDrawingLocked();
            ......
        }
        ......
    };

Continue to look at the commitFinishDrawingLocked() method of WindowStateAnimator.
final boolean committed = winAnimator.commitFinishDrawingLocked();
1. Filter the status of mDrawState. Non-COMMIT_DRAW_PENDING and READY_TO_SHOW will be returned directly.
2. At this time, our mDrawState has updated the status to COMMIT_DRAW_PENDING in " [2.3.2 finishDrawingWindow] ", so change it to READY_TO_SHOW here.
Code path: framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

    // This must be called while inside a transaction.
    boolean commitFinishDrawingLocked() {
    
    
    	//非COMMIT_DRAW_PENDING和READY_TO_SHOW则直接返回
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
    
    
            return false;
        }
        ProtoLog.i(WM_DEBUG_ANIM, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
                mSurfaceController);
        //将状态更变为READY_TO_SHOW
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        //如果ActivityRecord为空,或者canShowWindows()为true,或者窗口类型为启动窗口,则直接进入到WindowState.performShowLocked()流程
        //进入performShowLocked()流程后mDrawState更新HAS_DRAWN
        //由于非这三种情况最终也会调用到performShowLocked(),因此下面这种情况我们暂不讨论
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
    
    
            result = mWin.performShowLocked();
        }
        return result;
    }
2.checkAppTransitionReady()

Here we continue to track the checkAppTransitionReady() method in the RootWindowContainer.performSurfacePlacementNoTrace() method.
checkAppTransitionReady(surfacePlacer);
This method will traverse all DisplayContents and process the filter animation of the activity. Here we only track the relevant code code path for mDrawState state changes
: framework/services/core /java/com/android/server/wm/RootWindowContainer.java

    private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
    
    
        // Trace all displays app transition by Z-order for pending layout change.
        for (int i = mChildren.size() - 1; i >= 0; --i) {
    
    
            final DisplayContent curDisplay = mChildren.get(i);

            // If we are ready to perform an app transition, check through all of the app tokens
            // to be shown and see if they are ready to go.
            //检查所有要显示的app token,是否已经准备就绪
            if (curDisplay.mAppTransition.isReady()) {
    
    
                // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
                curDisplay.mAppTransitionController.handleAppTransitionReady();
                if (DEBUG_LAYOUT_REPEATS) {
    
    
                    surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
                            curDisplay.pendingLayoutChanges);
                }
            }
            ......
        }
    }

Call the handleAppTransitionReady() method of AppTransitionController. This method mainly handles the transition animation of the activity. However, when applying the transition animation, it also does the following things: 1.
Call handleClosingApps and handleOpeningApps respectively to make the visibility of the Activity to be closed and the Activity to be opened renew.
2. Due to the change in the visibility of the activity, set DisplayContent.mLayoutNeeded to true. This flag is used in DisplayContent.performLayoutNoTrace to determine whether to refresh all windows under the current Displaycontent.
Code path: framework/services/core/java/com/android/server/wm/AppTransitionController.java

    /**
     * Handle application transition for given display.
     */
    void handleAppTransitionReady() {
    
    
    	......
        try {
    
    
        	//应用app transition动画
            applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp,
                    voiceInteraction);
            /*1.1处理closing activity可见性*/
            handleClosingApps();
            /*1.2处理opening actvity可见性*/
            handleOpeningApps();
            ......
        } finally {
    
    
            mService.mSurfaceAnimationRunner.continueStartingAnimations();
        }
        ......

        // This has changed the visibility of windows, so perform
        // a new layout to get them all up-to-date.
        /*2.由于activity的可见性变更,将DisplayContent.mLayoutNeeded标志位置为true*/
        mDisplayContent.setLayoutNeeded();
        ......
    }

Let's first look at handleClosingApps().
The main function of this method is to set the mVisible flag of all activities that are about to close to false. This flag is one of the conditions for determining whether to show surface in subsequent prepareSurfaces.

   private void handleClosingApps() {
    
    
        final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
        final int appsCount = closingApps.size();

        for (int i = 0; i < appsCount; i++) {
    
    
            final ActivityRecord app = closingApps.valueAt(i);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", app);
            //设置activity的可见性,将mVisible设置为false
            app.commitVisibility(false /* visible */, false /* performLayout */);
            app.updateReportedVisibilityLocked();
            // Force the allDrawn flag, because we want to start
            // this guy's animations regardless of whether it's
            // gotten drawn.
            //强制将allDrawn设置为true
            app.allDrawn = true;
            ......
        }
    }

Look again, similar to handleClosingApps, it mainly handles two things:
1. Set the mVisible flag of all activities that are about to be opened to true.
2. Call ActivityRecord.showAllWindowsLocked(), which will eventually call WindowState.performShowLocked() for processing. mDrawState state change

    private void handleOpeningApps() {
    
    
        final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
        final int appsCount = openingApps.size();

        for (int i = 0; i < appsCount; i++) {
    
    
            final ActivityRecord app = openingApps.valueAt(i);
            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
            /*1.设置activity的可见性,将mVisible设置为true*/
            app.commitVisibility(true /* visible */, false /* performLayout */);
            ......
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                    ">>> OPEN TRANSACTION handleAppTransitionReady()");
            //开启事务
            mService.openSurfaceTransaction();
            try {
    
    
            	/*2.此方法最终会调用到WindowState.performShowLocked*/
                app.showAllWindowsLocked();
            } finally {
    
    
			//关闭事务
            mService.closeSurfaceTransaction("handleAppTransitionReady");
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                        "<<< CLOSE TRANSACTION handleAppTransitionReady()");
            }
            ......
        }
    }

app.commitVisibility(true /* visible */, false /* performLayout */);
First call the howAllWindowsLocked()
code path of ActivityRecord: framework/services/core/java/com/android/server/wm/ActivityRecord.java

    /**
     * This must be called while inside a transaction.
     */
    void showAllWindowsLocked() {
    
    
        forAllWindows(windowState -> {
    
    
            if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
            windowState.performShowLocked();
        }, false /* traverseTopToBottom */);
    }

windowState.performShowLocked();
Then call performShowLocked() of WindowState
to change the status of mDrawState from READY_TO_SHOW to HAS_DRAW
Code path: framework/services/core/java/com/android/server/wm/WindowState.java

    // This must be called while inside a transaction.
    boolean performShowLocked() {
    
    
    	......
		//获取WindowStateAnimator.mDrawState
        final int drawState = mWinAnimator.mDrawState;
        //这里判断(drawState 状态为HAS_DRAWN 或者READY_TO_SHOW)且ActivityRecord不为空
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
    
    
        	//窗口类型不为启动窗口
            if (mAttrs.type != TYPE_APPLICATION_STARTING) {
    
    
                mActivityRecord.onFirstWindowDrawn(this);
            } else {
    
    
                mActivityRecord.onStartingWindowDrawn();
            }
        }
		//如果当前mDrawState的状态不为READY_TO_SHOW ,则直接返回
        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
    
    
            return false;
        }
        ......
        // Force the show in the next prepareSurfaceLocked() call.
        mWinAnimator.mLastAlpha = -1;
        ProtoLog.v(WM_DEBUG_ANIM, "performShowLocked: mDrawState=HAS_DRAWN in %s", this);
        //设置mDrawState的状态为HAS_DRAWN
        mWinAnimator.mDrawState = HAS_DRAWN;
        mWmService.scheduleAnimationLocked();
        ......
        return true;
    }
3. Request layout again

Go back to WindowSurfacePlacer and request layout again through requestTraversals(). This method sets the mTraversalScheduled flag to true. There are two judgment conditions:
1. Traverse all DisplayContent.mLayoutNeeded flags to see if they are true. (Since the AppTransitionController.handleAppTransitionReady stage has set mLayoutNeeded to true, this condition is true)
2. The layout cannot be repeated more than 6 times, and this condition is also true. (Because this is just the first layout)
Code path: framework/services/core/java/com/android/server/wm/WindowSurfacePlacer.java

    private void performSurfacePlacementLoop() {
    
    
    	......
        try {
    
    
        	......
        	/*1.遍历所有DisplayContent.mLayoutNeeded标志位是否为true*/
            if (mService.mRoot.isLayoutNeeded()) {
    
    
            	/*2.如果需要布局,且布局次数小于6次,则需要再次请求布局*/
                if (++mLayoutRepeatCount < 6) {
    
    
                	//该方法中会将mTraversalScheduled标志位设置位true
                    requestTraversal();
                } else {
    
    
                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                    mLayoutRepeatCount = 0;
                }
            } else {
    
    
                mLayoutRepeatCount = 0;
            }
            ......
        } catch (RuntimeException e) {
    
    
        ......
        }
    }

Next, enter the second layout loop , whose main purpose is to show surface

2.3.4 show Surface

In the second loop, we mainly focus on prepareSurfaces() called by the applySurfaceChangesTransaction() method in DisplayContent.

This method will eventually call the root container WindowContainer to traverse prepareSurfaces in all subcontainers.
Code path: framework/services/core/java/com/android/server/wm/DisplayContent.java

    @Override
    void prepareSurfaces() {
    
    
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
        try {
    
    
        	//获取事务
            final Transaction transaction = getPendingTransaction();
            //调用其父类方法
            super.prepareSurfaces();

            // TODO: Once we totally eliminate global transaction we will pass transaction in here
            //       rather than merging to global.
            SurfaceControl.mergeToGlobalTransaction(transaction);
        } finally {
    
    
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

The parent class that calls its parent class method super.prepareSurfaces();
DisplayContent is WindowContainer
code path: framework/services/core/java/com/android/server/wm/WindowContainer.java

    void prepareSurfaces() {
    
    
        // If a leash has been set when the transaction was committed, then the leash reparent has
        // been committed.
        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
        //调用所有子容器中的prepareSurfaces
        for (int i = 0; i < mChildren.size(); i++) {
    
    
            mChildren.get(i).prepareSurfaces();
        }
    }

mChildren.get(i).prepareSurfaces();In WindowState.prepareSurfaces, two aspects of work are mainly done.
1. Set the surface position of left and top calculated in mWindowFrames, and adjust the window proportion.
2. To control the visibility of the surface, view the WindowStateAnimator.prepareSurfaceLocked
code path: framework/services/core/java/com/android/server/wm/WindowState.java

    void prepareSurfaces() {
    
    
        mIsDimming = false;
        applyDims();
        //实际调用的是其父类WindowContainer的方法
        /*1.最终调用自身的updateSurfacePosition()(自身有重写该方法)计算surface的位置*/
        updateSurfacePositionNonOrganized();
        // Send information to SurfaceFlinger about the priority of the current window.
        updateFrameRateSelectionPriorityIfNeeded();
        //更新窗口比例
        updateScaleIfNeeded();

		/*2.控制surface的可见性,调用WindowStateAnimator的prepareSurfaceLocked()方法*/
        mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
        super.prepareSurfaces();
    }
    
    @Override
    @VisibleForTesting
    void updateSurfacePosition(Transaction t) {
    
    
        if (mSurfaceControl == null) {
    
    
            return;
        }

		......
        mSurfacePlacementNeeded = false;
        //将mSurfacePosition的left以及top设置mWindowFrames中计算出来的left以及top,并根据parent进行偏移
        transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
                mSurfacePosition);
		//根据壁纸的比例对SurfacePosition进行调整
        if (mWallpaperScale != 1f) {
    
    
            final Rect bounds = getLastReportedBounds();
            Matrix matrix = mTmpMatrix;
            matrix.setTranslate(mXOffset, mYOffset);
            matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
                    bounds.exactCenterY());
            matrix.getValues(mTmpMatrixArray);
            mSurfacePosition.offset(Math.round(mTmpMatrixArray[Matrix.MTRANS_X]),
                Math.round(mTmpMatrixArray[Matrix.MTRANS_Y]));
        } else {
    
    
            mSurfacePosition.offset(mXOffset, mYOffset);
        }
        ......
    }

mWinAnimator.prepareSurfaceLocked(getSyncTransaction());Call the prepareSurfaceLocked() method of WindowStateAnimator, which actually handles the logic of triggering surface show. Mainly divided into two parts.
1. Apply the calculated alpha to the current surface.
2. Determine whether to call showSurfaceRobustlyLocked to show the surface.
Code path: framework/services/core/java/com/android/server/wm/WindowStateAnimator.java

   void prepareSurfaceLocked(SurfaceControl.Transaction t) {
    
    
        final WindowState w = mWin;
        //首先判断是否有SurfaceControl
        if (!hasSurface()) {
    
    
        	......
            return;
        }
		//设置mShowAlpha
        computeShownFrameLocked();

		//判断parentWindow是否hidden,或者当前窗口是否on-screen
        if (w.isParentWindowHidden() || !w.isOnScreen()) {
    
    
        	......
        } else if (mLastAlpha != mShownAlpha
                || mLastHidden) {
    
    
            mLastAlpha = mShownAlpha;
            ProtoLog.i(WM_SHOW_TRANSACTIONS,
                    "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
                    mSurfaceController, mShownAlpha, w.mHScale, w.mVScale, w);
            /*1.设置surface的alpha*/
            boolean prepared =
                mSurfaceController.prepareToShowInTransaction(t, mShownAlpha);
            //如果当前状态为HAS_DRAWN
            if (prepared && mDrawState == HAS_DRAWN) {
    
    
                if (mLastHidden) {
    
    
                /*2.触发show surface*/
                    if (showSurfaceRobustlyLocked(t)) {
    
    
                        mAnimator.requestRemovalOfReplacedWindows(w);
                        //设置mLastHidden为false
                        mLastHidden = false;
                        .......
                    } else {
    
    
                        w.setOrientationChanging(false);
                    }
                }
            }
        } else {
    
    
            if (mWin.isAnimating(TRANSITION | PARENTS)) {
    
    
                ProtoLog.v(WM_DEBUG_ANIM, "prepareSurface: No changes in animation for %s", this);
            }
        }

		......
    }

From the above code, we can see that the judgment conditions for triggering showSurfaceRobustlyLocked are as follows:
1.w.isParentWindowHidden judges whether the mHidden of its parent is true. At this time, if the current window has no parent, it directly returns false.
2.w.isOnScreen, judges whether the current window On the screen, if the window mVisible is true or animation is running before it becomes invisible, it is judged to be on the screen. We set mVisible of the current window to true in the AppTransitionController.handleAppTransitionReady stage of the last layout, so w.isOnScreen returns true.
3.mLastAlpha != mShownAlpha and mLastHidden satisfy one of them. Here we analyze mLastHidden. This flag will be set to true when creating a SurfaceControl or hide surface. Because the current window has just been created, mLastHidden is true.
After the above judgment, we can conclude that we successfully triggered showSurfaceRobustlyLocked
and then passed the request for show SurfaceControl to WindowSurfaceController through WindowStateAnimator.

    /**
     * Have the surface flinger show a surface, robustly dealing with
     * error conditions.  In particular, if there is not enough memory
     * to show the surface, then we will try to get rid of other surfaces
     * in order to succeed.
     *
     * @return Returns true if the surface was successfully shown.
     */
    private boolean showSurfaceRobustlyLocked(SurfaceControl.Transaction t) {
    
    
    	//WindowStateAnimator将show SurfaceControl的请求传递给了WindowSurfaceController
    	//调用WindowSurfaceController的showRobustly方法
        boolean shown = mSurfaceController.showRobustly(t);
        //如果没有成功返回false
        if (!shown)
            return false;

        t.merge(mPostDrawTransaction);
        return true;
    }

In WindowSurfaceController, first determine the flag mSurfaceShown, and if it is true, return it directly; if it is false, set mSurfaceShown to true and call SurfaceControl.show. So far, the real drawing has been displayed, but whether it is really seen by the user depends on whether its parent is shown.
Code path: framework/services/core/java/com/android/server/wm/WindowSurfaceController.java

    boolean showRobustly(SurfaceControl.Transaction t) {
    
    
    	......

		//首先判断surface是否已经shown
        if (mSurfaceShown) {
    
    
            return true;
        }
		//将mSurfaceShown设置为true
        setShown(true);
        //调用SurfceControl中的show方法,将surface show出来
        t.show(mSurfaceControl);
        if (mAnimator.mIsWallpaper) {
    
    
            EventLog.writeEvent(EventLogTags.WM_WALLPAPER_SURFACE,
                    mAnimator.mWin.getDisplayId(), 1 /* request shown */);
        }
        return true;
    }

Judging from the creation of SurfaceControl and the show process, we can find that WMS manages SurfaceControl through WindowSurfaceController.
Finally, let’s take a look at the show method in SurfaceControl.
Code path: frameworks/base/core/java/android/view/SurfaceControl.java

        /**
         * Request that a given surface and it's sub-tree be shown.
         *
         * @param sc The surface to show.
         * @return This transaction.
         * @hide
         */
        @UnsupportedAppUsage
        public Transaction show(SurfaceControl sc) {
    
    
            checkPreconditions(sc);
            nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
            return this;
        }

2.4 Summary of performSurfacePlacement() process

Insert image description here
WindowSurfacePlacer.performSurfacePlacement() is called in the "[ 2.2 Window Position Calculation ]" and "[ 2.3 Window Status Refresh ]" sections. In fact, any change in window properties will trigger this method, but we only focus on the window position and size in performSurfacePlacement. Calculation and related processes of window state changes. Here is a brief overview of the process.
When WindowSurfacePlacer.performSurfacePlacement() is called, " 1 " will first be executed to update the size and status information of all windows, and " 2 " will be executed to determine whether performSurfacePlacement is called here.
1.1.1 : Mainly calls computeFrames to calculate the size of the window.
1.1.2 : Mainly handles the status change of mDrawState. In commitFinishDrawingLocked, mDrawState in the DRAW_PENDING state will be updated to COMMIT_DRAW_PENDING.
1.1.3 : Set the position of Surface mainly based on the window size calculated in computerFrames, and call SurfaceControl.show() to show the window.
1.2 : Update mDrawState in COMMIT_DRAW_PENDING state to READY_TO_SHOW and set DisplayContent.mLayoutNeeded to true. In " 2" will determine the flag bit to process whether to call performSurfacePlacement again.

Guess you like

Origin blog.csdn.net/yimelancholy/article/details/130339779