1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.display; 18 19 import static android.view.Surface.ROTATION_270; 20 import static android.view.Surface.ROTATION_90; 21 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.graphics.Point; 25 import android.graphics.Rect; 26 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; 27 import android.hardware.display.DisplayViewport; 28 import android.os.IBinder; 29 import android.util.ArraySet; 30 import android.util.Slog; 31 import android.view.Display; 32 import android.view.DisplayAddress; 33 import android.view.Surface; 34 import android.view.SurfaceControl; 35 36 import com.android.server.display.mode.DisplayModeDirector; 37 38 import java.io.PrintWriter; 39 import java.util.Arrays; 40 41 /** 42 * Represents a display device such as the built-in display, an external monitor, a WiFi display, 43 * or a {@link android.hardware.display.VirtualDisplay}. 44 * <p> 45 * Display devices are guarded by the {@link DisplayManagerService.SyncRoot} lock. 46 * </p> 47 */ 48 abstract class DisplayDevice { 49 /** 50 * Maximum acceptable anisotropy for the output image. 51 * 52 * Necessary to avoid unnecessary scaling when pixels are almost square, as they are non ideal 53 * anyway. For external displays, we expect an anisotropy of about 2% even if the pixels 54 * are, in fact, square due to the imprecision of the display's actual size (parsed from edid 55 * and rounded to the nearest cm). 56 */ 57 static final float MAX_ANISOTROPY = 1.025f; 58 private static final String TAG = "DisplayDevice"; 59 private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build(); 60 61 private final DisplayAdapter mDisplayAdapter; 62 private final IBinder mDisplayToken; 63 private final String mUniqueId; 64 65 protected DisplayDeviceConfig mDisplayDeviceConfig; 66 // The display device does not manage these properties itself, they are set by 67 // the display manager service. The display device shouldn't really be looking at these. 68 private int mCurrentLayerStack = -1; 69 private int mCurrentFlags = 0; 70 private int mCurrentOrientation = -1; 71 private Rect mCurrentLayerStackRect; 72 private Rect mCurrentDisplayRect; 73 private final Context mContext; 74 75 // The display device owns its surface, but it should only set it 76 // within a transaction from performTraversalLocked. 77 private Surface mCurrentSurface; 78 79 // DEBUG STATE: Last device info which was written to the log, or null if none. 80 // Do not use for any other purpose. 81 DisplayDeviceInfo mDebugLastLoggedDeviceInfo; 82 83 private final boolean mIsAnisotropyCorrectionEnabled; 84 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context)85 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, 86 Context context) { 87 this(displayAdapter, displayToken, uniqueId, context, false); 88 } 89 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context, boolean isAnisotropyCorrectionEnabled)90 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, 91 Context context, boolean isAnisotropyCorrectionEnabled) { 92 mDisplayAdapter = displayAdapter; 93 mDisplayToken = displayToken; 94 mUniqueId = uniqueId; 95 mDisplayDeviceConfig = null; 96 mContext = context; 97 mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; 98 } 99 100 /** 101 * Gets the display adapter that owns the display device. 102 * 103 * @return The display adapter. 104 */ getAdapterLocked()105 public final DisplayAdapter getAdapterLocked() { 106 return mDisplayAdapter; 107 } 108 109 /* 110 * Gets the DisplayDeviceConfig for this DisplayDevice. 111 * 112 * @return The DisplayDeviceConfig; {@code null} if not overridden. 113 */ getDisplayDeviceConfig()114 public DisplayDeviceConfig getDisplayDeviceConfig() { 115 if (mDisplayDeviceConfig == null) { 116 mDisplayDeviceConfig = loadDisplayDeviceConfig(); 117 } 118 return mDisplayDeviceConfig; 119 } 120 121 /** 122 * Gets the Surface Flinger display token for this display. 123 * 124 * @return The display token, or null if the display is not being managed 125 * by Surface Flinger. 126 */ getDisplayTokenLocked()127 public final IBinder getDisplayTokenLocked() { 128 return mDisplayToken; 129 } 130 131 /** 132 * Gets the id of the display to mirror. 133 */ getDisplayIdToMirrorLocked()134 public int getDisplayIdToMirrorLocked() { 135 return Display.DEFAULT_DISPLAY; 136 } 137 138 /** 139 * Returns the if WindowManager is responsible for mirroring on this display. If {@code false}, 140 * then SurfaceFlinger performs no layer mirroring on this display. 141 * Only used for mirroring started from MediaProjection. 142 */ isWindowManagerMirroringLocked()143 public boolean isWindowManagerMirroringLocked() { 144 return false; 145 } 146 147 /** 148 * Updates if WindowManager is responsible for mirroring on this display. If {@code false}, then 149 * SurfaceFlinger performs no layer mirroring to this display. 150 * Only used for mirroring started from MediaProjection. 151 */ setWindowManagerMirroringLocked(boolean isMirroring)152 public void setWindowManagerMirroringLocked(boolean isMirroring) { 153 } 154 155 /** 156 * Returns the default size of the surface associated with the display, or null if the surface 157 * is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will 158 * be the actual display device's size, reflecting the current rotation. 159 */ 160 @Nullable getDisplaySurfaceDefaultSizeLocked()161 public Point getDisplaySurfaceDefaultSizeLocked() { 162 DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked(); 163 var width = displayDeviceInfo.width; 164 var height = displayDeviceInfo.height; 165 if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL 166 && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) { 167 if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) { 168 height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5); 169 } else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) { 170 width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi + 0.5); 171 } 172 } 173 return isRotatedLocked() ? new Point(height, width) : new Point(width, height); 174 } 175 176 /** 177 * Gets the name of the display device. 178 * 179 * @return The display device name. 180 */ getNameLocked()181 public final String getNameLocked() { 182 return getDisplayDeviceInfoLocked().name; 183 } 184 185 /** 186 * Returns the unique id of the display device. 187 */ getUniqueId()188 public final String getUniqueId() { 189 return mUniqueId; 190 } 191 192 /** 193 * Returns whether the unique id of the device is stable across reboots. 194 */ hasStableUniqueId()195 public abstract boolean hasStableUniqueId(); 196 197 /** 198 * Gets information about the display device. 199 * 200 * The information returned should not change between calls unless the display 201 * adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event and 202 * {@link #applyPendingDisplayDeviceInfoChangesLocked()} has been called to apply 203 * the pending changes. 204 * 205 * @return The display device info, which should be treated as immutable by the caller. 206 * The display device should allocate a new display device info object whenever 207 * the data changes. 208 */ getDisplayDeviceInfoLocked()209 public abstract DisplayDeviceInfo getDisplayDeviceInfoLocked(); 210 211 /** 212 * Applies any pending changes to the observable state of the display device 213 * if the display adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event. 214 */ applyPendingDisplayDeviceInfoChangesLocked()215 public void applyPendingDisplayDeviceInfoChangesLocked() { 216 } 217 218 /** 219 * Gives the display device a chance to update its properties while in a transaction. 220 */ performTraversalLocked(SurfaceControl.Transaction t)221 public void performTraversalLocked(SurfaceControl.Transaction t) { 222 } 223 224 /** 225 * Sets the display state, if supported. 226 * 227 * @param state The new display state. 228 * @param brightnessState The new display brightnessState. 229 * @param sdrBrightnessState The new display brightnessState for SDR layers. 230 * @param displayOffloadSession {@link DisplayOffloadSession} associated with current device. 231 * @return A runnable containing work to be deferred until after we have exited the critical 232 * section, or null if none. 233 */ requestDisplayStateLocked( int state, float brightnessState, float sdrBrightnessState, @Nullable DisplayOffloadSessionImpl displayOffloadSession)234 public Runnable requestDisplayStateLocked( 235 int state, 236 float brightnessState, 237 float sdrBrightnessState, 238 @Nullable DisplayOffloadSessionImpl displayOffloadSession) { 239 return null; 240 } 241 242 /** 243 * Sets the display mode specs. 244 * 245 * Not all display devices will automatically switch between modes, so it's important that the 246 * default modeId is set correctly. 247 */ setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)248 public void setDesiredDisplayModeSpecsLocked( 249 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {} 250 251 /** 252 * Sets the user preferred display mode. Removes the user preferred display mode and sets 253 * default display mode as the mode chosen by HAL, if 'mode' is null 254 * Returns true if the mode set by user is supported by the display. 255 */ setUserPreferredDisplayModeLocked(Display.Mode mode)256 public void setUserPreferredDisplayModeLocked(Display.Mode mode) { } 257 258 /** 259 * Returns the user preferred display mode. 260 */ getUserPreferredDisplayModeLocked()261 public Display.Mode getUserPreferredDisplayModeLocked() { 262 return EMPTY_DISPLAY_MODE; 263 } 264 265 /** 266 * Returns the system preferred display mode. 267 */ getSystemPreferredDisplayModeLocked()268 public Display.Mode getSystemPreferredDisplayModeLocked() { 269 return EMPTY_DISPLAY_MODE; 270 } 271 272 /** 273 * Returns the display mode that was being used when this display was first found by 274 * display manager. 275 * @hide 276 */ getActiveDisplayModeAtStartLocked()277 public Display.Mode getActiveDisplayModeAtStartLocked() { 278 return EMPTY_DISPLAY_MODE; 279 } 280 281 /** 282 * Sets the requested color mode. 283 */ setRequestedColorModeLocked(int colorMode)284 public void setRequestedColorModeLocked(int colorMode) { 285 } 286 287 /** 288 * Sends the Auto Low Latency Mode (ALLM) signal over HDMI, or requests an internal display to 289 * switch to a low-latency mode. 290 * 291 * @param on Whether to set ALLM on or off. 292 */ setAutoLowLatencyModeLocked(boolean on)293 public void setAutoLowLatencyModeLocked(boolean on) { 294 } 295 296 /** 297 * Sends a ContentType=Game signal over HDMI, or requests an internal display to switch to a 298 * game mode (generally lower latency). 299 * 300 * @param on Whether to send a ContentType=Game signal or not 301 */ setGameContentTypeLocked(boolean on)302 public void setGameContentTypeLocked(boolean on) { 303 } 304 onOverlayChangedLocked()305 public void onOverlayChangedLocked() { 306 } 307 308 /** 309 * Sets the display layer stack while in a transaction. 310 */ setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, int layerStackTag)311 public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, 312 int layerStackTag) { 313 if (mCurrentLayerStack != layerStack) { 314 mCurrentLayerStack = layerStack; 315 t.setDisplayLayerStack(mDisplayToken, layerStack); 316 Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for " 317 + mUniqueId); 318 } 319 } 320 321 /** 322 * Sets the display flags while in a transaction. 323 * 324 * Valid display flags: 325 * {@link SurfaceControl#DISPLAY_RECEIVES_INPUT} 326 */ setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags)327 public final void setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags) { 328 if (mCurrentFlags != flags) { 329 mCurrentFlags = flags; 330 t.setDisplayFlags(mDisplayToken, flags); 331 } 332 } 333 334 /** 335 * Sets the display projection while in a transaction. 336 * 337 * @param orientation defines the display's orientation 338 * @param layerStackRect defines which area of the window manager coordinate 339 * space will be used 340 * @param displayRect defines where on the display will layerStackRect be 341 * mapped to. displayRect is specified post-orientation, that is 342 * it uses the orientation seen by the end-user 343 */ setProjectionLocked(SurfaceControl.Transaction t, int orientation, Rect layerStackRect, Rect displayRect)344 public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation, 345 Rect layerStackRect, Rect displayRect) { 346 if (mCurrentOrientation != orientation 347 || mCurrentLayerStackRect == null 348 || !mCurrentLayerStackRect.equals(layerStackRect) 349 || mCurrentDisplayRect == null 350 || !mCurrentDisplayRect.equals(displayRect)) { 351 mCurrentOrientation = orientation; 352 353 if (mCurrentLayerStackRect == null) { 354 mCurrentLayerStackRect = new Rect(); 355 } 356 mCurrentLayerStackRect.set(layerStackRect); 357 358 if (mCurrentDisplayRect == null) { 359 mCurrentDisplayRect = new Rect(); 360 } 361 mCurrentDisplayRect.set(displayRect); 362 363 t.setDisplayProjection(mDisplayToken, 364 orientation, layerStackRect, displayRect); 365 } 366 } 367 368 /** 369 * Sets the display surface while in a transaction. 370 */ setSurfaceLocked(SurfaceControl.Transaction t, Surface surface)371 public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) { 372 if (mCurrentSurface != surface) { 373 mCurrentSurface = surface; 374 t.setDisplaySurface(mDisplayToken, surface); 375 } 376 } 377 378 /** 379 * Populates the specified viewport object with orientation, 380 * physical and logical rects based on the display's current projection. 381 */ populateViewportLocked(DisplayViewport viewport)382 public final void populateViewportLocked(DisplayViewport viewport) { 383 viewport.orientation = mCurrentOrientation; 384 385 if (mCurrentLayerStackRect != null) { 386 viewport.logicalFrame.set(mCurrentLayerStackRect); 387 } else { 388 viewport.logicalFrame.setEmpty(); 389 } 390 391 if (mCurrentDisplayRect != null) { 392 viewport.physicalFrame.set(mCurrentDisplayRect); 393 } else { 394 viewport.physicalFrame.setEmpty(); 395 } 396 397 final boolean isRotated = isRotatedLocked(); 398 DisplayDeviceInfo info = getDisplayDeviceInfoLocked(); 399 viewport.deviceWidth = isRotated ? info.height : info.width; 400 viewport.deviceHeight = isRotated ? info.width : info.height; 401 402 viewport.uniqueId = info.uniqueId; 403 404 if (info.address instanceof DisplayAddress.Physical) { 405 viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort(); 406 } else { 407 viewport.physicalPort = null; 408 } 409 } 410 411 /** 412 * Dumps the local state of the display device. 413 * Does not need to dump the display device info because that is already dumped elsewhere. 414 */ dumpLocked(PrintWriter pw)415 public void dumpLocked(PrintWriter pw) { 416 pw.println("mAdapter=" + mDisplayAdapter.getName()); 417 pw.println("mUniqueId=" + mUniqueId); 418 pw.println("mDisplayToken=" + mDisplayToken); 419 pw.println("mCurrentLayerStack=" + mCurrentLayerStack); 420 pw.println("mCurrentFlags=" + mCurrentFlags); 421 pw.println("mCurrentOrientation=" + mCurrentOrientation); 422 pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect); 423 pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect); 424 pw.println("mCurrentSurface=" + mCurrentSurface); 425 } 426 427 /** 428 * @return whether the orientation is {@link ROTATION_90} or {@link ROTATION_270}. 429 */ isRotatedLocked()430 boolean isRotatedLocked() { 431 return mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270; 432 } 433 434 /** 435 * @return set of supported resolutions as an ascending sorted array. 436 */ getSupportedResolutionsLocked()437 Point[] getSupportedResolutionsLocked() { 438 ArraySet<Point> resolutions = new ArraySet<>(2); 439 Display.Mode[] supportedModes = getDisplayDeviceInfoLocked().supportedModes; 440 for (Display.Mode mode : supportedModes) { 441 resolutions.add(new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight())); 442 } 443 Point[] sortedArray = new Point[resolutions.size()]; 444 resolutions.toArray(sortedArray); 445 Arrays.sort(sortedArray, (p1, p2) -> p1.x * p1.y - p2.x * p2.y); 446 return sortedArray; 447 } 448 loadDisplayDeviceConfig()449 private DisplayDeviceConfig loadDisplayDeviceConfig() { 450 return DisplayDeviceConfig.create(mContext, /* useConfigXml= */ false, 451 mDisplayAdapter.getFeatureFlags()); 452 } 453 } 454