wm size可以查看当前屏幕分辨率,也可以设置屏幕分辨率(当然也就一般调试问题wm size)。
eg: wm size 720x1280
这里要注意了乘号不是*,是x字母
我们先来看下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的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();
}
因此我们先看computeScreenConfigurationLocked函数,第一行就调用了updateDisplayAndOrientationLocked函数。
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;
}
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);
}
}
}
}
setDisplayInfoOverrideFromWindowManagerLocked只是把DeviceInfo保存在mOverrideDisplayInfo中。
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;
}
然后会在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);
......
}
我们最后再来看LogicalDisplay的configureDisplayInTransactionLocked函数,会调用getDisplayInfoLocked函数,获取DisplayInfo,然后利用其displayInfo.logicalWidth, displayInfo.logicalHeight,新建一个矩阵,以及orientation,最后
device.setProjectionInTransactionLocked函数设置到SurfaceControl中去(有旋转、长宽矩阵)。(这里我们之前在 http://blog.csdn.net/kc58236582/article/details/53689526博客中分析过)
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);
}
而getDisplayInfoLocked方法就是把mOverrideDisplayInfo数据放到mInfo中返回。mOverrideDisplayInfo就是之前在WMS的updateDisplayAndOrientationLocked调用DisplayManagerService的函数传入的数据。
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;
}