wm命令(wm size)修改屏幕尺寸

时间:2025-01-27 11:52:59

wm size可以查看当前屏幕分辨率,也可以设置屏幕分辨率(当然也就一般调试问题wm size)。

eg: wm size 720x1280

这里要注意了乘号不是*,是x字母

一、Wm源码

我们先来看下wm源码,中关于wm size部分。

    private void runDisplaySize() throws Exception {
        String size = nextArg();
        int w, h;
        if (size == null) {
            Point initialSize = new Point();
            Point baseSize = new Point();
            try {
                (Display.DEFAULT_DISPLAY, initialSize);
                (Display.DEFAULT_DISPLAY, baseSize);
                ("Physical size: " +  + "x" + );
                if (!(baseSize)) {
                    ("Override size: " +  + "x" + );
                }
            } catch (RemoteException e) {
            }
            return;
        } else if ("reset".equals(size)) {
            w = h = -1;
        } else {
            int div = ('x');
            if (div <= 0 || div >= (()-1)) {
                ("Error: bad size " + size);
                return;
            }
            String wstr = (0, div);
            String hstr = (div+1);
            try {
                w = parseDimension(wstr);
                h = parseDimension(hstr);
            } catch (NumberFormatException e) {
                ("Error: bad number " + e);
                return;
            }
        }

        try {
            if (w >= 0 && h >= 0) {
                // TODO(multidisplay): For now Configuration only applies to main screen.
                (Display.DEFAULT_DISPLAY, w, h);
            } else {
                (Display.DEFAULT_DISPLAY);
            }
        } catch (RemoteException e) {
        }
    }

当没有参数时会WMS中的initialSize和baseSize,如果有参数,最终会调用WMS的setForcedDisplaySize函数,如果是reset就调用WMS的clearForcedDisplaySize函数重置分辨率。

二、WMS设置分辨率

下面我们主要看下WMS的setForcedDisplaySize函数:

    public void setForcedDisplaySize(int displayId, int width, int height) {
        ......
        final long ident = ();
        try {
            synchronized(mWindowMap) {
                // Set some sort of reasonable bounds on the size of the display that we
                // will try to emulate.
                final int MIN_WIDTH = 200;
                final int MIN_HEIGHT = 200;
                final int MAX_SCALE = 2;
                final DisplayContent displayContent = getDisplayContentLocked(displayId);
                if (displayContent != null) {
                    width = ((width, MIN_WIDTH),
                             * MAX_SCALE);
                    height = ((height, MIN_HEIGHT),
                             * MAX_SCALE);
                    setForcedDisplaySizeLocked(displayContent, width, height);
                    ((),
                            .DISPLAY_SIZE_FORCED, width + "," + height);
                }
            }
        } finally {
            (ident);
        }
    }

最后调用了setForcedDisplaySizeLocked函数,这个函数主要设置了displayContent的mBaseDisplayWidth和mBaseDisplayHeight变量,然后调用了reconfigureDisplayLocked函数。

    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
        (TAG, "Using new display size: " + width + "x" + height);

        synchronized() {
             = width;
             = height;
        }
        reconfigureDisplayLocked(displayContent);
    }

reconfigureDisplayLocked函数先调用了computeScreenConfigurationLocked函数,这个函数会通知DisplayManagerService相关设备的信息改变了,然后发送SEND_NEW_CONFIGURATION消息通知AMS(这个在/kc58236582/article/details/53735136博客中分析过了),以及调用performLayoutAndPlaceSurfacesLocked刷新系统。

    private void reconfigureDisplayLocked(DisplayContent displayContent) {
        // TODO: Multidisplay: for now only use with default display.
        if (!mDisplayReady) {
            return;
        }
        configureDisplayPolicyLocked(displayContent);
         = true;

        boolean configChanged = updateOrientationFromAppTokensLocked(false);
        ();
         = ;
        computeScreenConfigurationLocked(mTempConfiguration);
        configChanged |= (mTempConfiguration) != 0;

        if (configChanged) {
            mWaitingForConfig = true;
            startFreezingDisplayLocked(false, 0, 0);
            (H.SEND_NEW_CONFIGURATION);
        }

        performLayoutAndPlaceSurfacesLocked();
    }
因此我们先看computeScreenConfigurationLocked函数,第一行就调用了updateDisplayAndOrientationLocked函数。

    void computeScreenConfigurationLocked(Configuration config) {
        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();

这个函数会获取displayContent的mBaseDisplayWidth和mBaseDisplayHeight,然后封装在displayInfo,最终调用

    DisplayInfo updateDisplayAndOrientationLocked() {
        // TODO(multidisplay): For now, apply Configuration to main screen only.
        final DisplayContent displayContent = getDefaultDisplayContentLocked();

        // Use the effective "visual" dimensions based on current rotation
        final boolean rotated = (mRotation == Surface.ROTATION_90
                || mRotation == Surface.ROTATION_270);
        final int realdw = rotated ?
                 : ;
        final int realdh = rotated ?
                 : ;
        int dw = realdw;
        int dh = realdh;

        if (mAltOrientation) {
            if (realdw > realdh) {
                // Turn landscape into portrait.
                int maxw = (int)(realdh/1.3f);
                if (maxw < realdw) {
                    dw = maxw;
                }
            } else {
                // Turn portrait into landscape.
                int maxh = (int)(realdw/1.3f);
                if (maxh < realdh) {
                    dh = maxh;
                }
            }
        }

        // Update application display metrics.
        final int appWidth = (dw, dh, mRotation);
        final int appHeight = (dw, dh, mRotation);
        final DisplayInfo displayInfo = ();
        synchronized() {
             = mRotation;
             = dw;
             = dh;
             = ;
             = appWidth;
             = appHeight;
            (mRealDisplayMetrics,
                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
            (mDisplayMetrics);
            if () {
                 |= Display.FLAG_SCALING_DISABLED;
            } else {
                 &= ~Display.FLAG_SCALING_DISABLED;
            }

            //设置到DisplayManagerService中去
                    (), displayInfo);

            (0, 0, dw, dh);
        }
        if (false) {
            (TAG, "Set app display size: " + appWidth + " x " + appHeight);
        }

        mCompatibleScreenScale = (mDisplayMetrics,
                mCompatDisplayMetrics);
        return displayInfo;
    }

2.1 WMS传递DeviceInfo到DisplayManagerService中

WMS通过DeviceManagerService的setDisplayInfoOverrideFromWindowManager函数把DeviceInfo到DisplayManagerService中。

setDisplayInfoOverrideFromWindowManager函数之前分析过,这里我们再看下,直接调用了setDisplayInfoOverrideFromWindowManagerInternal函数

        @Override
        public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
            setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
        }

而setDisplayInfoOverrideFromWindowManagerInternal方法,找到合适的LogicalDisplay,然后调用其setDisplayInfoOverrideFromWindowManagerLocked方法把DisplayInfo保存下来。

    private void setDisplayInfoOverrideFromWindowManagerInternal(
            int displayId, DisplayInfo info) {
        synchronized (mSyncRoot) {
            LogicalDisplay display = (displayId);
            if (display != null) {
                if ((info)) {
                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
                    scheduleTraversalLocked(false);
                }
            }
        }
    }
setDisplayInfoOverrideFromWindowManagerLocked只是把DeviceInfo保存在mOverrideDisplayInfo中。

    public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
        if (info != null) {
            if (mOverrideDisplayInfo == null) {
                mOverrideDisplayInfo = new DisplayInfo(info);
                mInfo = null;
                return true;
            }
            if (!(info)) {
                (info);
                mInfo = null;
                return true;
            }
        } else if (mOverrideDisplayInfo != null) {
            mOverrideDisplayInfo = null;
            mInfo = null;
            return true;
        }
        return false;
    }

2.2 DisplayManagerService设置信息(屏幕长宽、旋转等)到SurfaceControl

然后会在WMS的刷新核心函数performLayoutAndPlaceSurfacesLockedInner调用了如下代码:

();

performTraversalInTransactionFromWindowManager函数直接调用了performTraversalInTransactionFromWindowManagerInternal函数

        @Override
        public void performTraversalInTransactionFromWindowManager() {
            performTraversalInTransactionFromWindowManagerInternal();
        }

performTraversalInTransactionFromWindowManagerInternal函数,我们主要看下performTraversalInTransactionLocked函数。

    private void performTraversalInTransactionFromWindowManagerInternal() {
        synchronized (mSyncRoot) {
            if (!mPendingTraversal) {
                return;
            }
            mPendingTraversal = false;

            performTraversalInTransactionLocked();
        }

        // List is self-synchronized copy-on-write.
        for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
            ();
        }
    }

performTraversalInTransactionLocked函数会遍历所有的DisplayDevice,然后调用configureDisplayInTransactionLocked函数。

    private void performTraversalInTransactionLocked() {
        // Clear all viewports before configuring displays so that we can keep
        // track of which ones we have configured.
        clearViewportsLocked();

        // Configure each display device.
        final int count = ();
        for (int i = 0; i < count; i++) {
            DisplayDevice device = (i);
            configureDisplayInTransactionLocked(device);
            ();
        }

        // Tell the input system about these new viewports.
        if (mInputManagerInternal != null) {
            (MSG_UPDATE_VIEWPORT);
        }
    }

configureDisplayInTransactionLocked这个函数会调用LogicalDisplay的configureDisplayInTransactionLocked函数

    private void configureDisplayInTransactionLocked(DisplayDevice device) {
        final DisplayDeviceInfo info = ();
        ......
        (device,  == Display.STATE_OFF);

        ......
    }
我们最后再来看LogicalDisplay的configureDisplayInTransactionLocked函数,会调用getDisplayInfoLocked函数,获取DisplayInfo,然后利用其, ,新建一个矩阵,以及orientation,最后 函数设置到SurfaceControl中去(有旋转、长宽矩阵)。(这里我们之前在 /kc58236582/article/details/53689526博客中分析过)
    public void configureDisplayInTransactionLocked(DisplayDevice device,
            boolean isBlanked) {
        ......
        final DisplayInfo displayInfo = getDisplayInfoLocked();
        final DisplayDeviceInfo displayDeviceInfo = ();

        (0, 0, , );

        // Set the orientation.
        // The orientation specifies how the physical coordinate system of the display
        // is rotated when the contents of the logical display are rendered.
        int orientation = Surface.ROTATION_0;
        if (( & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
            orientation = ;
        }

        // Apply the physical rotation of the display device itself.
        orientation = (orientation + ) % 4;

        // Set the frame.
        // The frame specifies the rotated physical coordinates into which the viewport
        // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
        // Currently we maximize the area to fill the display, but we could try to be
        // more clever and match resolutions.
        boolean rotated = (orientation == Surface.ROTATION_90
                || orientation == Surface.ROTATION_270);
        int physWidth = rotated ?  : ;
        int physHeight = rotated ?  : ;

        // Determine whether the width or height is more constrained to be scaled.
        //    physWidth /     => letter box
        // or physHeight /   => pillar box
        //
        // We avoid a division (and possible floating point imprecision) here by
        // multiplying the fractions by the product of their denominators before
        // comparing them.
        int displayRectWidth, displayRectHeight;
        if (( & Display.FLAG_SCALING_DISABLED) != 0) {
            displayRectWidth = ;
            displayRectHeight = ;
        } else if (physWidth * 
                < physHeight * ) {
            // Letter box.
            displayRectWidth = physWidth;
            displayRectHeight =  * physWidth / ;
        } else {
            // Pillar box.
            displayRectWidth =  * physHeight / ;
            displayRectHeight = physHeight;
        }
        int displayRectTop = (physHeight - displayRectHeight) / 2;
        int displayRectLeft = (physWidth - displayRectWidth) / 2;
        (displayRectLeft, displayRectTop,
                displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);

         += mDisplayOffsetX;
         += mDisplayOffsetX;
         += mDisplayOffsetY;
         += mDisplayOffsetY;
        (orientation, mTempLayerStackRect, mTempDisplayRect);
    }
而getDisplayInfoLocked方法就是把mOverrideDisplayInfo数据放到mInfo中返回。mOverrideDisplayInfo就是之前在WMS的updateDisplayAndOrientationLocked调用DisplayManagerService的函数传入的数据。
    public DisplayInfo getDisplayInfoLocked() {
        if (mInfo == null) {
            mInfo = new DisplayInfo();
            (mBaseDisplayInfo);
            if (mOverrideDisplayInfo != null) {
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
                 = ;
            }
        }
        return mInfo;
    }