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.os.Trace.TRACE_TAG_WINDOW_MANAGER; 20 import static android.view.Display.Mode.INVALID_MODE_ID; 21 22 import android.app.ActivityThread; 23 import android.content.Context; 24 import android.content.res.Resources; 25 import android.hardware.sidekick.SidekickInternal; 26 import android.os.Build; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.Looper; 30 import android.os.PowerManager; 31 import android.os.SystemProperties; 32 import android.os.Trace; 33 import android.util.DisplayUtils; 34 import android.util.LongSparseArray; 35 import android.util.Slog; 36 import android.util.SparseArray; 37 import android.view.Display; 38 import android.view.DisplayAddress; 39 import android.view.DisplayCutout; 40 import android.view.DisplayEventReceiver; 41 import android.view.DisplayShape; 42 import android.view.RoundedCorners; 43 import android.view.SurfaceControl; 44 45 import com.android.internal.R; 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.display.BrightnessSynchronizer; 48 import com.android.internal.util.function.pooled.PooledLambda; 49 import com.android.server.LocalServices; 50 import com.android.server.display.mode.DisplayModeDirector; 51 import com.android.server.lights.LightsManager; 52 import com.android.server.lights.LogicalLight; 53 54 import java.io.PrintWriter; 55 import java.util.ArrayList; 56 import java.util.Arrays; 57 import java.util.Collections; 58 import java.util.List; 59 import java.util.Objects; 60 61 /** 62 * A display adapter for the local displays managed by SurfaceFlinger. 63 * <p> 64 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. 65 * </p> 66 */ 67 final class LocalDisplayAdapter extends DisplayAdapter { 68 private static final String TAG = "LocalDisplayAdapter"; 69 private static final boolean DEBUG = false; 70 71 private static final String UNIQUE_ID_PREFIX = "local:"; 72 73 private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; 74 75 private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>(); 76 77 private final Injector mInjector; 78 79 private final SurfaceControlProxy mSurfaceControlProxy; 80 81 private final boolean mIsBootDisplayModeSupported; 82 83 private Context mOverlayContext; 84 85 // Called with SyncRoot lock held. LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener)86 public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 87 Context context, Handler handler, Listener listener) { 88 this(syncRoot, context, handler, listener, new Injector()); 89 } 90 91 @VisibleForTesting LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Injector injector)92 LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, 93 Context context, Handler handler, Listener listener, Injector injector) { 94 super(syncRoot, context, handler, listener, TAG); 95 mInjector = injector; 96 mSurfaceControlProxy = mInjector.getSurfaceControlProxy(); 97 mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport(); 98 } 99 100 @Override registerLocked()101 public void registerLocked() { 102 super.registerLocked(); 103 104 mInjector.setDisplayEventListenerLocked(getHandler().getLooper(), 105 new LocalDisplayEventListener()); 106 107 for (long physicalDisplayId : mSurfaceControlProxy.getPhysicalDisplayIds()) { 108 tryConnectDisplayLocked(physicalDisplayId); 109 } 110 } 111 tryConnectDisplayLocked(long physicalDisplayId)112 private void tryConnectDisplayLocked(long physicalDisplayId) { 113 final IBinder displayToken = 114 mSurfaceControlProxy.getPhysicalDisplayToken(physicalDisplayId); 115 if (displayToken != null) { 116 SurfaceControl.StaticDisplayInfo staticInfo = 117 mSurfaceControlProxy.getStaticDisplayInfo(physicalDisplayId); 118 if (staticInfo == null) { 119 Slog.w(TAG, "No valid static info found for display device " + physicalDisplayId); 120 return; 121 } 122 SurfaceControl.DynamicDisplayInfo dynamicInfo = 123 mSurfaceControlProxy.getDynamicDisplayInfo(physicalDisplayId); 124 if (dynamicInfo == null) { 125 Slog.w(TAG, "No valid dynamic info found for display device " + physicalDisplayId); 126 return; 127 } 128 if (dynamicInfo.supportedDisplayModes == null) { 129 // There are no valid modes for this device, so we can't use it 130 Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId); 131 return; 132 } 133 if (dynamicInfo.activeDisplayModeId < 0) { 134 // There is no active mode, and for now we don't have the 135 // policy to set one. 136 Slog.w(TAG, "No valid active mode found for display device " + physicalDisplayId); 137 return; 138 } 139 if (dynamicInfo.activeColorMode < 0) { 140 // We failed to get the active color mode. We don't bail out here since on the next 141 // configuration pass we'll go ahead and set it to whatever it was set to last (or 142 // COLOR_MODE_NATIVE if this is the first configuration). 143 Slog.w(TAG, "No valid active color mode for display device " + physicalDisplayId); 144 dynamicInfo.activeColorMode = Display.COLOR_MODE_INVALID; 145 } 146 SurfaceControl.DesiredDisplayModeSpecs modeSpecs = 147 mSurfaceControlProxy.getDesiredDisplayModeSpecs(displayToken); 148 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 149 if (device == null) { 150 // Display was added. 151 final boolean isFirstDisplay = mDevices.size() == 0; 152 device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo, 153 dynamicInfo, modeSpecs, isFirstDisplay); 154 mDevices.put(physicalDisplayId, device); 155 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); 156 } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo, 157 modeSpecs)) { 158 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); 159 } 160 } else { 161 // The display is no longer available. Ignore the attempt to add it. 162 // If it was connected but has already been disconnected, we'll get a 163 // disconnect event that will remove it from mDevices. 164 } 165 } 166 tryDisconnectDisplayLocked(long physicalDisplayId)167 private void tryDisconnectDisplayLocked(long physicalDisplayId) { 168 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 169 if (device != null) { 170 // Display was removed. 171 mDevices.remove(physicalDisplayId); 172 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 173 } 174 } 175 getPowerModeForState(int state)176 static int getPowerModeForState(int state) { 177 switch (state) { 178 case Display.STATE_OFF: 179 return SurfaceControl.POWER_MODE_OFF; 180 case Display.STATE_DOZE: 181 return SurfaceControl.POWER_MODE_DOZE; 182 case Display.STATE_DOZE_SUSPEND: 183 return SurfaceControl.POWER_MODE_DOZE_SUSPEND; 184 case Display.STATE_ON_SUSPEND: 185 return SurfaceControl.POWER_MODE_ON_SUSPEND; 186 default: 187 return SurfaceControl.POWER_MODE_NORMAL; 188 } 189 } 190 191 private final class LocalDisplayDevice extends DisplayDevice { 192 private final long mPhysicalDisplayId; 193 private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>(); 194 private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>(); 195 private final DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs = 196 new DisplayModeDirector.DesiredDisplayModeSpecs(); 197 private final boolean mIsFirstDisplay; 198 private final BacklightAdapter mBacklightAdapter; 199 private final SidekickInternal mSidekickInternal; 200 201 private DisplayDeviceInfo mInfo; 202 private boolean mHavePendingChanges; 203 private int mState = Display.STATE_UNKNOWN; 204 private int mCommittedState = Display.STATE_UNKNOWN; 205 206 // This is only set in the runnable returned from requestDisplayStateLocked. 207 private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; 208 private float mSdrBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; 209 private float mCurrentHdrSdrRatio = Float.NaN; 210 private int mDefaultModeId = INVALID_MODE_ID; 211 private int mSystemPreferredModeId = INVALID_MODE_ID; 212 private int mDefaultModeGroup; 213 private int mUserPreferredModeId = INVALID_MODE_ID; 214 // This is used only for the purpose of testing, to verify if the mode was correct when the 215 // device started or booted. 216 private int mActiveSfDisplayModeAtStartId = INVALID_MODE_ID; 217 private Display.Mode mUserPreferredMode; 218 private int mActiveModeId = INVALID_MODE_ID; 219 private boolean mDisplayModeSpecsInvalid; 220 private int mActiveColorMode; 221 private Display.HdrCapabilities mHdrCapabilities; 222 private boolean mAllmSupported; 223 private boolean mGameContentTypeSupported; 224 private boolean mAllmRequested; 225 private boolean mGameContentTypeRequested; 226 private boolean mSidekickActive; 227 private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo; 228 // The supported display modes according to SurfaceFlinger 229 private SurfaceControl.DisplayMode[] mSfDisplayModes; 230 // The active display mode in SurfaceFlinger 231 private SurfaceControl.DisplayMode mActiveSfDisplayMode; 232 // The active display vsync period in SurfaceFlinger 233 private float mActiveRenderFrameRate; 234 235 private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides = 236 new DisplayEventReceiver.FrameRateOverride[0]; 237 LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.StaticDisplayInfo staticDisplayInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay)238 LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, 239 SurfaceControl.StaticDisplayInfo staticDisplayInfo, 240 SurfaceControl.DynamicDisplayInfo dynamicInfo, 241 SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay) { 242 super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId, 243 getContext()); 244 mPhysicalDisplayId = physicalDisplayId; 245 mIsFirstDisplay = isFirstDisplay; 246 updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs); 247 mSidekickInternal = LocalServices.getService(SidekickInternal.class); 248 mBacklightAdapter = new BacklightAdapter(displayToken, isFirstDisplay, 249 mSurfaceControlProxy); 250 mActiveSfDisplayModeAtStartId = dynamicInfo.activeDisplayModeId; 251 } 252 253 @Override hasStableUniqueId()254 public boolean hasStableUniqueId() { 255 return true; 256 } 257 258 /** 259 * Returns the boot display mode of this display. 260 * @hide 261 */ 262 @Override getActiveDisplayModeAtStartLocked()263 public Display.Mode getActiveDisplayModeAtStartLocked() { 264 return findMode(findMatchingModeIdLocked(mActiveSfDisplayModeAtStartId)); 265 } 266 267 /** 268 * Returns true if there is a change. 269 **/ updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)270 public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, 271 SurfaceControl.DynamicDisplayInfo dynamicInfo, 272 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 273 boolean changed = updateDisplayModesLocked( 274 dynamicInfo.supportedDisplayModes, dynamicInfo.preferredBootDisplayMode, 275 dynamicInfo.activeDisplayModeId, dynamicInfo.renderFrameRate, modeSpecs); 276 changed |= updateStaticInfo(staticInfo); 277 changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, 278 dynamicInfo.activeColorMode); 279 changed |= updateHdrCapabilitiesLocked(dynamicInfo.hdrCapabilities); 280 changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported); 281 changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported); 282 283 if (changed) { 284 mHavePendingChanges = true; 285 } 286 return changed; 287 } 288 updateDisplayModesLocked( SurfaceControl.DisplayMode[] displayModes, int preferredSfDisplayModeId, int activeSfDisplayModeId, float renderFrameRate, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)289 public boolean updateDisplayModesLocked( 290 SurfaceControl.DisplayMode[] displayModes, int preferredSfDisplayModeId, 291 int activeSfDisplayModeId, float renderFrameRate, 292 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 293 mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length); 294 mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId); 295 SurfaceControl.DisplayMode preferredSfDisplayMode = 296 getModeById(displayModes, preferredSfDisplayModeId); 297 298 // Build an updated list of all existing modes. 299 ArrayList<DisplayModeRecord> records = new ArrayList<>(); 300 boolean modesAdded = false; 301 for (int i = 0; i < displayModes.length; i++) { 302 SurfaceControl.DisplayMode mode = displayModes[i]; 303 List<Float> alternativeRefreshRates = new ArrayList<>(); 304 for (int j = 0; j < displayModes.length; j++) { 305 SurfaceControl.DisplayMode other = displayModes[j]; 306 boolean isAlternative = j != i && other.width == mode.width 307 && other.height == mode.height 308 && other.refreshRate != mode.refreshRate 309 && other.group == mode.group; 310 if (isAlternative) { 311 alternativeRefreshRates.add(displayModes[j].refreshRate); 312 } 313 } 314 Collections.sort(alternativeRefreshRates); 315 316 // First, check to see if we've already added a matching mode. Since not all 317 // configuration options are exposed via Display.Mode, it's possible that we have 318 // multiple DisplayModes that would generate the same Display.Mode. 319 boolean existingMode = false; 320 for (DisplayModeRecord record : records) { 321 if (record.hasMatchingMode(mode) 322 && refreshRatesEquals(alternativeRefreshRates, 323 record.mMode.getAlternativeRefreshRates())) { 324 existingMode = true; 325 break; 326 } 327 } 328 if (existingMode) { 329 continue; 330 } 331 // If we haven't already added a mode for this configuration to the new set of 332 // supported modes then check to see if we have one in the prior set of supported 333 // modes to reuse. 334 DisplayModeRecord record = findDisplayModeRecord(mode, alternativeRefreshRates); 335 if (record == null) { 336 float[] alternativeRates = new float[alternativeRefreshRates.size()]; 337 for (int j = 0; j < alternativeRates.length; j++) { 338 alternativeRates[j] = alternativeRefreshRates.get(j); 339 } 340 record = new DisplayModeRecord(mode, alternativeRates); 341 modesAdded = true; 342 } 343 records.add(record); 344 } 345 346 // Get the currently active mode 347 DisplayModeRecord activeRecord = null; 348 for (DisplayModeRecord record : records) { 349 if (record.hasMatchingMode(mActiveSfDisplayMode)) { 350 activeRecord = record; 351 break; 352 } 353 } 354 355 boolean preferredModeChanged = false; 356 357 if (preferredSfDisplayModeId != INVALID_MODE_ID && preferredSfDisplayMode != null) { 358 DisplayModeRecord preferredRecord = null; 359 for (DisplayModeRecord record : records) { 360 if (record.hasMatchingMode(preferredSfDisplayMode)) { 361 preferredRecord = record; 362 break; 363 } 364 } 365 366 if (preferredRecord != null) { 367 int preferredModeId = preferredRecord.mMode.getModeId(); 368 if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) { 369 mSystemPreferredModeId = preferredModeId; 370 preferredModeChanged = true; 371 } 372 } 373 } 374 375 boolean activeModeChanged = false; 376 377 // Check whether SurfaceFlinger or the display device changed the active mode out from 378 // under us. 379 if (mActiveModeId != INVALID_MODE_ID 380 && mActiveModeId != activeRecord.mMode.getModeId()) { 381 Slog.d(TAG, "The active mode was changed from SurfaceFlinger or the display" 382 + " device to " + activeRecord.mMode); 383 mActiveModeId = activeRecord.mMode.getModeId(); 384 activeModeChanged = true; 385 sendTraversalRequestLocked(); 386 } 387 388 boolean renderFrameRateChanged = false; 389 390 if (mActiveRenderFrameRate > 0 && mActiveRenderFrameRate != renderFrameRate) { 391 Slog.d(TAG, "The render frame rate was changed from SurfaceFlinger or the display" 392 + " device to " + renderFrameRate); 393 mActiveRenderFrameRate = renderFrameRate; 394 renderFrameRateChanged = true; 395 sendTraversalRequestLocked(); 396 } 397 398 // Check whether surface flinger spontaneously changed display config specs out from 399 // under us. If so, schedule a traversal to reapply our display config specs. 400 if (mDisplayModeSpecs.baseModeId != INVALID_MODE_ID) { 401 int activeBaseMode = findMatchingModeIdLocked(modeSpecs.defaultMode); 402 // If we can't map the defaultMode index to a mode, then the physical display 403 // modes must have changed, and the code below for handling changes to the 404 // list of available modes will take care of updating display mode specs. 405 if (activeBaseMode == INVALID_MODE_ID 406 || mDisplayModeSpecs.baseModeId != activeBaseMode 407 || !mDisplayModeSpecs.primary.equals(modeSpecs.primaryRanges) 408 || !mDisplayModeSpecs.appRequest.equals(modeSpecs.appRequestRanges)) { 409 mDisplayModeSpecsInvalid = true; 410 sendTraversalRequestLocked(); 411 } 412 } 413 414 boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded; 415 // If the records haven't changed then we're done here. 416 if (!recordsChanged) { 417 return activeModeChanged || preferredModeChanged || renderFrameRateChanged; 418 } 419 420 mSupportedModes.clear(); 421 for (DisplayModeRecord record : records) { 422 mSupportedModes.put(record.mMode.getModeId(), record); 423 } 424 425 // For a new display, we need to initialize the default mode ID. 426 if (mDefaultModeId == INVALID_MODE_ID) { 427 mDefaultModeId = activeRecord.mMode.getModeId(); 428 mDefaultModeGroup = mActiveSfDisplayMode.group; 429 mActiveRenderFrameRate = renderFrameRate; 430 } else if (modesAdded && activeModeChanged) { 431 Slog.d(TAG, "New display modes are added and the active mode has changed, " 432 + "use active mode as default mode."); 433 mDefaultModeId = activeRecord.mMode.getModeId(); 434 mDefaultModeGroup = mActiveSfDisplayMode.group; 435 mActiveRenderFrameRate = renderFrameRate; 436 } else if (findSfDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) { 437 Slog.w(TAG, "Default display mode no longer available, using currently" 438 + " active mode as default."); 439 mDefaultModeId = activeRecord.mMode.getModeId(); 440 mDefaultModeGroup = mActiveSfDisplayMode.group; 441 mActiveRenderFrameRate = renderFrameRate; 442 } 443 444 // Determine whether the display mode specs' base mode is still there. 445 if (mSupportedModes.indexOfKey(mDisplayModeSpecs.baseModeId) < 0) { 446 if (mDisplayModeSpecs.baseModeId != INVALID_MODE_ID) { 447 Slog.w(TAG, 448 "DisplayModeSpecs base mode no longer available, using currently" 449 + " active mode."); 450 } 451 mDisplayModeSpecs.baseModeId = activeRecord.mMode.getModeId(); 452 mDisplayModeSpecsInvalid = true; 453 } 454 455 if (mUserPreferredMode != null) { 456 mUserPreferredModeId = findUserPreferredModeIdLocked(mUserPreferredMode); 457 } 458 459 // Determine whether the active mode is still there. 460 if (mSupportedModes.indexOfKey(mActiveModeId) < 0) { 461 if (mActiveModeId != INVALID_MODE_ID) { 462 Slog.w(TAG, "Active display mode no longer available, reverting to default" 463 + " mode."); 464 } 465 mActiveModeId = getPreferredModeId(); 466 } 467 468 // Schedule traversals so that we apply pending changes. 469 sendTraversalRequestLocked(); 470 return true; 471 } 472 473 @Override getDisplayDeviceConfig()474 public DisplayDeviceConfig getDisplayDeviceConfig() { 475 if (mDisplayDeviceConfig == null) { 476 loadDisplayDeviceConfig(); 477 } 478 return mDisplayDeviceConfig; 479 } 480 getPreferredModeId()481 private int getPreferredModeId() { 482 return mUserPreferredModeId != INVALID_MODE_ID 483 ? mUserPreferredModeId 484 : mDefaultModeId; 485 } 486 getLogicalDensity()487 private int getLogicalDensity() { 488 DensityMapping densityMapping = getDisplayDeviceConfig().getDensityMapping(); 489 if (densityMapping == null) { 490 return (int) (mStaticDisplayInfo.density * 160 + 0.5); 491 } 492 493 return densityMapping.getDensityForResolution(mInfo.width, mInfo.height); 494 } 495 loadDisplayDeviceConfig()496 private void loadDisplayDeviceConfig() { 497 // Load display device config 498 final Context context = getOverlayContext(); 499 mDisplayDeviceConfig = mInjector.createDisplayDeviceConfig(context, mPhysicalDisplayId, 500 mIsFirstDisplay); 501 502 // Load brightness HWC quirk 503 mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk( 504 DisplayDeviceConfig.QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC)); 505 } 506 updateStaticInfo(SurfaceControl.StaticDisplayInfo info)507 private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) { 508 if (Objects.equals(mStaticDisplayInfo, info)) { 509 return false; 510 } 511 mStaticDisplayInfo = info; 512 return true; 513 } 514 updateColorModesLocked(int[] colorModes, int activeColorMode)515 private boolean updateColorModesLocked(int[] colorModes, int activeColorMode) { 516 if (colorModes == null) { 517 return false; 518 } 519 520 List<Integer> pendingColorModes = new ArrayList<>(); 521 // Build an updated list of all existing color modes. 522 boolean colorModesAdded = false; 523 for (int colorMode : colorModes) { 524 if (!mSupportedColorModes.contains(colorMode)) { 525 colorModesAdded = true; 526 } 527 pendingColorModes.add(colorMode); 528 } 529 530 boolean colorModesChanged = 531 pendingColorModes.size() != mSupportedColorModes.size() 532 || colorModesAdded; 533 534 // If the supported color modes haven't changed then we're done here. 535 if (!colorModesChanged) { 536 return false; 537 } 538 539 mSupportedColorModes.clear(); 540 mSupportedColorModes.addAll(pendingColorModes); 541 Collections.sort(mSupportedColorModes); 542 543 // Determine whether the active color mode is still there. 544 if (!mSupportedColorModes.contains(mActiveColorMode)) { 545 if (mActiveColorMode != Display.COLOR_MODE_DEFAULT) { 546 Slog.w(TAG, "Active color mode no longer available, reverting" 547 + " to default mode."); 548 mActiveColorMode = Display.COLOR_MODE_DEFAULT; 549 } else { 550 if (!mSupportedColorModes.isEmpty()) { 551 // This should never happen. 552 Slog.e(TAG, "Default and active color mode is no longer available!" 553 + " Reverting to first available mode."); 554 mActiveColorMode = mSupportedColorModes.get(0); 555 } else { 556 // This should really never happen. 557 Slog.e(TAG, "No color modes available!"); 558 } 559 } 560 } 561 return true; 562 } 563 updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities)564 private boolean updateHdrCapabilitiesLocked(Display.HdrCapabilities newHdrCapabilities) { 565 // If the HDR capabilities haven't changed, then we're done here. 566 if (Objects.equals(mHdrCapabilities, newHdrCapabilities)) { 567 return false; 568 } 569 mHdrCapabilities = newHdrCapabilities; 570 return true; 571 } 572 updateAllmSupport(boolean supported)573 private boolean updateAllmSupport(boolean supported) { 574 if (mAllmSupported == supported) { 575 return false; 576 } 577 mAllmSupported = supported; 578 return true; 579 } 580 updateGameContentTypeSupport(boolean supported)581 private boolean updateGameContentTypeSupport(boolean supported) { 582 if (mGameContentTypeSupported == supported) { 583 return false; 584 } 585 mGameContentTypeSupported = supported; 586 return true; 587 } 588 getModeById(SurfaceControl.DisplayMode[] supportedModes, int modeId)589 private SurfaceControl.DisplayMode getModeById(SurfaceControl.DisplayMode[] supportedModes, 590 int modeId) { 591 for (SurfaceControl.DisplayMode mode : supportedModes) { 592 if (mode.id == modeId) { 593 return mode; 594 } 595 } 596 Slog.e(TAG, "Can't find display mode with id " + modeId); 597 return null; 598 } 599 findDisplayModeRecord(SurfaceControl.DisplayMode mode, List<Float> alternativeRefreshRates)600 private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode, 601 List<Float> alternativeRefreshRates) { 602 for (int i = 0; i < mSupportedModes.size(); i++) { 603 DisplayModeRecord record = mSupportedModes.valueAt(i); 604 if (record.hasMatchingMode(mode) 605 && refreshRatesEquals(alternativeRefreshRates, 606 record.mMode.getAlternativeRefreshRates()) 607 && hdrTypesEqual(mode.supportedHdrTypes, 608 record.mMode.getSupportedHdrTypes())) { 609 return record; 610 } 611 } 612 return null; 613 } 614 refreshRatesEquals(List<Float> list, float[] array)615 private boolean refreshRatesEquals(List<Float> list, float[] array) { 616 if (list.size() != array.length) { 617 return false; 618 } 619 for (int i = 0; i < list.size(); i++) { 620 if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) { 621 return false; 622 } 623 } 624 return true; 625 } 626 627 @Override applyPendingDisplayDeviceInfoChangesLocked()628 public void applyPendingDisplayDeviceInfoChangesLocked() { 629 if (mHavePendingChanges) { 630 mInfo = null; 631 mHavePendingChanges = false; 632 } 633 } 634 635 @Override getDisplayDeviceInfoLocked()636 public DisplayDeviceInfo getDisplayDeviceInfoLocked() { 637 if (mInfo == null) { 638 mInfo = new DisplayDeviceInfo(); 639 mInfo.width = mActiveSfDisplayMode.width; 640 mInfo.height = mActiveSfDisplayMode.height; 641 mInfo.modeId = mActiveModeId; 642 mInfo.renderFrameRate = mActiveRenderFrameRate; 643 mInfo.defaultModeId = getPreferredModeId(); 644 mInfo.supportedModes = getDisplayModes(mSupportedModes); 645 mInfo.colorMode = mActiveColorMode; 646 mInfo.allmSupported = mAllmSupported; 647 mInfo.gameContentTypeSupported = mGameContentTypeSupported; 648 mInfo.supportedColorModes = 649 new int[mSupportedColorModes.size()]; 650 for (int i = 0; i < mSupportedColorModes.size(); i++) { 651 mInfo.supportedColorModes[i] = mSupportedColorModes.get(i); 652 } 653 mInfo.hdrCapabilities = mHdrCapabilities; 654 mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos; 655 mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos; 656 mInfo.state = mState; 657 mInfo.committedState = mCommittedState; 658 mInfo.uniqueId = getUniqueId(); 659 final DisplayAddress.Physical physicalAddress = 660 DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); 661 mInfo.address = physicalAddress; 662 mInfo.densityDpi = getLogicalDensity(); 663 mInfo.xDpi = mActiveSfDisplayMode.xDpi; 664 mInfo.yDpi = mActiveSfDisplayMode.yDpi; 665 mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo; 666 667 // Assume that all built-in displays that have secure output (eg. HDCP) also 668 // support compositing from gralloc protected buffers. 669 if (mStaticDisplayInfo.secure) { 670 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE 671 | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; 672 } 673 674 final Resources res = getOverlayContext().getResources(); 675 676 mInfo.flags |= DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; 677 678 if (mIsFirstDisplay) { 679 if (res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound) 680 || (Build.IS_EMULATOR 681 && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { 682 mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; 683 } 684 } else { 685 if (!res.getBoolean(R.bool.config_localDisplaysMirrorContent)) { 686 mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; 687 } 688 689 if (isDisplayPrivate(physicalAddress)) { 690 mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; 691 } 692 } 693 694 if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) { 695 mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT; 696 } 697 698 final Display.Mode maxDisplayMode = 699 DisplayUtils.getMaximumResolutionDisplayMode(mInfo.supportedModes); 700 final int maxWidth = 701 maxDisplayMode == null ? mInfo.width : maxDisplayMode.getPhysicalWidth(); 702 final int maxHeight = 703 maxDisplayMode == null ? mInfo.height : maxDisplayMode.getPhysicalHeight(); 704 705 // We cannot determine cutouts and rounded corners of external displays. 706 if (mStaticDisplayInfo.isInternal) { 707 mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res, 708 mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height); 709 mInfo.roundedCorners = RoundedCorners.fromResources( 710 res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height); 711 } 712 713 mInfo.installOrientation = mStaticDisplayInfo.installOrientation; 714 715 mInfo.displayShape = DisplayShape.fromResources( 716 res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height); 717 718 mInfo.name = getDisplayDeviceConfig().getName(); 719 720 if (mStaticDisplayInfo.isInternal) { 721 mInfo.type = Display.TYPE_INTERNAL; 722 mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 723 mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 724 if (mInfo.name == null) { 725 mInfo.name = res.getString(R.string.display_manager_built_in_display_name); 726 } 727 } else { 728 mInfo.type = Display.TYPE_EXTERNAL; 729 mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 730 mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION; 731 if (mInfo.name == null) { 732 mInfo.name = getContext().getResources().getString( 733 R.string.display_manager_hdmi_display_name); 734 } 735 } 736 mInfo.frameRateOverrides = mFrameRateOverrides; 737 738 // The display is trusted since it is created by system. 739 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED; 740 mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN; 741 mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX; 742 mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault(); 743 mInfo.hdrSdrRatio = mCurrentHdrSdrRatio; 744 } 745 return mInfo; 746 } 747 748 @Override requestDisplayStateLocked(final int state, final float brightnessState, final float sdrBrightnessState)749 public Runnable requestDisplayStateLocked(final int state, final float brightnessState, 750 final float sdrBrightnessState) { 751 // Assume that the brightness is off if the display is being turned off. 752 assert state != Display.STATE_OFF 753 || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT; 754 final boolean stateChanged = (mState != state); 755 final boolean brightnessChanged = mBrightnessState != brightnessState 756 || mSdrBrightnessState != sdrBrightnessState; 757 if (stateChanged || brightnessChanged) { 758 final long physicalDisplayId = mPhysicalDisplayId; 759 final IBinder token = getDisplayTokenLocked(); 760 final int oldState = mState; 761 762 if (stateChanged) { 763 mState = state; 764 updateDeviceInfoLocked(); 765 } 766 767 // Defer actually setting the display state until after we have exited 768 // the critical section since it can take hundreds of milliseconds 769 // to complete. 770 return new Runnable() { 771 @Override 772 public void run() { 773 // Exit a suspended state before making any changes. 774 int currentState = oldState; 775 if (Display.isSuspendedState(oldState) 776 || oldState == Display.STATE_UNKNOWN) { 777 if (!Display.isSuspendedState(state)) { 778 setDisplayState(state); 779 currentState = state; 780 } else if (state == Display.STATE_DOZE_SUSPEND 781 || oldState == Display.STATE_DOZE_SUSPEND) { 782 setDisplayState(Display.STATE_DOZE); 783 currentState = Display.STATE_DOZE; 784 } else if (state == Display.STATE_ON_SUSPEND 785 || oldState == Display.STATE_ON_SUSPEND) { 786 setDisplayState(Display.STATE_ON); 787 currentState = Display.STATE_ON; 788 789 // If UNKNOWN, we still want to set the initial display state, 790 // otherwise, return early. 791 } else if (oldState != Display.STATE_UNKNOWN) { 792 return; // old state and new state is off 793 } 794 } 795 796 // Apply brightness changes given that we are in a non-suspended state. 797 if (brightnessChanged) { 798 setDisplayBrightness(brightnessState, sdrBrightnessState); 799 mBrightnessState = brightnessState; 800 mSdrBrightnessState = sdrBrightnessState; 801 } 802 803 // Enter the final desired state, possibly suspended. 804 if (state != currentState) { 805 setDisplayState(state); 806 } 807 } 808 809 private void setDisplayState(int state) { 810 if (DEBUG) { 811 Slog.d(TAG, "setDisplayState(" 812 + "id=" + physicalDisplayId 813 + ", state=" + Display.stateToString(state) + ")"); 814 } 815 816 // We must tell sidekick to stop controlling the display before we 817 // can change its power mode, so do that first. 818 if (mSidekickActive) { 819 Trace.traceBegin(Trace.TRACE_TAG_POWER, 820 "SidekickInternal#endDisplayControl"); 821 try { 822 mSidekickInternal.endDisplayControl(); 823 } finally { 824 Trace.traceEnd(Trace.TRACE_TAG_POWER); 825 } 826 mSidekickActive = false; 827 } 828 final int mode = getPowerModeForState(state); 829 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState(" 830 + "id=" + physicalDisplayId 831 + ", state=" + Display.stateToString(state) + ")"); 832 try { 833 mSurfaceControlProxy.setDisplayPowerMode(token, mode); 834 Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode); 835 } finally { 836 Trace.traceEnd(Trace.TRACE_TAG_POWER); 837 } 838 setCommittedState(state); 839 // If we're entering a suspended (but not OFF) power state and we 840 // have a sidekick available, tell it now that it can take control. 841 if (Display.isSuspendedState(state) && state != Display.STATE_OFF 842 && mSidekickInternal != null && !mSidekickActive) { 843 Trace.traceBegin(Trace.TRACE_TAG_POWER, 844 "SidekickInternal#startDisplayControl"); 845 try { 846 mSidekickActive = mSidekickInternal.startDisplayControl(state); 847 } finally { 848 Trace.traceEnd(Trace.TRACE_TAG_POWER); 849 } 850 } 851 } 852 853 private void setCommittedState(int state) { 854 // After the display state is set, let's update the committed state. 855 synchronized (getSyncRoot()) { 856 mCommittedState = state; 857 updateDeviceInfoLocked(); 858 } 859 } 860 861 private void setDisplayBrightness(float brightnessState, 862 float sdrBrightnessState) { 863 // brightnessState includes invalid, off and full range. 864 if (Float.isNaN(brightnessState) || Float.isNaN(sdrBrightnessState)) { 865 return; 866 } 867 868 if (DEBUG) { 869 Slog.d(TAG, "setDisplayBrightness(" 870 + "id=" + physicalDisplayId 871 + ", brightnessState=" + brightnessState 872 + ", sdrBrightnessState=" + sdrBrightnessState + ")"); 873 } 874 875 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness(" 876 + "id=" + physicalDisplayId + ", brightnessState=" 877 + brightnessState + ", sdrBrightnessState=" + sdrBrightnessState 878 + ")"); 879 try { 880 final float backlight = brightnessToBacklight(brightnessState); 881 final float sdrBacklight = brightnessToBacklight(sdrBrightnessState); 882 883 final float nits = backlightToNits(backlight); 884 final float sdrNits = backlightToNits(sdrBacklight); 885 886 mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits); 887 Trace.traceCounter(Trace.TRACE_TAG_POWER, 888 "ScreenBrightness", 889 BrightnessSynchronizer.brightnessFloatToInt(brightnessState)); 890 Trace.traceCounter(Trace.TRACE_TAG_POWER, 891 "SdrScreenBrightness", 892 BrightnessSynchronizer.brightnessFloatToInt( 893 sdrBrightnessState)); 894 895 if (getDisplayDeviceConfig().hasSdrToHdrRatioSpline()) { 896 handleHdrSdrNitsChanged(nits, sdrNits); 897 } 898 899 } finally { 900 Trace.traceEnd(Trace.TRACE_TAG_POWER); 901 } 902 } 903 904 private float brightnessToBacklight(float brightness) { 905 if (brightness == PowerManager.BRIGHTNESS_OFF_FLOAT) { 906 return PowerManager.BRIGHTNESS_OFF_FLOAT; 907 } else { 908 return getDisplayDeviceConfig().getBacklightFromBrightness(brightness); 909 } 910 } 911 912 private float backlightToNits(float backlight) { 913 return getDisplayDeviceConfig().getNitsFromBacklight(backlight); 914 } 915 916 void handleHdrSdrNitsChanged(float displayNits, float sdrNits) { 917 final float newHdrSdrRatio; 918 if (displayNits != DisplayDeviceConfig.NITS_INVALID 919 && sdrNits != DisplayDeviceConfig.NITS_INVALID) { 920 // Ensure the ratio stays >= 1.0f as values below that are nonsensical 921 newHdrSdrRatio = Math.max(1.f, displayNits / sdrNits); 922 } else { 923 newHdrSdrRatio = Float.NaN; 924 } 925 if (!BrightnessSynchronizer.floatEquals( 926 mCurrentHdrSdrRatio, newHdrSdrRatio)) { 927 synchronized (getSyncRoot()) { 928 mCurrentHdrSdrRatio = newHdrSdrRatio; 929 updateDeviceInfoLocked(); 930 } 931 } 932 } 933 }; 934 } 935 return null; 936 } 937 938 @Override setUserPreferredDisplayModeLocked(Display.Mode mode)939 public void setUserPreferredDisplayModeLocked(Display.Mode mode) { 940 final int oldModeId = getPreferredModeId(); 941 mUserPreferredMode = mode; 942 // When clearing the user preferred mode we need to also reset the default mode. This is 943 // used by DisplayModeDirector to determine the default resolution, so if we don't clear 944 // it then the resolution won't reset to what it would've been prior to setting a user 945 // preferred display mode. 946 if (mode == null && mSystemPreferredModeId != INVALID_MODE_ID) { 947 mDefaultModeId = mSystemPreferredModeId; 948 } 949 if (mode != null && (mode.isRefreshRateSet() || mode.isResolutionSet())) { 950 Display.Mode matchingSupportedMode; 951 matchingSupportedMode = findMode(mode.getPhysicalWidth(), 952 mode.getPhysicalHeight(), mode.getRefreshRate()); 953 if (matchingSupportedMode != null) { 954 mUserPreferredMode = matchingSupportedMode; 955 } 956 } 957 958 mUserPreferredModeId = findUserPreferredModeIdLocked(mUserPreferredMode); 959 960 if (oldModeId == getPreferredModeId()) { 961 return; 962 } 963 updateDeviceInfoLocked(); 964 965 if (!mIsBootDisplayModeSupported) { 966 return; 967 } 968 if (mUserPreferredModeId == INVALID_MODE_ID) { 969 mSurfaceControlProxy.clearBootDisplayMode(getDisplayTokenLocked()); 970 } else { 971 int preferredSfDisplayModeId = findSfDisplayModeIdLocked( 972 mUserPreferredMode.getModeId(), mDefaultModeGroup); 973 mSurfaceControlProxy.setBootDisplayMode(getDisplayTokenLocked(), 974 preferredSfDisplayModeId); 975 } 976 } 977 978 @Override getUserPreferredDisplayModeLocked()979 public Display.Mode getUserPreferredDisplayModeLocked() { 980 return mUserPreferredMode; 981 } 982 983 @Override getSystemPreferredDisplayModeLocked()984 public Display.Mode getSystemPreferredDisplayModeLocked() { 985 return findMode(mSystemPreferredModeId); 986 } 987 988 @Override setRequestedColorModeLocked(int colorMode)989 public void setRequestedColorModeLocked(int colorMode) { 990 requestColorModeLocked(colorMode); 991 } 992 993 @Override setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs)994 public void setDesiredDisplayModeSpecsLocked( 995 DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) { 996 if (displayModeSpecs.baseModeId == 0) { 997 // Bail if the caller is requesting a null mode. We'll get called again shortly with 998 // a valid mode. 999 return; 1000 } 1001 1002 // Find the mode Id based on the desired mode specs. In case there is more than one 1003 // mode matching the mode spec, prefer the one that is in the default mode group. 1004 // For now the default config mode is taken from the active mode when we got the 1005 // hotplug event for the display. In the future we might want to change the default 1006 // mode based on vendor requirements. 1007 // Note: We prefer the default mode group over the current one as this is the mode 1008 // group the vendor prefers. 1009 int baseSfModeId = findSfDisplayModeIdLocked(displayModeSpecs.baseModeId, 1010 mDefaultModeGroup); 1011 if (baseSfModeId < 0) { 1012 // When a display is hotplugged, it's possible for a mode to be removed that was 1013 // previously valid. Because of the way display changes are propagated through the 1014 // framework, and the caching of the display mode specs in LogicalDisplay, it's 1015 // possible we'll get called with a stale mode id that no longer represents a valid 1016 // mode. This should only happen in extremely rare cases. A followup call will 1017 // contain a valid mode id. 1018 Slog.w(TAG, 1019 "Ignoring request for invalid base mode id " + displayModeSpecs.baseModeId); 1020 updateDeviceInfoLocked(); 1021 return; 1022 } 1023 if (mDisplayModeSpecsInvalid || !displayModeSpecs.equals(mDisplayModeSpecs)) { 1024 mDisplayModeSpecsInvalid = false; 1025 mDisplayModeSpecs.copyFrom(displayModeSpecs); 1026 getHandler().sendMessage(PooledLambda.obtainMessage( 1027 LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this, 1028 getDisplayTokenLocked(), 1029 new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId, 1030 mDisplayModeSpecs.allowGroupSwitching, 1031 mDisplayModeSpecs.primary, 1032 mDisplayModeSpecs.appRequest))); 1033 } 1034 } 1035 setDesiredDisplayModeSpecsAsync(IBinder displayToken, SurfaceControl.DesiredDisplayModeSpecs modeSpecs)1036 private void setDesiredDisplayModeSpecsAsync(IBinder displayToken, 1037 SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { 1038 // Do not lock when calling these SurfaceControl methods because they are sync 1039 // operations that may block for a while when setting display power mode. 1040 mSurfaceControlProxy.setDesiredDisplayModeSpecs(displayToken, modeSpecs); 1041 } 1042 1043 @Override onOverlayChangedLocked()1044 public void onOverlayChangedLocked() { 1045 updateDeviceInfoLocked(); 1046 } 1047 onActiveDisplayModeChangedLocked(int sfModeId, float renderFrameRate)1048 public void onActiveDisplayModeChangedLocked(int sfModeId, float renderFrameRate) { 1049 if (updateActiveModeLocked(sfModeId, renderFrameRate)) { 1050 updateDeviceInfoLocked(); 1051 } 1052 } 1053 onFrameRateOverridesChanged( DisplayEventReceiver.FrameRateOverride[] overrides)1054 public void onFrameRateOverridesChanged( 1055 DisplayEventReceiver.FrameRateOverride[] overrides) { 1056 if (updateFrameRateOverridesLocked(overrides)) { 1057 updateDeviceInfoLocked(); 1058 } 1059 } 1060 updateActiveModeLocked(int activeSfModeId, float renderFrameRate)1061 public boolean updateActiveModeLocked(int activeSfModeId, float renderFrameRate) { 1062 if (mActiveSfDisplayMode.id == activeSfModeId 1063 && mActiveRenderFrameRate == renderFrameRate) { 1064 return false; 1065 } 1066 mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId); 1067 mActiveModeId = findMatchingModeIdLocked(activeSfModeId); 1068 if (mActiveModeId == INVALID_MODE_ID) { 1069 Slog.w(TAG, "In unknown mode after setting allowed modes" 1070 + ", activeModeId=" + activeSfModeId); 1071 } 1072 mActiveRenderFrameRate = renderFrameRate; 1073 return true; 1074 } 1075 updateFrameRateOverridesLocked( DisplayEventReceiver.FrameRateOverride[] overrides)1076 public boolean updateFrameRateOverridesLocked( 1077 DisplayEventReceiver.FrameRateOverride[] overrides) { 1078 if (Arrays.equals(overrides, mFrameRateOverrides)) { 1079 return false; 1080 } 1081 1082 mFrameRateOverrides = overrides; 1083 return true; 1084 } 1085 requestColorModeLocked(int colorMode)1086 public void requestColorModeLocked(int colorMode) { 1087 if (mActiveColorMode == colorMode) { 1088 return; 1089 } 1090 if (!mSupportedColorModes.contains(colorMode)) { 1091 Slog.w(TAG, "Unable to find color mode " + colorMode 1092 + ", ignoring request."); 1093 return; 1094 } 1095 1096 mActiveColorMode = colorMode; 1097 getHandler().sendMessage(PooledLambda.obtainMessage( 1098 LocalDisplayDevice::requestColorModeAsync, this, 1099 getDisplayTokenLocked(), colorMode)); 1100 } 1101 requestColorModeAsync(IBinder displayToken, int colorMode)1102 private void requestColorModeAsync(IBinder displayToken, int colorMode) { 1103 // Do not lock when calling this SurfaceControl method because it is a sync operation 1104 // that may block for a while when setting display power mode. 1105 mSurfaceControlProxy.setActiveColorMode(displayToken, colorMode); 1106 synchronized (getSyncRoot()) { 1107 updateDeviceInfoLocked(); 1108 } 1109 } 1110 1111 @Override setAutoLowLatencyModeLocked(boolean on)1112 public void setAutoLowLatencyModeLocked(boolean on) { 1113 if (mAllmRequested == on) { 1114 return; 1115 } 1116 1117 mAllmRequested = on; 1118 1119 if (!mAllmSupported) { 1120 Slog.d(TAG, "Unable to set ALLM because the connected display " 1121 + "does not support ALLM."); 1122 return; 1123 } 1124 1125 mSurfaceControlProxy.setAutoLowLatencyMode(getDisplayTokenLocked(), on); 1126 } 1127 1128 @Override setGameContentTypeLocked(boolean on)1129 public void setGameContentTypeLocked(boolean on) { 1130 if (mGameContentTypeRequested == on) { 1131 return; 1132 } 1133 1134 mGameContentTypeRequested = on; 1135 1136 // Even if game content type is not supported on the connected display we 1137 // propagate the requested state down to the HAL. This is because some devices 1138 // with external displays, such as Android TV set-top boxes, use this signal 1139 // to disable/enable on-device processing. 1140 // TODO(b/202378408) set game content type only if it's supported once we have a 1141 // separate API for disabling on-device processing. 1142 mSurfaceControlProxy.setGameContentType(getDisplayTokenLocked(), on); 1143 } 1144 1145 @Override dumpLocked(PrintWriter pw)1146 public void dumpLocked(PrintWriter pw) { 1147 super.dumpLocked(pw); 1148 pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId); 1149 pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}"); 1150 pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid); 1151 pw.println("mActiveModeId=" + mActiveModeId); 1152 pw.println("mActiveColorMode=" + mActiveColorMode); 1153 pw.println("mDefaultModeId=" + mDefaultModeId); 1154 pw.println("mUserPreferredModeId=" + mUserPreferredModeId); 1155 pw.println("mState=" + Display.stateToString(mState)); 1156 pw.println("mCommittedState=" + Display.stateToString(mCommittedState)); 1157 pw.println("mBrightnessState=" + mBrightnessState); 1158 pw.println("mBacklightAdapter=" + mBacklightAdapter); 1159 pw.println("mAllmSupported=" + mAllmSupported); 1160 pw.println("mAllmRequested=" + mAllmRequested); 1161 pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported); 1162 pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested); 1163 pw.println("mStaticDisplayInfo=" + mStaticDisplayInfo); 1164 pw.println("mSfDisplayModes="); 1165 for (SurfaceControl.DisplayMode sfDisplayMode : mSfDisplayModes) { 1166 pw.println(" " + sfDisplayMode); 1167 } 1168 pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode); 1169 pw.println("mActiveRenderFrameRate=" + mActiveRenderFrameRate); 1170 pw.println("mSupportedModes="); 1171 for (int i = 0; i < mSupportedModes.size(); i++) { 1172 pw.println(" " + mSupportedModes.valueAt(i)); 1173 } 1174 pw.println("mSupportedColorModes=" + mSupportedColorModes); 1175 pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig); 1176 } 1177 findSfDisplayModeIdLocked(int displayModeId, int modeGroup)1178 private int findSfDisplayModeIdLocked(int displayModeId, int modeGroup) { 1179 int matchingSfDisplayModeId = INVALID_MODE_ID; 1180 DisplayModeRecord record = mSupportedModes.get(displayModeId); 1181 if (record != null) { 1182 for (SurfaceControl.DisplayMode mode : mSfDisplayModes) { 1183 if (record.hasMatchingMode(mode)) { 1184 if (matchingSfDisplayModeId == INVALID_MODE_ID) { 1185 matchingSfDisplayModeId = mode.id; 1186 } 1187 1188 // Prefer to return a mode that matches the modeGroup 1189 if (mode.group == modeGroup) { 1190 return mode.id; 1191 } 1192 } 1193 } 1194 } 1195 return matchingSfDisplayModeId; 1196 } 1197 1198 // Returns a mode with id = modeId. findMode(int modeId)1199 private Display.Mode findMode(int modeId) { 1200 for (int i = 0; i < mSupportedModes.size(); i++) { 1201 Display.Mode supportedMode = mSupportedModes.valueAt(i).mMode; 1202 if (supportedMode.getModeId() == modeId) { 1203 return supportedMode; 1204 } 1205 } 1206 return null; 1207 } 1208 1209 // Returns a mode with resolution (width, height) and/or refreshRate. If any one of the 1210 // resolution or refresh-rate is valid, a mode having the valid parameters is returned. findMode(int width, int height, float refreshRate)1211 private Display.Mode findMode(int width, int height, float refreshRate) { 1212 for (int i = 0; i < mSupportedModes.size(); i++) { 1213 Display.Mode supportedMode = mSupportedModes.valueAt(i).mMode; 1214 if (supportedMode.matchesIfValid(width, height, refreshRate)) { 1215 return supportedMode; 1216 } 1217 } 1218 return null; 1219 } 1220 findUserPreferredModeIdLocked(Display.Mode userPreferredMode)1221 private int findUserPreferredModeIdLocked(Display.Mode userPreferredMode) { 1222 if (userPreferredMode != null) { 1223 for (int i = 0; i < mSupportedModes.size(); i++) { 1224 Display.Mode supportedMode = mSupportedModes.valueAt(i).mMode; 1225 if (userPreferredMode.matches(supportedMode.getPhysicalWidth(), 1226 supportedMode.getPhysicalHeight(), 1227 supportedMode.getRefreshRate())) { 1228 return supportedMode.getModeId(); 1229 } 1230 } 1231 } 1232 return INVALID_MODE_ID; 1233 } 1234 findMatchingModeIdLocked(int sfModeId)1235 private int findMatchingModeIdLocked(int sfModeId) { 1236 SurfaceControl.DisplayMode mode = getModeById(mSfDisplayModes, sfModeId); 1237 if (mode == null) { 1238 Slog.e(TAG, "Invalid display mode ID " + sfModeId); 1239 return INVALID_MODE_ID; 1240 } 1241 for (int i = 0; i < mSupportedModes.size(); i++) { 1242 DisplayModeRecord record = mSupportedModes.valueAt(i); 1243 if (record.hasMatchingMode(mode)) { 1244 return record.mMode.getModeId(); 1245 } 1246 } 1247 return INVALID_MODE_ID; 1248 } 1249 updateDeviceInfoLocked()1250 private void updateDeviceInfoLocked() { 1251 mInfo = null; 1252 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED); 1253 } 1254 getDisplayModes(SparseArray<DisplayModeRecord> records)1255 private Display.Mode[] getDisplayModes(SparseArray<DisplayModeRecord> records) { 1256 final int size = records.size(); 1257 Display.Mode[] modes = new Display.Mode[size]; 1258 for (int i = 0; i < size; i++) { 1259 DisplayModeRecord record = records.valueAt(i); 1260 modes[i] = record.mMode; 1261 } 1262 return modes; 1263 } 1264 isDisplayPrivate(DisplayAddress.Physical physicalAddress)1265 private boolean isDisplayPrivate(DisplayAddress.Physical physicalAddress) { 1266 if (physicalAddress == null) { 1267 return false; 1268 } 1269 final Resources res = getOverlayContext().getResources(); 1270 int[] ports = res.getIntArray(R.array.config_localPrivateDisplayPorts); 1271 if (ports != null) { 1272 int port = physicalAddress.getPort(); 1273 for (int p : ports) { 1274 if (p == port) { 1275 return true; 1276 } 1277 } 1278 } 1279 return false; 1280 } 1281 } 1282 1283 private boolean hdrTypesEqual(int[] modeHdrTypes, int[] recordHdrTypes) { 1284 int[] modeHdrTypesCopy = Arrays.copyOf(modeHdrTypes, modeHdrTypes.length); 1285 Arrays.sort(modeHdrTypesCopy); 1286 // Record HDR types are already sorted when we create the DisplayModeRecord 1287 return Arrays.equals(modeHdrTypesCopy, recordHdrTypes); 1288 } 1289 1290 /** Supplies a context whose Resources apply runtime-overlays */ 1291 Context getOverlayContext() { 1292 if (mOverlayContext == null) { 1293 mOverlayContext = ActivityThread.currentActivityThread().getSystemUiContext(); 1294 } 1295 return mOverlayContext; 1296 } 1297 1298 /** 1299 * Keeps track of a display mode. 1300 */ 1301 private static final class DisplayModeRecord { 1302 public final Display.Mode mMode; 1303 1304 DisplayModeRecord(SurfaceControl.DisplayMode mode, 1305 float[] alternativeRefreshRates) { 1306 mMode = createMode(mode.width, mode.height, mode.refreshRate, 1307 alternativeRefreshRates, mode.supportedHdrTypes); 1308 } 1309 1310 /** 1311 * Returns whether the mode generated by the given DisplayModes matches the mode 1312 * contained by the record modulo mode ID. 1313 * 1314 * Note that this doesn't necessarily mean that the DisplayModes are identical, just 1315 * that they generate identical modes. 1316 */ 1317 public boolean hasMatchingMode(SurfaceControl.DisplayMode mode) { 1318 return mMode.getPhysicalWidth() == mode.width 1319 && mMode.getPhysicalHeight() == mode.height 1320 && Float.floatToIntBits(mMode.getRefreshRate()) 1321 == Float.floatToIntBits(mode.refreshRate); 1322 } 1323 1324 public String toString() { 1325 return "DisplayModeRecord{mMode=" + mMode + "}"; 1326 } 1327 } 1328 1329 public static class Injector { 1330 // Native callback. 1331 @SuppressWarnings("unused") 1332 private ProxyDisplayEventReceiver mReceiver; 1333 public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { 1334 mReceiver = new ProxyDisplayEventReceiver(looper, listener); 1335 } 1336 public SurfaceControlProxy getSurfaceControlProxy() { 1337 return new SurfaceControlProxy(); 1338 } 1339 1340 public DisplayDeviceConfig createDisplayDeviceConfig(Context context, 1341 long physicalDisplayId, boolean isFirstDisplay) { 1342 return DisplayDeviceConfig.create(context, physicalDisplayId, isFirstDisplay); 1343 } 1344 } 1345 1346 public interface DisplayEventListener { 1347 void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); 1348 void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 1349 long renderPeriod); 1350 void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1351 DisplayEventReceiver.FrameRateOverride[] overrides); 1352 1353 } 1354 1355 public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver { 1356 private final DisplayEventListener mListener; 1357 ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) { 1358 super(looper, VSYNC_SOURCE_APP, 1359 EVENT_REGISTRATION_MODE_CHANGED_FLAG 1360 | EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG); 1361 mListener = listener; 1362 } 1363 1364 @Override 1365 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 1366 mListener.onHotplug(timestampNanos, physicalDisplayId, connected); 1367 } 1368 1369 @Override 1370 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 1371 long renderPeriod) { 1372 mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); 1373 } 1374 1375 @Override 1376 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1377 DisplayEventReceiver.FrameRateOverride[] overrides) { 1378 mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); 1379 } 1380 } 1381 1382 private final class LocalDisplayEventListener implements DisplayEventListener { 1383 @Override 1384 public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { 1385 synchronized (getSyncRoot()) { 1386 if (connected) { 1387 tryConnectDisplayLocked(physicalDisplayId); 1388 } else { 1389 tryDisconnectDisplayLocked(physicalDisplayId); 1390 } 1391 } 1392 } 1393 1394 @Override 1395 public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, 1396 long renderPeriod) { 1397 if (DEBUG) { 1398 Slog.d(TAG, "onModeChanged(" 1399 + "timestampNanos=" + timestampNanos 1400 + ", physicalDisplayId=" + physicalDisplayId 1401 + ", modeId=" + modeId 1402 + ", renderPeriod=" + renderPeriod + ")"); 1403 } 1404 synchronized (getSyncRoot()) { 1405 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 1406 if (device == null) { 1407 if (DEBUG) { 1408 Slog.d(TAG, "Received mode change for unhandled physical display: " 1409 + "physicalDisplayId=" + physicalDisplayId); 1410 } 1411 return; 1412 } 1413 float renderFrameRate = 1e9f / renderPeriod; 1414 device.onActiveDisplayModeChangedLocked(modeId, renderFrameRate); 1415 } 1416 } 1417 1418 @Override 1419 public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, 1420 DisplayEventReceiver.FrameRateOverride[] overrides) { 1421 if (DEBUG) { 1422 Slog.d(TAG, "onFrameRateOverrideChanged(timestampNanos=" + timestampNanos 1423 + ", physicalDisplayId=" + physicalDisplayId + " overrides=" 1424 + Arrays.toString(overrides) + ")"); 1425 } 1426 synchronized (getSyncRoot()) { 1427 LocalDisplayDevice device = mDevices.get(physicalDisplayId); 1428 if (device == null) { 1429 if (DEBUG) { 1430 Slog.d(TAG, "Received frame rate override event for unhandled physical" 1431 + " display: physicalDisplayId=" + physicalDisplayId); 1432 } 1433 return; 1434 } 1435 device.onFrameRateOverridesChanged(overrides); 1436 } 1437 } 1438 } 1439 1440 @VisibleForTesting 1441 public static class SurfaceControlProxy { 1442 public SurfaceControl.DynamicDisplayInfo getDynamicDisplayInfo(long displayId) { 1443 return SurfaceControl.getDynamicDisplayInfo(displayId); 1444 } 1445 1446 public long[] getPhysicalDisplayIds() { 1447 return DisplayControl.getPhysicalDisplayIds(); 1448 } 1449 1450 public IBinder getPhysicalDisplayToken(long physicalDisplayId) { 1451 return DisplayControl.getPhysicalDisplayToken(physicalDisplayId); 1452 } 1453 1454 public SurfaceControl.StaticDisplayInfo getStaticDisplayInfo(long displayId) { 1455 return SurfaceControl.getStaticDisplayInfo(displayId); 1456 } 1457 1458 public SurfaceControl.DesiredDisplayModeSpecs getDesiredDisplayModeSpecs( 1459 IBinder displayToken) { 1460 return SurfaceControl.getDesiredDisplayModeSpecs(displayToken); 1461 } 1462 1463 public boolean setDesiredDisplayModeSpecs(IBinder token, 1464 SurfaceControl.DesiredDisplayModeSpecs specs) { 1465 return SurfaceControl.setDesiredDisplayModeSpecs(token, specs); 1466 } 1467 1468 public void setDisplayPowerMode(IBinder displayToken, int mode) { 1469 SurfaceControl.setDisplayPowerMode(displayToken, mode); 1470 } 1471 1472 public boolean setActiveColorMode(IBinder displayToken, int colorMode) { 1473 return SurfaceControl.setActiveColorMode(displayToken, colorMode); 1474 } 1475 1476 public boolean getBootDisplayModeSupport() { 1477 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getBootDisplayModeSupport"); 1478 try { 1479 return SurfaceControl.getBootDisplayModeSupport(); 1480 } finally { 1481 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 1482 } 1483 } 1484 1485 public void setBootDisplayMode(IBinder displayToken, int modeId) { 1486 SurfaceControl.setBootDisplayMode(displayToken, modeId); 1487 } 1488 1489 public void clearBootDisplayMode(IBinder displayToken) { 1490 SurfaceControl.clearBootDisplayMode(displayToken); 1491 } 1492 1493 public void setAutoLowLatencyMode(IBinder displayToken, boolean on) { 1494 SurfaceControl.setAutoLowLatencyMode(displayToken, on); 1495 1496 } 1497 1498 public void setGameContentType(IBinder displayToken, boolean on) { 1499 SurfaceControl.setGameContentType(displayToken, on); 1500 } 1501 1502 public boolean getDisplayBrightnessSupport(IBinder displayToken) { 1503 return SurfaceControl.getDisplayBrightnessSupport(displayToken); 1504 } 1505 1506 public boolean setDisplayBrightness(IBinder displayToken, float brightness) { 1507 return SurfaceControl.setDisplayBrightness(displayToken, brightness); 1508 } 1509 1510 public boolean setDisplayBrightness(IBinder displayToken, float sdrBacklight, 1511 float sdrNits, float displayBacklight, float displayNits) { 1512 return SurfaceControl.setDisplayBrightness(displayToken, sdrBacklight, sdrNits, 1513 displayBacklight, displayNits); 1514 } 1515 } 1516 1517 static class BacklightAdapter { 1518 private final IBinder mDisplayToken; 1519 private final LogicalLight mBacklight; 1520 private final boolean mUseSurfaceControlBrightness; 1521 private final SurfaceControlProxy mSurfaceControlProxy; 1522 1523 private boolean mForceSurfaceControl = false; 1524 1525 /** 1526 * @param displayToken Token for display associated with this backlight. 1527 * @param isFirstDisplay {@code true} if it is the first display. 1528 */ 1529 BacklightAdapter(IBinder displayToken, boolean isFirstDisplay, 1530 SurfaceControlProxy surfaceControlProxy) { 1531 mDisplayToken = displayToken; 1532 mSurfaceControlProxy = surfaceControlProxy; 1533 1534 mUseSurfaceControlBrightness = mSurfaceControlProxy 1535 .getDisplayBrightnessSupport(mDisplayToken); 1536 1537 if (!mUseSurfaceControlBrightness && isFirstDisplay) { 1538 LightsManager lights = LocalServices.getService(LightsManager.class); 1539 mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT); 1540 } else { 1541 mBacklight = null; 1542 } 1543 } 1544 1545 // Set backlight within min and max backlight values 1546 void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) { 1547 if (mUseSurfaceControlBrightness || mForceSurfaceControl) { 1548 if (BrightnessSynchronizer.floatEquals( 1549 sdrBacklight, PowerManager.BRIGHTNESS_INVALID_FLOAT)) { 1550 mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight); 1551 } else { 1552 mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits, 1553 backlight, nits); 1554 } 1555 } else if (mBacklight != null) { 1556 mBacklight.setBrightness(backlight); 1557 } 1558 } 1559 1560 void setForceSurfaceControl(boolean forceSurfaceControl) { 1561 mForceSurfaceControl = forceSurfaceControl; 1562 } 1563 1564 @Override 1565 public String toString() { 1566 return "BacklightAdapter [useSurfaceControl=" + mUseSurfaceControlBrightness 1567 + " (force_anyway? " + mForceSurfaceControl + ")" 1568 + ", backlight=" + mBacklight + "]"; 1569 } 1570 } 1571 } 1572