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 int mLastDisplayWidth; 72 private int mLastDisplayHeight; 73 private Rect mCurrentLayerStackRect; 74 private Rect mCurrentDisplayRect; 75 private final Context mContext; 76 77 // The display device owns its surface, but it should only set it 78 // within a transaction from performTraversalLocked. 79 private Surface mCurrentSurface; 80 81 // DEBUG STATE: Last device info which was written to the log, or null if none. 82 // Do not use for any other purpose. 83 DisplayDeviceInfo mDebugLastLoggedDeviceInfo; 84 85 private final boolean mIsAnisotropyCorrectionEnabled; 86 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context)87 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, 88 Context context) { 89 this(displayAdapter, displayToken, uniqueId, context, false); 90 } 91 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context, boolean isAnisotropyCorrectionEnabled)92 DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, 93 Context context, boolean isAnisotropyCorrectionEnabled) { 94 mDisplayAdapter = displayAdapter; 95 mDisplayToken = displayToken; 96 mUniqueId = uniqueId; 97 mDisplayDeviceConfig = null; 98 mContext = context; 99 mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; 100 } 101 102 /** 103 * Gets the display adapter that owns the display device. 104 * 105 * @return The display adapter. 106 */ getAdapterLocked()107 public final DisplayAdapter getAdapterLocked() { 108 return mDisplayAdapter; 109 } 110 111 /* 112 * Gets the DisplayDeviceConfig for this DisplayDevice. 113 * 114 * @return The DisplayDeviceConfig; {@code null} if not overridden. 115 */ getDisplayDeviceConfig()116 public DisplayDeviceConfig getDisplayDeviceConfig() { 117 if (mDisplayDeviceConfig == null) { 118 mDisplayDeviceConfig = loadDisplayDeviceConfig(); 119 } 120 return mDisplayDeviceConfig; 121 } 122 123 /** 124 * Gets the Surface Flinger display token for this display. 125 * 126 * @return The display token, or null if the display is not being managed 127 * by Surface Flinger. 128 */ getDisplayTokenLocked()129 public final IBinder getDisplayTokenLocked() { 130 return mDisplayToken; 131 } 132 133 /** 134 * Gets the id of the display to mirror. 135 */ getDisplayIdToMirrorLocked()136 public int getDisplayIdToMirrorLocked() { 137 return Display.DEFAULT_DISPLAY; 138 } 139 140 /** 141 * Returns the if WindowManager is responsible for mirroring on this display. If {@code false}, 142 * then SurfaceFlinger performs no layer mirroring on this display. 143 * Only used for mirroring started from MediaProjection. 144 */ isWindowManagerMirroringLocked()145 public boolean isWindowManagerMirroringLocked() { 146 return false; 147 } 148 149 /** 150 * Updates if WindowManager is responsible for mirroring on this display. If {@code false}, then 151 * SurfaceFlinger performs no layer mirroring to this display. 152 * Only used for mirroring started from MediaProjection. 153 */ setWindowManagerMirroringLocked(boolean isMirroring)154 public void setWindowManagerMirroringLocked(boolean isMirroring) { 155 } 156 157 /** 158 * Returns the default size of the surface associated with the display, or null if the surface 159 * is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will 160 * be the actual display device's size, reflecting the current rotation. 161 */ 162 @Nullable getDisplaySurfaceDefaultSizeLocked()163 public Point getDisplaySurfaceDefaultSizeLocked() { 164 DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked(); 165 var width = displayDeviceInfo.width; 166 var height = displayDeviceInfo.height; 167 if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL 168 && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) { 169 if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) { 170 height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5); 171 } else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) { 172 width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi + 0.5); 173 } 174 } 175 return isRotatedLocked() ? new Point(height, width) : new Point(width, height); 176 } 177 178 /** 179 * Gets the name of the display device. 180 * 181 * @return The display device name. 182 */ getNameLocked()183 public final String getNameLocked() { 184 return getDisplayDeviceInfoLocked().name; 185 } 186 187 /** 188 * Returns the unique id of the display device. 189 */ getUniqueId()190 public final String getUniqueId() { 191 return mUniqueId; 192 } 193 194 /** 195 * Returns whether the unique id of the device is stable across reboots. 196 */ hasStableUniqueId()197 public abstract boolean hasStableUniqueId(); 198 199 /** 200 * Gets information about the display device. 201 * 202 * The information returned should not change between calls unless the display 203 * adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event and 204 * {@link #applyPendingDisplayDeviceInfoChangesLocked()} has been called to apply 205 * the pending changes. 206 * 207 * @return The display device info, which should be treated as immutable by the caller. 208 * The display device should allocate a new display device info object whenever 209 * the data changes. 210 */ getDisplayDeviceInfoLocked()211 public abstract DisplayDeviceInfo getDisplayDeviceInfoLocked(); 212 213 /** 214 * Applies any pending changes to the observable state of the display device 215 * if the display adapter sent a {@link DisplayAdapter#DISPLAY_DEVICE_EVENT_CHANGED} event. 216 */ applyPendingDisplayDeviceInfoChangesLocked()217 public void applyPendingDisplayDeviceInfoChangesLocked() { 218 } 219 220 /** 221 * Updates the surface for the display. 222 */ configureSurfaceLocked(SurfaceControl.Transaction t)223 public void configureSurfaceLocked(SurfaceControl.Transaction t) { 224 } 225 226 /** 227 * Sets the display state, if supported. 228 * 229 * @param state The new display state. 230 * @param brightnessState The new display brightnessState. 231 * @param sdrBrightnessState The new display brightnessState for SDR layers. 232 * @param displayOffloadSession {@link DisplayOffloadSession} associated with current device. 233 * @return A runnable containing work to be deferred until after we have exited the critical 234 * section, or null if none. 235 */ requestDisplayStateLocked( int state, float brightnessState, float sdrBrightnessState, @Nullable DisplayOffloadSessionImpl displayOffloadSession)236 public Runnable requestDisplayStateLocked( 237 int state, 238 float brightnessState, 239 float sdrBrightnessState, 240 @Nullable DisplayOffloadSessionImpl displayOffloadSession) { 241 return null; 242 } 243 244 /** 245 * Sets the display mode specs. 246 * 247 * Not all display devices will automatically switch between modes, so it's important that the 248 * default modeId is set correctly. 249 */ setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)250 public void setDesiredDisplayModeSpecsLocked( 251 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {} 252 253 /** 254 * Sets the user preferred display mode. Removes the user preferred display mode and sets 255 * default display mode as the mode chosen by HAL, if 'mode' is null 256 * Returns true if the mode set by user is supported by the display. 257 */ setUserPreferredDisplayModeLocked(Display.Mode mode)258 public void setUserPreferredDisplayModeLocked(Display.Mode mode) { } 259 260 /** 261 * Returns the user preferred display mode. 262 */ getUserPreferredDisplayModeLocked()263 public Display.Mode getUserPreferredDisplayModeLocked() { 264 return EMPTY_DISPLAY_MODE; 265 } 266 267 /** 268 * Returns the system preferred display mode. 269 */ getSystemPreferredDisplayModeLocked()270 public Display.Mode getSystemPreferredDisplayModeLocked() { 271 return EMPTY_DISPLAY_MODE; 272 } 273 274 /** 275 * Returns the display mode that was being used when this display was first found by 276 * display manager. 277 * @hide 278 */ getActiveDisplayModeAtStartLocked()279 public Display.Mode getActiveDisplayModeAtStartLocked() { 280 return EMPTY_DISPLAY_MODE; 281 } 282 283 /** 284 * Sets the requested color mode. 285 */ setRequestedColorModeLocked(int colorMode)286 public void setRequestedColorModeLocked(int colorMode) { 287 } 288 289 /** 290 * Sends the Auto Low Latency Mode (ALLM) signal over HDMI, or requests an internal display to 291 * switch to a low-latency mode. 292 * 293 * @param on Whether to set ALLM on or off. 294 */ setAutoLowLatencyModeLocked(boolean on)295 public void setAutoLowLatencyModeLocked(boolean on) { 296 } 297 298 /** 299 * Sends a ContentType=Game signal over HDMI, or requests an internal display to switch to a 300 * game mode (generally lower latency). 301 * 302 * @param on Whether to send a ContentType=Game signal or not 303 */ setGameContentTypeLocked(boolean on)304 public void setGameContentTypeLocked(boolean on) { 305 } 306 onOverlayChangedLocked()307 public void onOverlayChangedLocked() { 308 } 309 310 /** 311 * Returns if the display should only mirror another display rather than showing other content 312 * until it is destroyed. 313 */ shouldOnlyMirror()314 public boolean shouldOnlyMirror() { 315 return false; 316 } 317 318 /** 319 * Sets the display layer stack while in a transaction. 320 */ setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, int layerStackTag)321 public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, 322 int layerStackTag) { 323 if (mCurrentLayerStack != layerStack) { 324 mCurrentLayerStack = layerStack; 325 t.setDisplayLayerStack(mDisplayToken, layerStack); 326 Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for " 327 + mUniqueId); 328 } 329 } 330 331 /** 332 * Sets the display flags while in a transaction. 333 * 334 * Valid display flags: 335 * {@link SurfaceControl#DISPLAY_RECEIVES_INPUT} 336 */ setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags)337 public final void setDisplayFlagsLocked(SurfaceControl.Transaction t, int flags) { 338 if (mCurrentFlags != flags) { 339 mCurrentFlags = flags; 340 t.setDisplayFlags(mDisplayToken, flags); 341 } 342 } 343 344 /** 345 * Sets the display projection while in a transaction. 346 * 347 * @param orientation defines the display's orientation 348 * @param layerStackRect defines which area of the window manager coordinate 349 * space will be used 350 * @param displayRect defines where on the display will layerStackRect be 351 * mapped to. displayRect is specified post-orientation, that is 352 * it uses the orientation seen by the end-user 353 */ setProjectionLocked(SurfaceControl.Transaction t, int orientation, Rect layerStackRect, Rect displayRect)354 public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation, 355 Rect layerStackRect, Rect displayRect) { 356 if (mCurrentOrientation != orientation 357 || mCurrentLayerStackRect == null 358 || !mCurrentLayerStackRect.equals(layerStackRect) 359 || mCurrentDisplayRect == null 360 || !mCurrentDisplayRect.equals(displayRect)) { 361 mCurrentOrientation = orientation; 362 363 if (mCurrentLayerStackRect == null) { 364 mCurrentLayerStackRect = new Rect(); 365 } 366 mCurrentLayerStackRect.set(layerStackRect); 367 368 if (mCurrentDisplayRect == null) { 369 mCurrentDisplayRect = new Rect(); 370 } 371 mCurrentDisplayRect.set(displayRect); 372 373 t.setDisplayProjection(mDisplayToken, 374 orientation, layerStackRect, displayRect); 375 } 376 } 377 378 /** 379 * Configure transaction with the display size. 380 */ configureDisplaySizeLocked(SurfaceControl.Transaction t)381 public void configureDisplaySizeLocked(SurfaceControl.Transaction t) { 382 DisplayDeviceInfo info = getDisplayDeviceInfoLocked(); 383 boolean isInstalledRotated = info.installOrientation == ROTATION_90 384 || info.installOrientation == ROTATION_270; 385 int displayWidth = isInstalledRotated ? info.height : info.width; 386 int displayHeight = isInstalledRotated ? info.width : info.height; 387 setDisplaySizeLocked(t, displayWidth, displayHeight); 388 } 389 390 /** 391 * Sets display size while in a transaction. 392 */ setDisplaySizeLocked(SurfaceControl.Transaction t, int width, int height)393 public final void setDisplaySizeLocked(SurfaceControl.Transaction t, int width, int height) { 394 if (width != mLastDisplayWidth && height != mLastDisplayHeight) { 395 mLastDisplayWidth = width; 396 mLastDisplayHeight = height; 397 t.setDisplaySize(mDisplayToken, width, height); 398 } 399 } 400 401 /** 402 * Sets the display surface while in a transaction. 403 */ setSurfaceLocked(SurfaceControl.Transaction t, Surface surface)404 public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) { 405 if (mCurrentSurface != surface) { 406 mCurrentSurface = surface; 407 t.setDisplaySurface(mDisplayToken, surface); 408 } 409 } 410 411 /** 412 * Populates the specified viewport object with orientation, 413 * physical and logical rects based on the display's current projection. 414 */ populateViewportLocked(DisplayViewport viewport)415 public final void populateViewportLocked(DisplayViewport viewport) { 416 viewport.orientation = mCurrentOrientation; 417 418 if (mCurrentLayerStackRect != null) { 419 viewport.logicalFrame.set(mCurrentLayerStackRect); 420 } else { 421 viewport.logicalFrame.setEmpty(); 422 } 423 424 if (mCurrentDisplayRect != null) { 425 viewport.physicalFrame.set(mCurrentDisplayRect); 426 } else { 427 viewport.physicalFrame.setEmpty(); 428 } 429 430 final boolean isRotated = isRotatedLocked(); 431 DisplayDeviceInfo info = getDisplayDeviceInfoLocked(); 432 viewport.deviceWidth = isRotated ? info.height : info.width; 433 viewport.deviceHeight = isRotated ? info.width : info.height; 434 435 viewport.uniqueId = info.uniqueId; 436 437 if (info.address instanceof DisplayAddress.Physical) { 438 viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort(); 439 } else { 440 viewport.physicalPort = null; 441 } 442 } 443 444 /** 445 * Dumps the local state of the display device. 446 * Does not need to dump the display device info because that is already dumped elsewhere. 447 */ dumpLocked(PrintWriter pw)448 public void dumpLocked(PrintWriter pw) { 449 pw.println("mAdapter=" + mDisplayAdapter.getName()); 450 pw.println("mUniqueId=" + mUniqueId); 451 pw.println("mDisplayToken=" + mDisplayToken); 452 pw.println("mCurrentLayerStack=" + mCurrentLayerStack); 453 pw.println("mCurrentFlags=" + mCurrentFlags); 454 pw.println("mCurrentOrientation=" + mCurrentOrientation); 455 pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect); 456 pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect); 457 pw.println("mCurrentSurface=" + mCurrentSurface); 458 } 459 460 /** 461 * @return whether the orientation is {@link ROTATION_90} or {@link ROTATION_270}. 462 */ isRotatedLocked()463 boolean isRotatedLocked() { 464 return mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270; 465 } 466 467 /** 468 * @return set of supported resolutions as an ascending sorted array. 469 */ getSupportedResolutionsLocked()470 Point[] getSupportedResolutionsLocked() { 471 ArraySet<Point> resolutions = new ArraySet<>(2); 472 Display.Mode[] supportedModes = getDisplayDeviceInfoLocked().supportedModes; 473 for (Display.Mode mode : supportedModes) { 474 resolutions.add(new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight())); 475 } 476 Point[] sortedArray = new Point[resolutions.size()]; 477 resolutions.toArray(sortedArray); 478 Arrays.sort(sortedArray, (p1, p2) -> p1.x * p1.y - p2.x * p2.y); 479 return sortedArray; 480 } 481 loadDisplayDeviceConfig()482 private DisplayDeviceConfig loadDisplayDeviceConfig() { 483 return DisplayDeviceConfig.create(mContext, /* useConfigXml= */ false, 484 mDisplayAdapter.getFeatureFlags()); 485 } 486 } 487