As mentioned in Android R DisplayManagerService module (1) startup, every physical screen in the system corresponds to a logical screen, and DisplayInfo represents the information object encapsulated by the logical screen. It is not fixed. When the DisplayInfo object changes, The WMS module sends a notification to the DMS, telling the DMS module to do the corresponding processing. This article summarizes the DMS update process after the logical screen information changes.

The update process of Configuration parameters of logical screen and physical screen in DMS is closely related to THE WMS module, because the update of DisplayInfo takes place in WMS. When the Configuration is updated, the DisplayInfo will be updated. If any changes are found, If properties such as screen orientation, screen size, and screen density change, WMS sets a new DisplayInfo to THE DMS. At the same time, when the DMS status changes, it also sends traversal request to WMS, and sets the corresponding configuration according to the WMS window status.

1. DisplayContent# updateDisplayAndOrientation update DisplayInfo ()

After the state change in WMS, in DisplayContent# updateDisplayAndOrientation () method of updating DisplayInfo objects:

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
    private DisplayInfo updateDisplayAndOrientation(int uiMode, Configuration outConfig) {...final DisplayInfo overrideDisplayInfo = mShouldOverrideDisplayConfiguration
                ? mDisplayInfo : null; mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId, overrideDisplayInfo); .return mDisplayInfo;
    }
Copy the code

The detailed process of the DisplayInfo update will be analyzed in the WMS module. Here by DMS# setDisplayInfoOverrideFromWindowManager () method, pass DisplayInfo information to DMS, according to the new update logic DisplayInfo screen information in DMS.

2. DMS# setDisplayInfoOverrideFromWindowManagerInternal update logic () screen

After entering the DMS, in setDisplayInfoOverrideFromWindowManagerInternal () method for processing:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

    private void setDisplayInfoOverrideFromWindowManagerInternal(
            int displayId, DisplayInfo info) {
        synchronized (mSyncRoot) {
            // Run the Display Id command to obtain the logical screen
            LogicalDisplay display = mLogicalDisplays.get(displayId);
            if(display ! =null) {
                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                    // Update the logical screen
                    handleLogicalDisplayChanged(displayId, display);
                    // Initiate window traversal to WMS
                    scheduleTraversalLocked(false); }}}}Copy the code

In this method:

  • First, the corresponding logical screen is obtained according to the displayId.
  • And then callLogicalDisplay#setDisplayInfoOverrideFromWindowManagerLocked()Method to update the DisplayInfo variable in DMS;
  • If the logical screen information is updated, the callback is performedonDisplayChanged()Method and initiate window traversal to WMS;

Let’s break it down one by one.

2.1. LogicalDisplay# setDisplayInfoOverrideFromWindowManagerLocked () ` update DisplayInfo variables in DMS

// frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java

    public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
        if(info ! =null) {
            if (mOverrideDisplayInfo == null) {
                mOverrideDisplayInfo = new DisplayInfo(info);
                mInfo.set(null);
                return true;
            MOverrideDisplayInfo is different from info
            } else if(! mOverrideDisplayInfo.equals(info)) {/ / update the mOverrideDisplayInfo
                mOverrideDisplayInfo.copyFrom(info);
                // empty mInfo for updates
                mInfo.set(null);
                return true; }}else if(mOverrideDisplayInfo ! =null) {
            mOverrideDisplayInfo = null;
            mInfo.set(null);
            return true;
        }
        return false;
    }
Copy the code

In this method, if the mOverrideDisplayInfo is inconsistent with the INFO, it indicates that the logical screen has changed, and the info is updated to the mOverrideDisplayInfo, and mInfo is empty. At the same time, true is returned to update the logical screen.

MInfo is a DisplayInfoProxy object. It holds a DisplayInfo object, which is the global logical screen information of the current system. When mInfo is updated, it needs to be empty first.

MOverrideDisplayInfo represents the DisplayInfo object from the WMS, the actual DisplayInfo object, that will be used to update the mInfo object when it is updated.

2.2. SendDisplayEventLocked () initiated DisplayListener# onDisplayChanged () callback

If DisplayInfo changes, then execute handleLogicalDisplayChanged () method, this method is invoked in sendDisplayEventLocked () method, Finally launched DisplayManager. DisplayListener# onDisplayChanged () callback method:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
    
    private void sendDisplayEventLocked(int displayId, int event) {
        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
        mHandler.sendMessage(msg);
    }
Copy the code

2.3. ScheduleTraversalLocked () request to launch window traversal to WMS

In the method, a traversal window request is made to WMS:

    private void scheduleTraversalLocked(boolean inTraversal) {
        if(! mPendingTraversal && mWindowManagerInternal ! =null) {
            // Initiate the tag
            mPendingTraversal = true;
            if(! inTraversal) { mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); }}}Copy the code

In the Handler, direct call WMS. RequestTraversalFromDisplayManager () launched an update request, the WMS in the android. The display thread:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

    private final class DisplayManagerHandler extends Handler {
        public DisplayManagerHandler(Looper looper) {
            super(looper, null.true /*async*/);
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ......
                case MSG_REQUEST_TRAVERSAL:
                    // Initiate a traversal request to WMS
                    mWindowManagerInternal.requestTraversalFromDisplayManager();
                    break; . }}}Copy the code

2.4.dms# getDisplayInfo() completes the DisplayInfo update and returns it to the other components

When mInfo is empty, it waits to be updated again, either by the application or by system_server. DMS provides the getDisplayInfo() method, which is called by the Binder to trigger the update, for example, when the orientation is rotated, Before executing the onConfiguration() method on the Activity where the application is located, the DisplayInfo is updated:

// frameworks/base/core/java/android/app/ActivityThread.java

    private void updateDisplayInfoLocked(a) { DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId); . }Copy the code

DMS#getDisplayInfoLocked()

// frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java

    public DisplayInfo getDisplayInfoLocked(a) {
        if (mInfo.get() == null) {
            DisplayInfo info = new DisplayInfo();
            info.copyFrom(mBaseDisplayInfo);
            if(mOverrideDisplayInfo ! =null) {
                info.appWidth = mOverrideDisplayInfo.appWidth;
                info.appHeight = mOverrideDisplayInfo.appHeight;
                info.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
                info.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
                info.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
                info.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
                info.logicalWidth = mOverrideDisplayInfo.logicalWidth;
                info.logicalHeight = mOverrideDisplayInfo.logicalHeight;
                info.rotation = mOverrideDisplayInfo.rotation;
                info.displayCutout = mOverrideDisplayInfo.displayCutout;
                info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
                info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
                info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
            }
            mInfo.set(info);
        }
        return mInfo.get();
    }
Copy the code

In this method, if the mInfo object is not null, it is returned directly; otherwise, the mInfo object is updated from the mOverrideDisplayInfo object to complete the update of the logical screen information.

At this point, the first phase of the DMS process is completed. In this stage, we mainly did three things:

  • 1. Update mOverrideDisplayInfo and mInfo objects;
  • 2. Call the DisplayListener#onDisplayChanged() method;
  • 3. Initiate window traversal request to WMS for window placement;

Let’s take a look at the interaction between WMS and DMS as it traverses Windows State.

There are two interactions between WMS and DMS as it traverses the WindowState for window placement:

  • First, in the traversal process, it will get the preferred parameter of the control display mode carried by the window, and set it to the DMS by the DMS#setDisplayProperties() method;
  • The second is after completing the placement of all Windows Surface, throughDisplayManagerInternal#performTraversal()Notifies the DMS that J updates the configurations related to the physical screen, such as the Layer Stack and area size displayed on the interface……

Let’s take a look at each of them.

3.DMS#setDisplayProperties() sets window preferences

The detailed process of installing Windows State in the WMS Surface is analyzed in the WMS module. Here’s a look at the process associated with this section. In the function interface object mApplySurfaceChangesTransaction DisplayContent will iterate over all the window, And will be carried in the display window mTmpApplySurfaceChangesTransactionState to maintain the preferences of the object:

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
        final booleanobscuredChanged = w.mObscured ! = mTmpApplySurfaceChangesTransactionState.obscured;final RootWindowContainer root = mWmService.mRoot;

        if(! mTmpApplySurfaceChangesTransactionState.obscured) {final boolean isDisplayed = w.isDisplayedLw();

            if (isDisplayed && w.isObscuringDisplay()) {
                root.mObscuringWindow = w;
                mTmpApplySurfaceChangesTransactionState.obscured = true;
            }
            // Whether there is content displayed on the logical screen to control multi-screen mirroring
            final boolean displayHasContent = root.handleNotObscuredLocked(w,
                    mTmpApplySurfaceChangesTransactionState.obscured,
                    mTmpApplySurfaceChangesTransactionState.syswin);

            if(! mTmpApplySurfaceChangesTransactionState.displayHasContent && ! getDisplayPolicy().isWindowExcludedFromContent(w)) { mTmpApplySurfaceChangesTransactionState.displayHasContent |= displayHasContent; }if (w.mHasSurface && isDisplayed) {
                final int type = w.mAttrs.type;
                // Set the preferred frame rate
                if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0&& w.mAttrs.preferredRefreshRate ! =0) {
                    mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
                            = w.mAttrs.preferredRefreshRate;
                }
                / / set preferMinimalPostProcessing
                mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing
                        |= w.mAttrs.preferMinimalPostProcessing;

                final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
                        .getPreferredModeId(w);
                / / set preferredModeId
                if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0&& preferredModeId ! =0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId; }}}... };Copy the code

Traverse is completed, the value stored in mTmpApplySurfaceChangesTransactionState, and in the last issue request to DMS, set the display parameters, such as high refresh rate, wide, whether the mirror…

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
 
    void applySurfaceChangesTransaction(a) { mTmpApplySurfaceChangesTransactionState.reset(); . mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId, mLastHasContent, mTmpApplySurfaceChangesTransactionState.preferredRefreshRate, mTmpApplySurfaceChangesTransactionState.preferredModeId, mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,true /* inTraversal, must call performTraversalInTrans... below */);
    }
Copy the code

The meanings of the parameters are as follows:

  • HasContent Indicates whether content is displayed on the logical screen and is used to control screen mirroring.
  • PreferredRefreshRate indicates the preferredRefreshRate carried by the top-level window;
  • PreferredModeId indicates the preferred mode carried by the top-level window;
  • PreferMinimalPostProcessing said the smallest Post – Processing, this is a display professional term.

4.DMS#performTraversal() updates the screen configuration

When all Windows are installed, transaction commit in DMS is performed in WMS using the DMS#performTraversal() method and the mDisplayTransaction object:

// frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
 
    private void applySurfaceChangesTransaction(a) {...// Iterate over each DisplayContent, placing the Surface in each Display
        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
            final DisplayContent dc = mChildren.get(j);
            dc.applySurfaceChangesTransaction();
        }
        // Notify THE DMS to adjust the Display attributes
        mWmService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
        // Merge mDisplayTransaction into sGlobalTransaction
        SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
    }
Copy the code

After entering DMS:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

void performTraversalInternal(SurfaceControl.Transaction t) {
    synchronized (mSyncRoot) {
        // Only mPendingTraversal can be updated
        if(! mPendingTraversal) {return;
        }
        // Reset to false
        mPendingTraversal = false;
        performTraversalLocked(t);
    }
 
    for(DisplayTransactionListener listener : mDisplayTransactionListeners) { listener.onDisplayTransaction(t); }}Copy the code

As you can see, only mPendingTraversal will be updated, which happens to be true in scheduleTraversalLocked(), and performTraversalLocked(), This method completes the DMS update step by step:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

private void performTraversalLocked(SurfaceControl.Transaction t) {
    // Clear the DisplayViewport list
    clearViewportsLocked();
 
    // Go through all physical displays
    final int count = mDisplayDevices.size();
    for (int i = 0; i < count; i++) {
        DisplayDevice device = mDisplayDevices.get(i);
        // Update the physical screen configuration
        configureDisplayLocked(t, device);
        device.performTraversalLocked(t);
    }
 
    // Notifies the IMS when the Viewport changes
    if(mInputManagerInternal ! =null) { mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT); }}Copy the code

In this method, the configuration of each physical display is updated. Finally, if the DisplayViewport changes, the IMS is notified.

4.1. ConfigureDisplayLocked ()

The method is as follows:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
    // Get the DisplayDeviceInfo object corresponding to the physical screen
    final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
    // Whether the display can be mirrored to other displays. True indicates that the display is not allowed
    final booleanownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) ! =0;
    // Gets the logical display object corresponding to the physical display
    LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
    // If the physical screen allows mirroring, determine the source of the mirroring according to display.hascontentlocked ()
    if(! ownContent) {if(display ! =null && !display.hasContentLocked()) {
            display = mLogicalDisplays.get(device.getDisplayIdToMirrorLocked());
        }
        if (display == null) { display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY); }}// Configure logical display
    display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
    // Update viewPort type
    final Optional<Integer> viewportType = getViewportType(info);

    / / fill the viewport
    populateViewportLocked(viewportType, display.getDisplayIdLocked(), device, info.uniqueId);
}
Copy the code

This method completes the reconfiguration of the logical screen, physical screen, and ViewPort. Let’s analyze it step by step.

4.2. ConfigureDisplayLocked update physical screen configuration ()

The method is as follows:

// frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java

    public void configureDisplayLocked(SurfaceControl.Transaction t,
            DisplayDevice device,
            boolean isBlanked) {
        // Set the Layer Stack ID
        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);

        // Set the color mode.// Get the DisplayInfo object corresponding to the logical screen
        final DisplayInfo displayInfo = getDisplayInfoLocked();
		// Get the DisplayDeviceInfo object corresponding to the physical screen
        final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        // Set the mTempLayerStackRect area, which represents the logical screen area to display on the physical screen
        mTempLayerStackRect.set(0.0, displayInfo.logicalWidth, displayInfo.logicalHeight);

        // Determine the direction
        int orientation = Surface.ROTATION_0;
        if((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) ! =0) {
            orientation = displayInfo.rotation;
        }
        orientation = (orientation + displayDeviceInfo.rotation) % 4;

        // According to the display direction, ok
        boolean rotated = (orientation == Surface.ROTATION_90
                || orientation == Surface.ROTATION_270);
		// Get the physical display width
        int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
        int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
		// Get the hidden area
        Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
        InsetUtils.rotateInsets(maskingInsets, orientation);
		// Physical size minus the width and height of the hidden area
        physWidth -= maskingInsets.left + maskingInsets.right;
        physHeight -= maskingInsets.top + maskingInsets.bottom;

        int displayRectWidth, displayRectHeight;
        if((displayInfo.flags & Display.FLAG_SCALING_DISABLED) ! =0 || mDisplayScalingDisabled) {
            displayRectWidth = displayInfo.logicalWidth;
            displayRectHeight = displayInfo.logicalHeight;
        } else if (physWidth * displayInfo.logicalHeight
                < physHeight * displayInfo.logicalWidth) {
            // Letter box
            displayRectWidth = physWidth;
            displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth;
        } else {
            // Pillar box. Pillar box with two black sides
            displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
            displayRectHeight = physHeight;
        }
        int displayRectTop = (physHeight - displayRectHeight) / 2;
        int displayRectLeft = (physWidth - displayRectWidth) / 2;
        // Set the mTempDisplayRect field
        mTempDisplayRect.set(displayRectLeft, displayRectTop,
                displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);

        // Set the offset
        mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
		// Apply offsets mDisplayOffsetX and mDisplayOffsetY
        if (orientation == Surface.ROTATION_0) {
            mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
        } else if (orientation == Surface.ROTATION_90) {
            mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
        } else if (orientation == Surface.ROTATION_180) {
            mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
        } else {  // Surface.ROTATION_270
            mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
        }
		// Set the physical display projection
        device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
    }
Copy the code

In this method, the following three things are done:

  • First, set the Layer Stack Id;
  • Then, mTempLayerStackRect and mTempDisplayRect are determined.
  • Finally, set the Display projection to the SurfaceFlinger;

4.3.DisplayDevice#setLayerStackLocked() Sets the LayerStack

Layer Stack Id Indicates the corresponding Layer Stack on each physical screen in the SurfaceFlinger. All the layers displayed on the Display are in the Layer Stack. When creating a logical screen, a Layer Stack ID is specified. When the screen is off, the Layer Stack ID is set to -1 and nothing is displayed:

// frameworks/base/services/core/java/com/android/server/display/DisplayDevice.java

    public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) {
        if(mCurrentLayerStack ! = layerStack) {// Indicates the id of the current Layer Stack
            mCurrentLayerStack = layerStack;
            / / sett.setDisplayLayerStack(mDisplayToken, layerStack); }}Copy the code

4.4.DisplayDevice#setProjectionLocked() sets the projection matrix

Next, we define two objects, mTempLayerStackRect and mTempDisplayRect. MTempLayerStackRect represents the logical screen size area, mTempDisplayRect represents the physical screen display area, Through SurfaceControl. Transaction# setDisplayLayerStack () after this two area to SurfaceFlinger, calculated the final projection matrix:

// 
public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation,
        Rect layerStackRect, Rect displayRect) {
    if(mCurrentOrientation ! = orientation || mCurrentLayerStackRect ==null| |! mCurrentLayerStackRect.equals(layerStackRect) || mCurrentDisplayRect ==null| |! mCurrentDisplayRect.equals(displayRect)) {// Current screen orientation
        mCurrentOrientation = orientation;
        // Update the logical display area and the corresponding physical display area. mCurrentLayerStackRect.set(layerStackRect); . mCurrentDisplayRect.set(displayRect);// Pass to the SurfaceControl to compute the projection matrixt.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect); }}Copy the code

In this method, mTempLayerStackRect and mTempDisplayRect are updated to the global variables mCurrentLayerStackRect and mCurrentDisplayRect, which will play a role in mapping the ViewPort.

At this point, the LogicalDisplay#configureDisplayLocked() method is finished, and back to DMS#configureDisplayLocked(), the viewport population will begin.

4.5 update the ViewPort

ViewPort represents the corresponding relationship between the physical screen and the logical screen. In the Input module, ViewPort is used to convert the touch event coordinates of the physical screen to the coordinates of the logical screen. Therefore, the view port is repopulated and sent to the IMS module every time the logical screen and physical screen are configured.

Each time performTraversalLocked() is performed, the current ViewPort list is first emptied:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
    
    private void clearViewportsLocked(a) {
        mViewports.clear();
    }
Copy the code

After LogicalDisplay#configureDisplayLocked() is executed, mCurrentOrientation and mCurrentDisplayRect are updated for the physical screen, Next, DMS#getViewportType() is used to determine the new ViewPort type of the physical screen according to the physical screen properties:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

    private Optional<Integer> getViewportType(DisplayDeviceInfo info) {
        // Built-in screen, Viewport type is VIEWPORT_INTERNAL
        if((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) ! =0) {
            return Optional.of(VIEWPORT_INTERNAL);
        // Set the TOUCH_EXTERNAL flag to indicate that the touch event is external and the Viewport type is VIEWPORT_INTERNAL
        } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
            return Optional.of(VIEWPORT_EXTERNAL);
        } else if(info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL && ! TextUtils.isEmpty(info.uniqueId)) {return Optional.of(VIEWPORT_VIRTUAL);
        } else{}return Optional.empty();
    }
Copy the code

4.6. PopulateViewportLocked () to fill the ViewPort

Next, fill the ViewPort with DMS#populateViewportLocked() :

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
    
    private void populateViewportLocked(int viewportType, int displayId, DisplayDevice device,
            DisplayDeviceInfo info) {
        final DisplayViewport viewport = getViewportLocked(viewportType, info.uniqueId);
        // Go to the physical screen to fill the blanks
        device.populateViewportLocked(viewport);
        // Indicates valid
        viewport.valid = true;
        viewport.displayId = displayId;
        // Use Display state to determine whether the viewPort is active
        viewport.isActive = Display.isActiveState(info.state);
    }
Copy the code

Enter the corresponding physical screen for filling:

// frameworks/base/services/core/java/com/android/server/display/DisplayDevice.java

    public final void populateViewportLocked(DisplayViewport viewport) {
        // Set the direction
        viewport.orientation = mCurrentOrientation;
        // Set the logical screen area
        if(mCurrentLayerStackRect ! =null) {
            viewport.logicalFrame.set(mCurrentLayerStackRect);
        } else {
            viewport.logicalFrame.setEmpty();
        }
        // Set the physical screen area
        if(mCurrentDisplayRect ! =null) {
            viewport.physicalFrame.set(mCurrentDisplayRect);
        } else {
            viewport.physicalFrame.setEmpty();
        }
        // Whether rotation occurs
        boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
                || mCurrentOrientation == Surface.ROTATION_270);
        // Obtain physical screen information
        DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
        // Indicates the width and height of the physical screen
        viewport.deviceWidth = isRotated ? info.height : info.width;
        viewport.deviceHeight = isRotated ? info.width : info.height;
        // Physical screen ID
        viewport.uniqueId = info.uniqueId;
        // Physical screen Fixed physical port
        if (info.address instanceof DisplayAddress.Physical) {
            viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
        } else {
            viewport.physicalPort = null; }}Copy the code

As you can see, the ViewPort is populated by passing the width and height of the display area of the logical screen, the width and height of the display area of the physical screen, and the information carried in the DisplayDeviceInfo object of the physical screen to the ViewPort object. The ViewPort.PhysicalPort object is very important, as you’ll see later there is also a static route.

4.7. Notify IMS to update ViewPort

At the end of the DMS#performTraversalLocked() method, an MSG_UPDATE_VIEWPORT is sent through the Handler, which notifies IMS of the changed viewport:

// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
    
    private final class DisplayManagerHandler extends Handler {...@Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ......
                case MSG_UPDATE_VIEWPORT: {
                    final boolean changed;
                    synchronized(mSyncRoot) { changed = ! mTempViewports.equals(mViewports);if (changed) {
                            mTempViewports.clear();
                            for(DisplayViewport d : mViewports) { mTempViewports.add(d.makeCopy()); }}}if (changed) {
                        mInputManagerInternal.setDisplayViewports(mTempViewports);
                    }
                    break; }... }}}Copy the code

At this point, the update in the entire DMS is complete, and finally the updated display is complete with the commit of the transaction in THE WMS.

The sequence diagram of main processes in the main process is as follows: