wm size可以查看当前屏幕分辨率,也可以设置屏幕分辨率(当然也就一般调试问题wm size)。
eg: wm size 720x1280
这里要注意了乘号不是*,是x字母
一、Wm源码
我们先来看下wm源码,Wm.java中关于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 {
- mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
- mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
- System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
- if (!initialSize.equals(baseSize)) {
- System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
- }
- } catch (RemoteException e) {
- }
- return;
- } else if ("reset".equals(size)) {
- w = h = -1;
- } else {
- int div = size.indexOf('x');
- if (div <= 0 || div >= (size.length()-1)) {
- System.err.println("Error: bad size " + size);
- return;
- }
- String wstr = size.substring(0, div);
- String hstr = size.substring(div+1);
- try {
- w = parseDimension(wstr);
- h = parseDimension(hstr);
- } catch (NumberFormatException e) {
- System.err.println("Error: bad number " + e);
- return;
- }
- }
- try {
- if (w >= 0 && h >= 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
- } else {
- mWm.clearForcedDisplaySize(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 = Binder.clearCallingIdentity();
- 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 = Math.min(Math.max(width, MIN_WIDTH),
- displayContent.mInitialDisplayWidth * MAX_SCALE);
- height = Math.min(Math.max(height, MIN_HEIGHT),
- displayContent.mInitialDisplayHeight * MAX_SCALE);
- setForcedDisplaySizeLocked(displayContent, width, height);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
最后调用了setForcedDisplaySizeLocked函数,这个函数主要设置了displayContent的mBaseDisplayWidth和mBaseDisplayHeight变量,然后调用了reconfigureDisplayLocked函数。
- private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
- Slog.i(TAG, "Using new display size: " + width + "x" + height);
- synchronized(displayContent.mDisplaySizeLock) {
- displayContent.mBaseDisplayWidth = width;
- displayContent.mBaseDisplayHeight = height;
- }
- reconfigureDisplayLocked(displayContent);
- }
reconfigureDisplayLocked函数先调用了computeScreenConfigurationLocked函数,这个函数会通知DisplayManagerService相关设备的信息改变了,然后发送SEND_NEW_CONFIGURATION消息通知AMS(这个在http://blog.csdn.net/kc58236582/article/details/53735136博客中分析过了),以及调用performLayoutAndPlaceSurfacesLocked刷新系统。
- private void reconfigureDisplayLocked(DisplayContent displayContent) {
- // TODO: Multidisplay: for now only use with default display.
- if (!mDisplayReady) {
- return;
- }
- configureDisplayPolicyLocked(displayContent);
- displayContent.layoutNeeded = true;
- boolean configChanged = updateOrientationFromAppTokensLocked(false);
- mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = mCurConfiguration.fontScale;
- computeScreenConfigurationLocked(mTempConfiguration);
- configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
- if (configChanged) {
- mWaitingForConfig = true;
- startFreezingDisplayLocked(false, 0, 0);
- mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
- }
- performLayoutAndPlaceSurfacesLocked();
- }
- void computeScreenConfigurationLocked(Configuration config) {
- final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();
这个函数会获取displayContent的mBaseDisplayWidth和mBaseDisplayHeight,然后封装在displayInfo,最终调用mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager
- 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 ?
- displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
- final int realdh = rotated ?
- displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
- 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 = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
- final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- synchronized(displayContent.mDisplaySizeLock) {
- displayInfo.rotation = mRotation;
- displayInfo.logicalWidth = dw;
- displayInfo.logicalHeight = dh;
- displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
- displayInfo.appWidth = appWidth;
- displayInfo.appHeight = appHeight;
- displayInfo.getLogicalMetrics(mRealDisplayMetrics,
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
- displayInfo.getAppMetrics(mDisplayMetrics);
- if (displayContent.mDisplayScalingDisabled) {
- displayInfo.flags |= Display.FLAG_SCALING_DISABLED;
- } else {
- displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
- }
- mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager//设置到DisplayManagerService中去
- displayContent.getDisplayId(), displayInfo);
- displayContent.mBaseDisplayRect.set(0, 0, dw, dh);
- }
- if (false) {
- Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
- }
- mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(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 = mLogicalDisplays.get(displayId);
- if (display != null) {
- if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
- scheduleTraversalLocked(false);
- }
- }
- }
- }
- public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
- if (info != null) {
- if (mOverrideDisplayInfo == null) {
- mOverrideDisplayInfo = new DisplayInfo(info);
- mInfo = null;
- return true;
- }
- if (!mOverrideDisplayInfo.equals(info)) {
- mOverrideDisplayInfo.copyFrom(info);
- mInfo = null;
- return true;
- }
- } else if (mOverrideDisplayInfo != null) {
- mOverrideDisplayInfo = null;
- mInfo = null;
- return true;
- }
- return false;
- }
2.2 DisplayManagerService设置信息(屏幕长宽、旋转等)到SurfaceControl
然后会在WMS的刷新核心函数performLayoutAndPlaceSurfacesLockedInner调用了如下代码:
- mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
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) {
- listener.onDisplayTransaction();
- }
- }
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 = mDisplayDevices.size();
- for (int i = 0; i < count; i++) {
- DisplayDevice device = mDisplayDevices.get(i);
- configureDisplayInTransactionLocked(device);
- device.performTraversalInTransactionLocked();
- }
- // Tell the input system about these new viewports.
- if (mInputManagerInternal != null) {
- mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
- }
- }
configureDisplayInTransactionLocked这个函数会调用LogicalDisplay的configureDisplayInTransactionLocked函数
- private void configureDisplayInTransactionLocked(DisplayDevice device) {
- final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- ......
- display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
- ......
- }
- public void configureDisplayInTransactionLocked(DisplayDevice device,
- boolean isBlanked) {
- ......
- final DisplayInfo displayInfo = getDisplayInfoLocked();
- final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
- mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
- // 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.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
- orientation = displayInfo.rotation;
- }
- // Apply the physical rotation of the display device itself.
- orientation = (orientation + displayDeviceInfo.rotation) % 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 ? displayDeviceInfo.height : displayDeviceInfo.width;
- int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
- // Determine whether the width or height is more constrained to be scaled.
- // physWidth / displayInfo.logicalWidth => letter box
- // or physHeight / displayInfo.logicalHeight => 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 ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) {
- 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.
- displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight;
- displayRectHeight = physHeight;
- }
- int displayRectTop = (physHeight - displayRectHeight) / 2;
- int displayRectLeft = (physWidth - displayRectWidth) / 2;
- mTempDisplayRect.set(displayRectLeft, displayRectTop,
- displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
- mTempDisplayRect.left += mDisplayOffsetX;
- mTempDisplayRect.right += mDisplayOffsetX;
- mTempDisplayRect.top += mDisplayOffsetY;
- mTempDisplayRect.bottom += mDisplayOffsetY;
- device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
- }
- public DisplayInfo getDisplayInfoLocked() {
- if (mInfo == null) {
- mInfo = new DisplayInfo();
- mInfo.copyFrom(mBaseDisplayInfo);
- if (mOverrideDisplayInfo != null) {
- mInfo.appWidth = mOverrideDisplayInfo.appWidth;
- mInfo.appHeight = mOverrideDisplayInfo.appHeight;
- mInfo.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
- mInfo.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
- mInfo.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
- mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
- mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth;
- mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight;
- mInfo.overscanLeft = mOverrideDisplayInfo.overscanLeft;
- mInfo.overscanTop = mOverrideDisplayInfo.overscanTop;
- mInfo.overscanRight = mOverrideDisplayInfo.overscanRight;
- mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
- mInfo.rotation = mOverrideDisplayInfo.rotation;
- mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
- mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
- mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
- }
- }
- return mInfo;
- }