1 /* 2 * Copyright (C) 2020 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.hardware.devicestate.DeviceState.PROPERTY_EMULATED_ONLY; 20 import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP; 21 import static android.hardware.devicestate.DeviceState.PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE; 22 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE; 23 import static android.view.Display.DEFAULT_DISPLAY; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.hardware.devicestate.DeviceState; 29 import android.hardware.devicestate.DeviceStateManager; 30 import android.hardware.devicestate.feature.flags.FeatureFlags; 31 import android.hardware.devicestate.feature.flags.FeatureFlagsImpl; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.PowerManager; 36 import android.os.SystemClock; 37 import android.os.SystemProperties; 38 import android.text.TextUtils; 39 import android.util.ArrayMap; 40 import android.util.IndentingPrintWriter; 41 import android.util.Slog; 42 import android.util.SparseArray; 43 import android.util.SparseBooleanArray; 44 import android.util.SparseIntArray; 45 import android.view.Display; 46 import android.view.DisplayAddress; 47 import android.view.DisplayInfo; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.foldables.FoldGracePeriodProvider; 51 import com.android.server.LocalServices; 52 import com.android.server.display.feature.DisplayManagerFlags; 53 import com.android.server.display.layout.DisplayIdProducer; 54 import com.android.server.display.layout.Layout; 55 import com.android.server.display.mode.SyntheticModeManager; 56 import com.android.server.display.utils.DebugUtils; 57 import com.android.server.policy.WindowManagerPolicy; 58 import com.android.server.utils.FoldSettingProvider; 59 60 import java.io.PrintWriter; 61 import java.util.Arrays; 62 import java.util.function.Consumer; 63 64 /** 65 * Responsible for creating {@link LogicalDisplay}s and associating them to the 66 * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}. 67 * 68 * Additionally this class will keep track of which {@link DisplayGroup} each 69 * {@link LogicalDisplay} belongs to. 70 * 71 * For devices with a single internal display, the mapping is done once and left 72 * alone. For devices with multiple built-in displays, such as foldable devices, 73 * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s. 74 */ 75 class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { 76 private static final String TAG = "LogicalDisplayMapper"; 77 78 // To enable these logs, run: 79 // 'adb shell setprop persist.log.tag.LogicalDisplayMapper DEBUG && adb reboot' 80 private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); 81 82 public static final int LOGICAL_DISPLAY_EVENT_BASE = 0; 83 public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1 << 0; 84 public static final int LOGICAL_DISPLAY_EVENT_BASIC_CHANGED = 1 << 1; 85 public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 1 << 2; 86 public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 1 << 3; 87 public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 1 << 4; 88 public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 1 << 5; 89 public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 1 << 6; 90 public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 1 << 7; 91 public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 1 << 8; 92 public static final int LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED = 1 << 9; 93 public static final int LOGICAL_DISPLAY_EVENT_STATE_CHANGED = 1 << 10; 94 public static final int LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED = 1 << 11; 95 96 97 public static final int DISPLAY_GROUP_EVENT_ADDED = 1; 98 public static final int DISPLAY_GROUP_EVENT_CHANGED = 2; 99 public static final int DISPLAY_GROUP_EVENT_REMOVED = 3; 100 101 private static final int TIMEOUT_STATE_TRANSITION_MILLIS = 500; 102 103 private static final int MSG_TRANSITION_TO_PENDING_DEVICE_STATE = 1; 104 105 private static final int UPDATE_STATE_NEW = 0; 106 private static final int UPDATE_STATE_TRANSITION = 1; 107 private static final int UPDATE_STATE_UPDATED = 2; 108 109 private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1; 110 111 /** 112 * Temporary display info, used for comparing display configurations. 113 */ 114 private final DisplayInfo mTempDisplayInfo = new DisplayInfo(); 115 private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo(); 116 117 /** 118 * True if the display mapper service should pretend there is only one display 119 * and only tell applications about the existence of the default logical display. 120 * The display manager can still mirror content to secondary displays but applications 121 * cannot present unique content on those displays. 122 * Used for demonstration purposes only. 123 */ 124 private final boolean mSingleDisplayDemoMode; 125 126 /** 127 * True if the device can have more than one internal display on at a time. 128 */ 129 private final boolean mSupportsConcurrentInternalDisplays; 130 131 /** 132 * Wake the device when transitioning into these device state. 133 */ 134 private final SparseBooleanArray mDeviceStatesOnWhichToWakeUp; 135 136 /** 137 * Sleep the device when transitioning into these device state. 138 */ 139 private final SparseBooleanArray mDeviceStatesOnWhichToSelectiveSleep; 140 141 /** 142 * Map of all logical displays indexed by logical display id. 143 * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache. 144 * TODO: multi-display - Move the aforementioned comment? 145 */ 146 private final SparseArray<LogicalDisplay> mLogicalDisplays = 147 new SparseArray<LogicalDisplay>(); 148 149 // Cache whether or not the display was enabled on the last update. 150 private final SparseBooleanArray mDisplaysEnabledCache = new SparseBooleanArray(); 151 152 /** Map of all display groups indexed by display group id. */ 153 private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>(); 154 155 /** 156 * Map of display groups which are linked to virtual devices (all displays in the group are 157 * linked to that device). Keyed by virtual device unique id. 158 */ 159 private final SparseIntArray mDeviceDisplayGroupIds = new SparseIntArray(); 160 161 /** 162 * Map of display group ids indexed by display group name. 163 */ 164 private final ArrayMap<String, Integer> mDisplayGroupIdsByName = new ArrayMap<>(); 165 166 private final DisplayDeviceRepository mDisplayDeviceRepo; 167 private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; 168 private final Listener mListener; 169 private final DisplayManagerService.SyncRoot mSyncRoot; 170 private final LogicalDisplayMapperHandler mHandler; 171 private final FoldSettingProvider mFoldSettingProvider; 172 private final FoldGracePeriodProvider mFoldGracePeriodProvider; 173 private final PowerManager mPowerManager; 174 175 /** 176 * Has an entry for every logical display that the rest of the system has been notified about. 177 * The values are any of the {@code UPDATE_STATE_*} constant types. 178 */ 179 private final SparseIntArray mUpdatedLogicalDisplays = new SparseIntArray(); 180 181 /** 182 * Keeps track of all the display groups that we already told other people about. IOW, if a 183 * display group is in this array, then we *must* send change and remove notifications for it 184 * because other components know about them. Also, what this array stores is a change counter 185 * for each group, so we know if the group itself has changes since we last sent out a 186 * notification. See {@link DisplayGroup#getChangeCountLocked}. 187 */ 188 private final SparseIntArray mUpdatedDisplayGroups = new SparseIntArray(); 189 190 /** 191 * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. 192 */ 193 private final SparseIntArray mLogicalDisplaysToUpdate = new SparseIntArray(); 194 195 /** 196 * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out. 197 */ 198 private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray(); 199 200 /** 201 * ArrayMap of display device unique ID to virtual device ID. Used in {@link 202 * #updateLogicalDisplaysLocked} to establish which Virtual Devices own which Virtual Displays. 203 */ 204 private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>(); 205 private WindowManagerPolicy mWindowManagerPolicy; 206 207 private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; 208 private final DisplayIdProducer mIdProducer = (isDefault) -> 209 isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++; 210 private Layout mCurrentLayout = null; 211 private DeviceState mDeviceState = INVALID_DEVICE_STATE; 212 private DeviceState mPendingDeviceState = INVALID_DEVICE_STATE; 213 private DeviceState mDeviceStateToBeAppliedAfterBoot = INVALID_DEVICE_STATE; 214 private boolean mBootCompleted = false; 215 private boolean mInteractive; 216 private final DisplayManagerFlags mFlags; 217 private final SyntheticModeManager mSyntheticModeManager; 218 private final FeatureFlags mDeviceStateManagerFlags; 219 LogicalDisplayMapper(@onNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, DisplayManagerFlags flags)220 LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, 221 FoldGracePeriodProvider foldGracePeriodProvider, 222 @NonNull DisplayDeviceRepository repo, 223 @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, 224 @NonNull Handler handler, DisplayManagerFlags flags) { 225 this(context, foldSettingProvider, foldGracePeriodProvider, repo, listener, syncRoot, 226 handler, 227 new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY 228 : sNextNonDefaultDisplayId++, flags), flags, 229 new SyntheticModeManager(flags)); 230 } 231 LogicalDisplayMapper(@onNull Context context, FoldSettingProvider foldSettingProvider, FoldGracePeriodProvider foldGracePeriodProvider, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager)232 LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider, 233 FoldGracePeriodProvider foldGracePeriodProvider, 234 @NonNull DisplayDeviceRepository repo, 235 @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, 236 @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap, 237 DisplayManagerFlags flags, SyntheticModeManager syntheticModeManager) { 238 mSyncRoot = syncRoot; 239 mPowerManager = context.getSystemService(PowerManager.class); 240 mInteractive = mPowerManager.isInteractive(); 241 mHandler = new LogicalDisplayMapperHandler(handler.getLooper()); 242 mDisplayDeviceRepo = repo; 243 mListener = listener; 244 mFoldSettingProvider = foldSettingProvider; 245 mFoldGracePeriodProvider = foldGracePeriodProvider; 246 mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); 247 mSupportsConcurrentInternalDisplays = context.getResources().getBoolean( 248 com.android.internal.R.bool.config_supportsConcurrentInternalDisplays); 249 mDeviceStatesOnWhichToWakeUp = toSparseBooleanArray(context.getResources().getIntArray( 250 com.android.internal.R.array.config_deviceStatesOnWhichToWakeUp)); 251 mDeviceStatesOnWhichToSelectiveSleep = toSparseBooleanArray( 252 context.getResources().getIntArray( 253 com.android.internal.R.array.config_deviceStatesOnWhichToSleep)); 254 mDisplayDeviceRepo.addListener(this); 255 mDeviceStateToLayoutMap = deviceStateToLayoutMap; 256 mFlags = flags; 257 mSyntheticModeManager = syntheticModeManager; 258 mDeviceStateManagerFlags = new FeatureFlagsImpl(); 259 } 260 261 @Override onDisplayDeviceEventLocked(DisplayDevice device, int event)262 public void onDisplayDeviceEventLocked(DisplayDevice device, int event) { 263 switch (event) { 264 case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED: 265 if (DEBUG) { 266 Slog.d(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked()); 267 } 268 handleDisplayDeviceAddedLocked(device); 269 break; 270 271 case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED: 272 if (DEBUG) { 273 Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); 274 } 275 handleDisplayDeviceRemovedLocked(device); 276 updateLogicalDisplaysLocked(); 277 break; 278 } 279 } 280 281 @Override onDisplayDeviceChangedLocked(DisplayDevice device, int diff)282 public void onDisplayDeviceChangedLocked(DisplayDevice device, int diff) { 283 if (DEBUG) { 284 Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked()); 285 } 286 finishStateTransitionLocked(false /*force*/); 287 updateLogicalDisplaysLocked(diff); 288 } 289 290 @Override onTraversalRequested()291 public void onTraversalRequested() { 292 mListener.onTraversalRequested(); 293 } 294 onWindowManagerReady()295 public void onWindowManagerReady() { 296 mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); 297 } 298 getDisplayLocked(int displayId)299 public LogicalDisplay getDisplayLocked(int displayId) { 300 return getDisplayLocked(displayId, /* includeDisabled= */ true); 301 } 302 getDisplayLocked(int displayId, boolean includeDisabled)303 public LogicalDisplay getDisplayLocked(int displayId, boolean includeDisabled) { 304 LogicalDisplay display = mLogicalDisplays.get(displayId); 305 if (display == null || display.isEnabledLocked() || includeDisabled) { 306 return display; 307 } 308 return null; 309 } 310 getDisplayLocked(DisplayDevice device)311 public LogicalDisplay getDisplayLocked(DisplayDevice device) { 312 return getDisplayLocked(device, /* includeDisabled= */ true); 313 } 314 getDisplayLocked(DisplayDevice device, boolean includeDisabled)315 public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) { 316 if (device == null) { 317 return null; 318 } 319 final int count = mLogicalDisplays.size(); 320 for (int i = 0; i < count; i++) { 321 final LogicalDisplay display = mLogicalDisplays.valueAt(i); 322 if (display.getPrimaryDisplayDeviceLocked() == device) { 323 if (display.isEnabledLocked() || includeDisabled) { 324 return display; 325 } 326 return null; 327 } 328 } 329 return null; 330 } 331 getDisplayIdsLocked(int callingUid, boolean includeDisabled)332 public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) { 333 final int count = mLogicalDisplays.size(); 334 int[] displayIds = new int[count]; 335 int n = 0; 336 for (int i = 0; i < count; i++) { 337 LogicalDisplay display = mLogicalDisplays.valueAt(i); 338 if (display.isEnabledLocked() || includeDisabled) { 339 DisplayInfo info = display.getDisplayInfoLocked(); 340 if (info.hasAccess(callingUid)) { 341 displayIds[n++] = mLogicalDisplays.keyAt(i); 342 } 343 } 344 } 345 if (n != count) { 346 displayIds = Arrays.copyOfRange(displayIds, 0, n); 347 } 348 return displayIds; 349 } 350 getDisplayIdsForGroupLocked(int groupId)351 public int[] getDisplayIdsForGroupLocked(int groupId) { 352 DisplayGroup displayGroup = mDisplayGroups.get(groupId); 353 if (displayGroup == null) { 354 return new int[]{}; 355 } 356 return displayGroup.getIdsLocked(); 357 } 358 getDisplayIdsByGroupIdLocked()359 public SparseArray<int[]> getDisplayIdsByGroupIdLocked() { 360 SparseArray<int[]> displayIdsByGroupIds = new SparseArray<>(); 361 for (int i = 0; i < mDisplayGroups.size(); i++) { 362 final int displayGroupId = mDisplayGroups.keyAt(i); 363 displayIdsByGroupIds.put(displayGroupId, getDisplayIdsForGroupLocked(displayGroupId)); 364 } 365 return displayIdsByGroupIds; 366 } 367 forEachLocked(Consumer<LogicalDisplay> consumer)368 public void forEachLocked(Consumer<LogicalDisplay> consumer) { 369 forEachLocked(consumer, /* includeDisabled= */ true); 370 } 371 forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled)372 public void forEachLocked(Consumer<LogicalDisplay> consumer, boolean includeDisabled) { 373 final int count = mLogicalDisplays.size(); 374 for (int i = 0; i < count; i++) { 375 LogicalDisplay display = mLogicalDisplays.valueAt(i); 376 if (display.isEnabledLocked() || includeDisabled) { 377 consumer.accept(display); 378 } 379 } 380 } 381 382 @VisibleForTesting getDisplayGroupIdFromDisplayIdLocked(int displayId)383 public int getDisplayGroupIdFromDisplayIdLocked(int displayId) { 384 final LogicalDisplay display = getDisplayLocked(displayId); 385 if (display == null) { 386 return Display.INVALID_DISPLAY_GROUP; 387 } 388 389 final int size = mDisplayGroups.size(); 390 for (int i = 0; i < size; i++) { 391 final DisplayGroup displayGroup = mDisplayGroups.valueAt(i); 392 if (displayGroup.containsLocked(display)) { 393 return mDisplayGroups.keyAt(i); 394 } 395 } 396 397 return Display.INVALID_DISPLAY_GROUP; 398 } 399 getDisplayGroupLocked(int groupId)400 public DisplayGroup getDisplayGroupLocked(int groupId) { 401 return mDisplayGroups.get(groupId); 402 } 403 404 /** 405 * Returns the {@link DisplayInfo} for this device state, indicated by the given display id. The 406 * DisplayInfo represents the attributes of the indicated display in the layout associated with 407 * this state. This is used to get display information for various displays in various states; 408 * e.g. to help apps preload resources for the possible display states. 409 * 410 * @param deviceState the state to query possible layouts for 411 * @param displayId the display id to retrieve 412 * @return {@code null} if no corresponding {@link DisplayInfo} could be found, or the 413 * {@link DisplayInfo} with a matching display id. 414 */ 415 @Nullable getDisplayInfoForStateLocked(int deviceState, int displayId)416 public DisplayInfo getDisplayInfoForStateLocked(int deviceState, int displayId) { 417 // Retrieve the layout for this particular state. 418 final Layout layout = mDeviceStateToLayoutMap.get(deviceState); 419 if (layout == null) { 420 // TODO(b/352019542): remove the log once b/345960547 is fixed. 421 Slog.d(TAG, "Cannot get layout for given state:" + deviceState); 422 return null; 423 } 424 // Retrieve the details of the given display within this layout. 425 Layout.Display display = layout.getById(displayId); 426 if (display == null) { 427 // TODO(b/352019542): remove the log once b/345960547 is fixed. 428 Slog.d(TAG, "Cannot get display for given layout:" + layout); 429 return null; 430 } 431 // Retrieve the display info for the display that matches the display id. 432 final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(display.getAddress()); 433 if (device == null) { 434 Slog.w(TAG, "The display device (" + display.getAddress() 435 + "), is not available for the display state " + mDeviceState.getIdentifier()); 436 return null; 437 } 438 LogicalDisplay logicalDisplay = getDisplayLocked(device, /* includeDisabled= */ true); 439 if (logicalDisplay == null) { 440 Slog.w(TAG, "The logical display associated with address (" + display.getAddress() 441 + "), is not available for the display state " + mDeviceState); 442 return null; 443 } 444 DisplayInfo displayInfo = new DisplayInfo(logicalDisplay.getDisplayInfoLocked()); 445 displayInfo.displayId = displayId; 446 return displayInfo; 447 } 448 dumpLocked(PrintWriter pw)449 public void dumpLocked(PrintWriter pw) { 450 pw.println("LogicalDisplayMapper:"); 451 pw.println("---------------------"); 452 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 453 ipw.increaseIndent(); 454 455 ipw.println("mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); 456 ipw.println("mCurrentLayout=" + mCurrentLayout); 457 ipw.println("mDeviceStatesOnWhichToWakeUp=" + mDeviceStatesOnWhichToWakeUp); 458 ipw.println("mDeviceStatesOnWhichSelectiveSleep=" + mDeviceStatesOnWhichToSelectiveSleep); 459 ipw.println("mInteractive=" + mInteractive); 460 ipw.println("mBootCompleted=" + mBootCompleted); 461 462 ipw.println(); 463 464 ipw.println("mDeviceState=" + mDeviceState.getIdentifier()); 465 ipw.println("mPendingDeviceState=" + mPendingDeviceState.getIdentifier()); 466 ipw.println("mDeviceStateToBeAppliedAfterBoot=" 467 + mDeviceStateToBeAppliedAfterBoot.getIdentifier()); 468 469 final int logicalDisplayCount = mLogicalDisplays.size(); 470 ipw.println(); 471 ipw.println("Logical Displays: size=" + logicalDisplayCount); 472 for (int i = 0; i < logicalDisplayCount; i++) { 473 int displayId = mLogicalDisplays.keyAt(i); 474 LogicalDisplay display = mLogicalDisplays.valueAt(i); 475 ipw.println("Display " + displayId + ":"); 476 ipw.increaseIndent(); 477 display.dumpLocked(ipw); 478 ipw.decreaseIndent(); 479 ipw.println(); 480 } 481 482 final int displayGroupCount = mDisplayGroups.size(); 483 ipw.println(); 484 ipw.println("Display Groups: size=" + displayGroupCount); 485 for (int i = 0; i < displayGroupCount; i++) { 486 int groupId = mDisplayGroups.keyAt(i); 487 DisplayGroup displayGroup = mDisplayGroups.valueAt(i); 488 ipw.println("Group " + groupId + ":"); 489 ipw.increaseIndent(); 490 displayGroup.dumpLocked(ipw); 491 ipw.decreaseIndent(); 492 ipw.println(); 493 } 494 495 496 mDeviceStateToLayoutMap.dumpLocked(ipw); 497 } 498 499 /** 500 * Creates an association between a displayDevice and a virtual device. Any displays associated 501 * with this virtual device will be grouped together in a single {@link DisplayGroup} unless 502 * created with {@link Display.FLAG_OWN_DISPLAY_GROUP}. 503 * 504 * @param displayDevice the displayDevice to be linked 505 * @param virtualDeviceUniqueId the unique ID of the virtual device. 506 */ associateDisplayDeviceWithVirtualDevice( DisplayDevice displayDevice, int virtualDeviceUniqueId)507 void associateDisplayDeviceWithVirtualDevice( 508 DisplayDevice displayDevice, int virtualDeviceUniqueId) { 509 mVirtualDeviceDisplayMapping.put(displayDevice.getUniqueId(), virtualDeviceUniqueId); 510 } 511 setDeviceStateLocked(DeviceState state)512 void setDeviceStateLocked(DeviceState state) { 513 if (!mBootCompleted) { 514 // The boot animation might still be in progress, we do not want to switch states now 515 // as the boot animation would end up with an incorrect size. 516 if (DEBUG) { 517 Slog.d(TAG, "Postponing transition to state: " 518 + mPendingDeviceState.getIdentifier() + " until boot is completed"); 519 } 520 mDeviceStateToBeAppliedAfterBoot = state; 521 return; 522 } 523 524 // As part of a state transition, we may need to turn off some displays temporarily so that 525 // the transition is smooth. Plus, on some devices, only one internal displays can be 526 // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be 527 // temporarily turned off. 528 resetLayoutLocked(mDeviceState.getIdentifier(), 529 state.getIdentifier(), /* transitionValue= */ true); 530 mPendingDeviceState = state; 531 mDeviceStateToBeAppliedAfterBoot = INVALID_DEVICE_STATE; 532 final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, 533 mInteractive, mBootCompleted); 534 final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, 535 mInteractive, mBootCompleted); 536 537 Slog.i(TAG, "Requesting Transition to state: " + state.getIdentifier() + ", from state=" 538 + mDeviceState.getIdentifier() + ", interactive=" + mInteractive 539 + ", mBootCompleted=" + mBootCompleted + ", wakeDevice=" + wakeDevice 540 + ", sleepDevice=" + sleepDevice); 541 542 // If all displays are off already, we can just transition here, unless we are trying to 543 // wake or sleep the device as part of this transition. In that case defer the final 544 // transition until later once the device is awake/asleep. 545 if (areAllTransitioningDisplaysOffLocked() && !wakeDevice && !sleepDevice) { 546 transitionToPendingStateLocked(); 547 return; 548 } 549 550 if (DEBUG) { 551 Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState.getIdentifier()); 552 } 553 // Send the transitioning phase updates to DisplayManager so that the displays can 554 // start turning OFF in preparation for the new layout. 555 updateLogicalDisplaysLocked(); 556 557 if (wakeDevice || sleepDevice) { 558 if (wakeDevice) { 559 // We already told the displays to turn off, now we need to wake the device as 560 // we transition to this new state. We do it here so that the waking happens 561 // between the transition from one layout to another. 562 mHandler.post(() -> { 563 mPowerManager.wakeUp(SystemClock.uptimeMillis(), 564 PowerManager.WAKE_REASON_UNFOLD_DEVICE, "server.display:unfold"); 565 }); 566 } else if (sleepDevice) { 567 // Send the device to sleep when required. 568 int goToSleepFlag = 569 mFoldSettingProvider.shouldSleepOnFold() ? 0 570 : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP; 571 mHandler.post(() -> { 572 mPowerManager.goToSleep(SystemClock.uptimeMillis(), 573 PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD, 574 goToSleepFlag); 575 }); 576 } 577 } 578 579 mHandler.sendEmptyMessageDelayed(MSG_TRANSITION_TO_PENDING_DEVICE_STATE, 580 TIMEOUT_STATE_TRANSITION_MILLIS); 581 } 582 onBootCompleted()583 void onBootCompleted() { 584 synchronized (mSyncRoot) { 585 mBootCompleted = true; 586 if (!mDeviceStateToBeAppliedAfterBoot.equals(INVALID_DEVICE_STATE)) { 587 setDeviceStateLocked(mDeviceStateToBeAppliedAfterBoot); 588 } 589 } 590 } 591 onEarlyInteractivityChange(boolean interactive)592 void onEarlyInteractivityChange(boolean interactive) { 593 synchronized (mSyncRoot) { 594 if (mInteractive != interactive) { 595 mInteractive = interactive; 596 finishStateTransitionLocked(false /*force*/); 597 } 598 } 599 } 600 601 /** 602 * Returns if the device should be woken up or not. Called to check if the device state we are 603 * moving to is one that should awake the device, as well as if we are moving from a device 604 * state that shouldn't have been already woken from. 605 * 606 * @param pendingState device state we are moving to 607 * @param currentState device state we are currently in 608 * @param isInteractive if the device is in an interactive state 609 * @param isBootCompleted is the device fully booted 610 * 611 * @see #shouldDeviceBePutToSleep 612 * @see #setDeviceStateLocked 613 */ 614 @VisibleForTesting shouldDeviceBeWoken(DeviceState pendingState, DeviceState currentState, boolean isInteractive, boolean isBootCompleted)615 boolean shouldDeviceBeWoken(DeviceState pendingState, DeviceState currentState, 616 boolean isInteractive, boolean isBootCompleted) { 617 if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) { 618 if (currentState.hasProperties(PROPERTY_EMULATED_ONLY) 619 && !pendingState.hasProperties(PROPERTY_EMULATED_ONLY)) { 620 // Do not wake the device, since this transition may occur due to the user pressing 621 // the power button to exit an emulated state. 622 return false; 623 } 624 625 return pendingState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE) 626 && !currentState.equals(INVALID_DEVICE_STATE) 627 && !currentState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE) 628 && !isInteractive && isBootCompleted; 629 } else { 630 return mDeviceStatesOnWhichToWakeUp.get(pendingState.getIdentifier()) 631 && !mDeviceStatesOnWhichToWakeUp.get(currentState.getIdentifier()) 632 && !isInteractive && isBootCompleted; 633 } 634 } 635 636 /** 637 * Returns if the device should be put to sleep or not. 638 * 639 * Includes a check to verify that the device state that we are moving to, {@code pendingState}, 640 * is the same as the physical state of the device, {@code baseState}. Also if the 641 * 'Stay Awake On Fold' is not enabled. Different values for these parameters indicate a device 642 * state override is active, and we shouldn't put the device to sleep to provide a better user 643 * experience. 644 * 645 * @param pendingState device state we are moving to 646 * @param currentState device state we are currently in 647 * @param isInteractive if the device is in an interactive state 648 * @param isBootCompleted is the device fully booted 649 * 650 * @see #shouldDeviceBeWoken 651 * @see #setDeviceStateLocked 652 */ 653 @VisibleForTesting shouldDeviceBePutToSleep(DeviceState pendingState, DeviceState currentState, boolean isInteractive, boolean isBootCompleted)654 boolean shouldDeviceBePutToSleep(DeviceState pendingState, DeviceState currentState, 655 boolean isInteractive, boolean isBootCompleted) { 656 if (mDeviceStateManagerFlags.deviceStatePropertyMigration()) { 657 return pendingState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP) 658 && !currentState.equals(INVALID_DEVICE_STATE) 659 && !currentState.hasProperty(PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP) 660 && isInteractive 661 && isBootCompleted 662 && !mFoldSettingProvider.shouldStayAwakeOnFold(); 663 } else { 664 return currentState.getIdentifier() 665 != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER 666 && pendingState.getIdentifier() 667 != DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER 668 && mDeviceStatesOnWhichToSelectiveSleep.get(pendingState.getIdentifier()) 669 && !mDeviceStatesOnWhichToSelectiveSleep.get(currentState.getIdentifier()) 670 && isInteractive 671 && isBootCompleted 672 && !mFoldSettingProvider.shouldStayAwakeOnFold(); 673 } 674 } 675 areAllTransitioningDisplaysOffLocked()676 private boolean areAllTransitioningDisplaysOffLocked() { 677 final int count = mLogicalDisplays.size(); 678 for (int i = 0; i < count; i++) { 679 final LogicalDisplay display = mLogicalDisplays.valueAt(i); 680 if (!display.isInTransitionLocked()) { 681 continue; 682 } 683 684 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); 685 if (device != null) { 686 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 687 if (info.state != Display.STATE_OFF) { 688 return false; 689 } 690 } 691 } 692 return true; 693 } 694 transitionToPendingStateLocked()695 private void transitionToPendingStateLocked() { 696 resetLayoutLocked(mDeviceState.getIdentifier(), 697 mPendingDeviceState.getIdentifier(), /* transitionValue= */ false); 698 mDeviceState = mPendingDeviceState; 699 mPendingDeviceState = INVALID_DEVICE_STATE; 700 applyLayoutLocked(); 701 updateLogicalDisplaysLocked(); 702 } 703 finishStateTransitionLocked(boolean force)704 private void finishStateTransitionLocked(boolean force) { 705 if (mPendingDeviceState.equals(INVALID_DEVICE_STATE)) { 706 return; 707 } 708 709 final boolean waitingToWakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, 710 mInteractive, mBootCompleted); 711 // The device should only wait for sleep if #shouldStayAwakeOnFold method returns false. 712 // If not, device should be marked ready for transition immediately. 713 final boolean waitingToSleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, 714 mDeviceState, mInteractive, mBootCompleted) && !shouldStayAwakeOnFold(); 715 716 final boolean displaysOff = areAllTransitioningDisplaysOffLocked(); 717 final boolean isReadyToTransition = displaysOff && !waitingToWakeDevice 718 && !waitingToSleepDevice; 719 720 if (isReadyToTransition || force) { 721 transitionToPendingStateLocked(); 722 mHandler.removeMessages(MSG_TRANSITION_TO_PENDING_DEVICE_STATE); 723 } else if (DEBUG) { 724 Slog.d(TAG, "Not yet ready to transition to state=" + mPendingDeviceState 725 + " with displays-off=" + displaysOff + ", force=" + force 726 + ", mInteractive=" + mInteractive + ", isReady=" + isReadyToTransition); 727 } 728 } 729 handleDisplayDeviceAddedLocked(DisplayDevice device)730 private void handleDisplayDeviceAddedLocked(DisplayDevice device) { 731 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 732 // The default Display needs to have additional initialization. 733 // This initializes a default dynamic display layout for the default 734 // device, which is used as a fallback in case no static layout definitions 735 // exist or cannot be loaded. 736 if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) { 737 initializeDefaultDisplayDeviceLocked(device); 738 } 739 740 // Create a logical display for the new display device 741 LogicalDisplay display = createNewLogicalDisplayLocked( 742 device, mIdProducer.getId(/* isDefault= */ false)); 743 744 applyLayoutLocked(); 745 updateLogicalDisplaysLocked(); 746 } 747 handleDisplayDeviceRemovedLocked(DisplayDevice device)748 private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { 749 final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); 750 Layout.Display layoutDisplay = layout.getById(DEFAULT_DISPLAY); 751 if (layoutDisplay == null) { 752 return; 753 } 754 DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); 755 756 // Remove any virtual device mapping which exists for the display. 757 mVirtualDeviceDisplayMapping.remove(device.getUniqueId()); 758 759 if (layoutDisplay.getAddress().equals(deviceInfo.address)) { 760 layout.removeDisplayLocked(DEFAULT_DISPLAY); 761 762 // Need to find another local display and make it default 763 for (int i = 0; i < mLogicalDisplays.size(); i++) { 764 LogicalDisplay nextDisplay = mLogicalDisplays.valueAt(i); 765 DisplayDevice nextDevice = nextDisplay.getPrimaryDisplayDeviceLocked(); 766 if (nextDevice == null) { 767 continue; 768 } 769 DisplayDeviceInfo nextDeviceInfo = nextDevice.getDisplayDeviceInfoLocked(); 770 771 if ((nextDeviceInfo.flags 772 & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0 773 && !nextDeviceInfo.address.equals(deviceInfo.address)) { 774 layout.createDefaultDisplayLocked(nextDeviceInfo.address, mIdProducer); 775 applyLayoutLocked(); 776 return; 777 } 778 } 779 } 780 } 781 782 @VisibleForTesting updateLogicalDisplays()783 void updateLogicalDisplays() { 784 synchronized (mSyncRoot) { 785 updateLogicalDisplaysLocked(); 786 } 787 } 788 updateLogicalDisplaysLocked()789 void updateLogicalDisplaysLocked() { 790 updateLogicalDisplaysLocked(DisplayDeviceInfo.DIFF_EVERYTHING); 791 } 792 updateLogicalDisplaysLocked(int diff)793 private void updateLogicalDisplaysLocked(int diff) { 794 updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ false); 795 } 796 797 /** 798 * Updates the rest of the display system once all the changes are applied for display 799 * devices and logical displays. The includes releasing invalid/empty LogicalDisplays, 800 * creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the 801 * relevant changes. 802 * 803 * @param diff The DisplayDeviceInfo.DIFF_* of what actually changed to enable finer-grained 804 * display update listeners 805 * @param isSecondLoop If true, this is the second time this is called for the same change. 806 */ updateLogicalDisplaysLocked(int diff, boolean isSecondLoop)807 private void updateLogicalDisplaysLocked(int diff, boolean isSecondLoop) { 808 boolean reloop = false; 809 // Go through all the displays and figure out if they need to be updated. 810 // Loops in reverse so that displays can be removed during the loop without affecting the 811 // rest of the loop. 812 for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) { 813 final int displayId = mLogicalDisplays.keyAt(i); 814 LogicalDisplay display = mLogicalDisplays.valueAt(i); 815 assignDisplayGroupLocked(display); 816 817 boolean wasDirty = display.isDirtyLocked(); 818 mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked()); 819 display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo); 820 821 display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); 822 final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked(); 823 final int updateState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW); 824 final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW; 825 final boolean wasPreviouslyEnabled = mDisplaysEnabledCache.get(displayId); 826 final boolean isCurrentlyEnabled = display.isEnabledLocked(); 827 int logicalDisplayEventMask = mLogicalDisplaysToUpdate 828 .get(displayId, LOGICAL_DISPLAY_EVENT_BASE); 829 boolean hasBasicInfoChanged = 830 !mTempDisplayInfo.equals(newDisplayInfo, /* compareOnlyBasicChanges */ true); 831 // The display is no longer valid and needs to be removed. 832 if (!display.isValidLocked()) { 833 // Remove from group 834 final DisplayGroup displayGroup = getDisplayGroupLocked( 835 getDisplayGroupIdFromDisplayIdLocked(displayId)); 836 if (displayGroup != null) { 837 displayGroup.removeDisplayLocked(display); 838 } 839 840 if (wasPreviouslyUpdated) { 841 // The display isn't actually removed from our internal data structures until 842 // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}. 843 if (mDisplaysEnabledCache.get(displayId)) { 844 // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED 845 reloop = true; 846 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED; 847 } else { 848 mUpdatedLogicalDisplays.delete(displayId); 849 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DISCONNECTED; 850 } 851 } else { 852 // This display never left this class, safe to remove without notification 853 mLogicalDisplays.removeAt(i); 854 } 855 mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask); 856 continue; 857 858 // The display is new. 859 } else if (!wasPreviouslyUpdated) { 860 // We still need to send LOGICAL_DISPLAY_EVENT_ADDED 861 reloop = true; 862 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CONNECTED; 863 // Underlying displays device has changed to a different one. 864 } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) { 865 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_SWAPPED; 866 867 // Something about the display device has changed. 868 } else if (wasPreviouslyEnabled != isCurrentlyEnabled) { 869 int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED : 870 LOGICAL_DISPLAY_EVENT_REMOVED; 871 logicalDisplayEventMask |= event; 872 } else if (wasDirty) { 873 // If only the hdr/sdr ratio changed, then send just the event for that case 874 if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { 875 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED; 876 } else { 877 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED 878 | LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED 879 | LOGICAL_DISPLAY_EVENT_STATE_CHANGED; 880 } 881 } else if (hasBasicInfoChanged 882 || mTempDisplayInfo.getRefreshRate() != newDisplayInfo.getRefreshRate()) { 883 // If only the hdr/sdr ratio changed, then send just the event for that case 884 if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) { 885 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED; 886 } else { 887 888 if (hasBasicInfoChanged) { 889 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED; 890 } 891 logicalDisplayEventMask 892 |= updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo); 893 } 894 // The display is involved in a display layout transition 895 } else if (updateState == UPDATE_STATE_TRANSITION) { 896 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION; 897 898 // Display frame rate overrides changed. 899 } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) { 900 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED; 901 902 // Non-override display values changed. 903 } else { 904 // While application shouldn't know nor care about the non-overridden info, we 905 // still need to let WindowManager know so it can update its own internal state for 906 // things like display cutouts. 907 display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo); 908 if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo, 909 /* compareOnlyBasicChanges */ true)) { 910 logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED; 911 } 912 logicalDisplayEventMask 913 |= updateAndGetMaskForDisplayPropertyChanges(mTempNonOverrideDisplayInfo); 914 } 915 mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask); 916 mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED); 917 } 918 919 // Go through the groups and do the same thing. We do this after displays since group 920 // information can change in the previous loop. 921 // Loops in reverse so that groups can be removed during the loop without affecting the 922 // rest of the loop. 923 for (int i = mDisplayGroups.size() - 1; i >= 0; i--) { 924 final int groupId = mDisplayGroups.keyAt(i); 925 final DisplayGroup group = mDisplayGroups.valueAt(i); 926 final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) > -1; 927 final int changeCount = group.getChangeCountLocked(); 928 929 if (group.isEmptyLocked()) { 930 mUpdatedDisplayGroups.delete(groupId); 931 if (wasPreviouslyUpdated) { 932 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_REMOVED); 933 } 934 continue; 935 } else if (!wasPreviouslyUpdated) { 936 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_ADDED); 937 } else if (mUpdatedDisplayGroups.get(groupId) != changeCount) { 938 mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_CHANGED); 939 } 940 mUpdatedDisplayGroups.put(groupId, changeCount); 941 } 942 943 // Send the display and display group updates in order by message type. This is important 944 // to ensure that addition and removal notifications happen in the right order. 945 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); 946 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED); 947 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED); 948 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); 949 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_BASIC_CHANGED); 950 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED); 951 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED); 952 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED); 953 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); 954 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED); 955 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED); 956 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); 957 sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); 958 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED); 959 sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED); 960 961 mLogicalDisplaysToUpdate.clear(); 962 mDisplayGroupsToUpdate.clear(); 963 964 if (reloop) { 965 if (isSecondLoop) { 966 Slog.wtf(TAG, "Trying to loop a third time"); 967 return; 968 } 969 updateLogicalDisplaysLocked(diff, /* isSecondLoop= */ true); 970 } 971 } 972 973 @VisibleForTesting updateAndGetMaskForDisplayPropertyChanges(DisplayInfo newDisplayInfo)974 int updateAndGetMaskForDisplayPropertyChanges(DisplayInfo newDisplayInfo) { 975 int mask = LOGICAL_DISPLAY_EVENT_BASE; 976 if (mTempDisplayInfo.getRefreshRate() != newDisplayInfo.getRefreshRate()) { 977 mask |= LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; 978 } 979 980 if (mFlags.isDisplayListenerPerformanceImprovementsEnabled() 981 && mTempDisplayInfo.state != newDisplayInfo.state) { 982 mask |= LOGICAL_DISPLAY_EVENT_STATE_CHANGED; 983 } 984 985 if (mFlags.isCommittedStateSeparateEventEnabled() 986 && mTempDisplayInfo.committedState != newDisplayInfo.committedState) { 987 mask |= LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED; 988 } 989 return mask; 990 } 991 /** 992 * Send the specified message for all relevant displays in the specified display-to-message map. 993 */ sendUpdatesForDisplaysLocked(int logicalDisplayEvent)994 private void sendUpdatesForDisplaysLocked(int logicalDisplayEvent) { 995 for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) { 996 final int logicalDisplayEventMask = mLogicalDisplaysToUpdate.valueAt(i); 997 if ((logicalDisplayEventMask & logicalDisplayEvent) == 0) { 998 continue; 999 } 1000 1001 final int id = mLogicalDisplaysToUpdate.keyAt(i); 1002 final LogicalDisplay display = getDisplayLocked(id); 1003 if (DEBUG) { 1004 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); 1005 final String uniqueId = device == null ? "null" : device.getUniqueId(); 1006 Slog.d(TAG, "Sending " + displayEventToString(logicalDisplayEvent) + " for " 1007 + "display=" + id + " with device=" + uniqueId); 1008 } 1009 1010 if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_ADDED) { 1011 mDisplaysEnabledCache.put(id, true); 1012 } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) { 1013 mDisplaysEnabledCache.delete(id); 1014 } 1015 1016 mListener.onLogicalDisplayEventLocked(display, logicalDisplayEvent); 1017 1018 if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_DISCONNECTED) { 1019 mLogicalDisplays.delete(id); 1020 } 1021 } 1022 } 1023 1024 /** 1025 * Send the specified message for all relevant display groups in the specified message map. 1026 */ sendUpdatesForGroupsLocked(int msg)1027 private void sendUpdatesForGroupsLocked(int msg) { 1028 for (int i = mDisplayGroupsToUpdate.size() - 1; i >= 0; --i) { 1029 final int currMsg = mDisplayGroupsToUpdate.valueAt(i); 1030 if (currMsg != msg) { 1031 continue; 1032 } 1033 1034 final int id = mDisplayGroupsToUpdate.keyAt(i); 1035 mListener.onDisplayGroupEventLocked(id, msg); 1036 if (msg == DISPLAY_GROUP_EVENT_REMOVED) { 1037 // We wait until we sent the EVENT_REMOVED event before actually removing the 1038 // group. 1039 mDisplayGroups.delete(id); 1040 // Remove possible reference to the removed group. 1041 int deviceIndex = mDeviceDisplayGroupIds.indexOfValue(id); 1042 if (deviceIndex >= 0) { 1043 mDeviceDisplayGroupIds.removeAt(deviceIndex); 1044 } 1045 } 1046 } 1047 } 1048 1049 /** This method should be called before LogicalDisplay.updateLocked, 1050 * DisplayInfo in LogicalDisplay (display.getDisplayInfoLocked()) is not updated yet, 1051 * and should not be used directly or indirectly in this method */ assignDisplayGroupLocked(LogicalDisplay display)1052 private void assignDisplayGroupLocked(LogicalDisplay display) { 1053 if (!display.isValidLocked()) { // null check for display.mPrimaryDisplayDevice 1054 return; 1055 } 1056 // updated primary device directly from LogicalDisplay (not from DisplayInfo) 1057 final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked(); 1058 // final in LogicalDisplay 1059 final int displayId = display.getDisplayIdLocked(); 1060 final String primaryDisplayUniqueId = displayDevice.getUniqueId(); 1061 final Integer linkedDeviceUniqueId = 1062 mVirtualDeviceDisplayMapping.get(primaryDisplayUniqueId); 1063 1064 // Get current display group data 1065 int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId); 1066 Integer deviceDisplayGroupId = null; 1067 if (linkedDeviceUniqueId != null 1068 && mDeviceDisplayGroupIds.indexOfKey(linkedDeviceUniqueId) > 0) { 1069 deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); 1070 } 1071 final DisplayGroup oldGroup = getDisplayGroupLocked(groupId); 1072 1073 // groupName directly from LogicalDisplay (not from DisplayInfo) 1074 final String groupName = display.getDisplayGroupNameLocked(); 1075 // DisplayDeviceInfo is safe to use, it is updated earlier 1076 final DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); 1077 // Get the new display group if a change is needed, if display group name is empty and 1078 // {@code DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP} is not set, the display is assigned 1079 // to the default display group. 1080 final boolean needsOwnDisplayGroup = 1081 (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0 1082 || !TextUtils.isEmpty(groupName); 1083 1084 final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP; 1085 final boolean needsDeviceDisplayGroup = 1086 !needsOwnDisplayGroup && linkedDeviceUniqueId != null; 1087 final boolean hasDeviceDisplayGroup = 1088 deviceDisplayGroupId != null && groupId == deviceDisplayGroupId; 1089 if (groupId == Display.INVALID_DISPLAY_GROUP 1090 || hasOwnDisplayGroup != needsOwnDisplayGroup 1091 || hasDeviceDisplayGroup != needsDeviceDisplayGroup) { 1092 groupId = 1093 assignDisplayGroupIdLocked(needsOwnDisplayGroup, 1094 display.getDisplayGroupNameLocked(), needsDeviceDisplayGroup, 1095 linkedDeviceUniqueId); 1096 } 1097 1098 // Create a new group if needed 1099 DisplayGroup newGroup = getDisplayGroupLocked(groupId); 1100 if (newGroup == null) { 1101 newGroup = new DisplayGroup(groupId); 1102 mDisplayGroups.append(groupId, newGroup); 1103 } 1104 if (oldGroup != newGroup) { 1105 if (oldGroup != null) { 1106 oldGroup.removeDisplayLocked(display); 1107 } 1108 newGroup.addDisplayLocked(display); 1109 display.updateDisplayGroupIdLocked(groupId); 1110 Slog.i(TAG, "Setting new display group " + groupId + " for display " 1111 + displayId + ", from previous group: " 1112 + (oldGroup != null ? oldGroup.getGroupId() : "null")); 1113 } 1114 } 1115 1116 /** 1117 * Goes through all the displays used in the layouts for the specified {@code fromState} and 1118 * {@code toState} and un/marks them for transition. When a new layout is requested, we 1119 * mark the displays that will change into a transitional phase so that they can all be turned 1120 * OFF. Once all are confirmed OFF, then this method gets called again to reset transition 1121 * marker. This helps to ensure that all display-OFF requests are made before 1122 * display-ON which in turn hides any resizing-jank windows might incur when switching displays. 1123 * 1124 * @param fromState The state we are switching from. 1125 * @param toState The state we are switching to. 1126 * @param transitionValue The value to mark the transition state: true == transitioning. 1127 */ resetLayoutLocked(int fromState, int toState, boolean transitionValue)1128 private void resetLayoutLocked(int fromState, int toState, boolean transitionValue) { 1129 final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState); 1130 final Layout toLayout = mDeviceStateToLayoutMap.get(toState); 1131 1132 final int count = mLogicalDisplays.size(); 1133 for (int i = 0; i < count; i++) { 1134 final LogicalDisplay logicalDisplay = mLogicalDisplays.valueAt(i); 1135 final int displayId = logicalDisplay.getDisplayIdLocked(); 1136 final DisplayDevice device = logicalDisplay.getPrimaryDisplayDeviceLocked(); 1137 if (device == null) { 1138 // If there's no device, then the logical display is due to be removed. Ignore it. 1139 continue; 1140 } 1141 1142 // Grab the display associations this display-device has in the old layout and the 1143 // new layout. 1144 final DisplayAddress address = device.getDisplayDeviceInfoLocked().address; 1145 1146 // Virtual displays do not have addresses, so account for nulls. 1147 final Layout.Display fromDisplay = 1148 address != null ? fromLayout.getByAddress(address) : null; 1149 final Layout.Display toDisplay = 1150 address != null ? toLayout.getByAddress(address) : null; 1151 1152 // If the display is in one of the layouts but not the other, then the content will 1153 // change, so in this case we also want to blank the displays to avoid jank. 1154 final boolean displayNotInBothLayouts = (fromDisplay == null) != (toDisplay == null); 1155 1156 // If a layout doesn't mention a display-device at all, then the display-device defaults 1157 // to enabled. This is why we treat null as "enabled" in the code below. 1158 final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled(); 1159 final boolean willBeEnabled = toDisplay == null || toDisplay.isEnabled(); 1160 1161 final boolean deviceHasNewLogicalDisplayId = fromDisplay != null && toDisplay != null 1162 && fromDisplay.getLogicalDisplayId() != toDisplay.getLogicalDisplayId(); 1163 1164 // We consider a display-device as changing/transition if 1165 // 1) It's already marked as transitioning 1166 // 2) It's going from enabled to disabled, or vice versa 1167 // 3) It's enabled, but it's mapped to a new logical display ID. To the user this 1168 // would look like apps moving from one screen to another since task-stacks stay 1169 // with the logical display [ID]. 1170 // 4) It's in one layout but not the other, so the content will change. 1171 final boolean isTransitioning = 1172 logicalDisplay.isInTransitionLocked() 1173 || (wasEnabled != willBeEnabled) 1174 || deviceHasNewLogicalDisplayId 1175 || displayNotInBothLayouts; 1176 1177 if (isTransitioning) { 1178 if (transitionValue != logicalDisplay.isInTransitionLocked()) { 1179 Slog.i(TAG, "Set isInTransition on display " + displayId + ": " 1180 + transitionValue); 1181 } 1182 // This will either mark the display as "transitioning" if we are starting to change 1183 // the device state, or remove the transitioning marker if the state change is 1184 // ending. 1185 logicalDisplay.setIsInTransitionLocked(transitionValue); 1186 mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION); 1187 } 1188 } 1189 } 1190 1191 /** 1192 * Apply (or reapply) the currently selected display layout. 1193 */ applyLayoutLocked()1194 private void applyLayoutLocked() { 1195 final Layout oldLayout = mCurrentLayout; 1196 mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState.getIdentifier()); 1197 Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout); 1198 1199 // Go through each of the displays in the current layout set. 1200 final int size = mCurrentLayout.size(); 1201 for (int i = 0; i < size; i++) { 1202 final Layout.Display displayLayout = mCurrentLayout.getAt(i); 1203 1204 // If the underlying display-device we want to use for this display 1205 // doesn't exist, then skip it. This can happen at startup as display-devices 1206 // trickle in one at a time. When the new display finally shows up, the layout is 1207 // recalculated so that the display is properly added to the current layout. 1208 final DisplayAddress address = displayLayout.getAddress(); 1209 final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address); 1210 if (device == null) { 1211 Slog.w(TAG, "applyLayoutLocked: The display device (" + address + "), is not " 1212 + "available for the display state " + mDeviceState.getIdentifier()); 1213 continue; 1214 } 1215 1216 // Now that we have a display-device, we need a LogicalDisplay to map it to. Find the 1217 // right one, if it doesn't exist, create a new one. 1218 final int logicalDisplayId = displayLayout.getLogicalDisplayId(); 1219 1220 LogicalDisplay newDisplay = getDisplayLocked(logicalDisplayId); 1221 boolean newDisplayCreated = false; 1222 if (newDisplay == null) { 1223 newDisplay = createNewLogicalDisplayLocked( 1224 null /*displayDevice*/, logicalDisplayId); 1225 newDisplayCreated = true; 1226 } 1227 1228 // Now swap the underlying display devices between the old display and the new display 1229 final LogicalDisplay oldDisplay = getDisplayLocked(device); 1230 if (newDisplay != oldDisplay) { 1231 // Display is swapping, notify WindowManager, so it can prepare for 1232 // the display switch 1233 if (!newDisplayCreated && mWindowManagerPolicy != null) { 1234 mWindowManagerPolicy.onDisplaySwitchStart(newDisplay.getDisplayIdLocked()); 1235 } 1236 1237 newDisplay.swapDisplaysLocked(oldDisplay); 1238 } 1239 DisplayDeviceConfig config = device.getDisplayDeviceConfig(); 1240 1241 newDisplay.setDevicePositionLocked(displayLayout.getPosition()); 1242 newDisplay.setLeadDisplayLocked(displayLayout.getLeadDisplayId()); 1243 newDisplay.updateLayoutLimitedRefreshRateLocked( 1244 config.getRefreshRange(displayLayout.getRefreshRateZoneId()) 1245 ); 1246 newDisplay.updateThermalRefreshRateThrottling( 1247 config.getThermalRefreshRateThrottlingData( 1248 displayLayout.getRefreshRateThermalThrottlingMapId() 1249 ) 1250 ); 1251 setEnabledLocked(newDisplay, displayLayout.isEnabled()); 1252 newDisplay.setThermalBrightnessThrottlingDataIdLocked( 1253 displayLayout.getThermalBrightnessThrottlingMapId() == null 1254 ? DisplayDeviceConfig.DEFAULT_ID 1255 : displayLayout.getThermalBrightnessThrottlingMapId()); 1256 newDisplay.setPowerThrottlingDataIdLocked( 1257 displayLayout.getPowerThrottlingMapId() == null 1258 ? DisplayDeviceConfig.DEFAULT_ID 1259 : displayLayout.getPowerThrottlingMapId()); 1260 newDisplay.setDisplayGroupNameLocked(displayLayout.getDisplayGroupName()); 1261 } 1262 } 1263 1264 /** 1265 * Creates a new logical display for the specified device and display Id and adds it to the list 1266 * of logical displays. 1267 * 1268 * @param device The device to associate with the LogicalDisplay. 1269 * @param displayId The display ID to give the new display. If invalid, a new ID is assigned. 1270 * @return The new logical display if created, null otherwise. 1271 */ createNewLogicalDisplayLocked(DisplayDevice device, int displayId)1272 private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) { 1273 final int layerStack = assignLayerStackLocked(displayId); 1274 final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, 1275 mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(), 1276 mFlags.isAlwaysRotateDisplayDeviceEnabled(), 1277 mFlags.isSyncedResolutionSwitchEnabled()); 1278 display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); 1279 1280 final DisplayInfo info = display.getDisplayInfoLocked(); 1281 if (info.type == Display.TYPE_INTERNAL && mDeviceStateToLayoutMap.size() > 1) { 1282 // If this is an internal display and the device uses a display layout configuration, 1283 // the display should be disabled as later we will receive a device state update, which 1284 // will tell us which internal displays should be enabled and which should be disabled. 1285 display.setEnabledLocked(false); 1286 } 1287 1288 mLogicalDisplays.put(displayId, display); 1289 return display; 1290 } 1291 setEnabledLocked(LogicalDisplay display, boolean isEnabled)1292 void setEnabledLocked(LogicalDisplay display, boolean isEnabled) { 1293 final int displayId = display.getDisplayIdLocked(); 1294 final DisplayInfo info = display.getDisplayInfoLocked(); 1295 1296 final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode 1297 && (info.type != Display.TYPE_INTERNAL); 1298 if (isEnabled && disallowSecondaryDisplay) { 1299 Slog.i(TAG, "Not creating a logical display for a secondary display because single" 1300 + " display demo mode is enabled: " + display.getDisplayInfoLocked()); 1301 isEnabled = false; 1302 } 1303 1304 if (display.isEnabledLocked() != isEnabled) { 1305 Slog.i(TAG, "SetEnabled on display " + displayId + ": " + isEnabled); 1306 display.setEnabledLocked(isEnabled); 1307 } 1308 } 1309 assignDisplayGroupIdLocked(boolean isOwnDisplayGroup, String displayGroupName, boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId)1310 private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup, String displayGroupName, 1311 boolean isDeviceDisplayGroup, Integer linkedDeviceUniqueId) { 1312 if (isDeviceDisplayGroup && linkedDeviceUniqueId != null) { 1313 int deviceDisplayGroupId = mDeviceDisplayGroupIds.get(linkedDeviceUniqueId); 1314 // A value of 0 indicates that no device display group was found. 1315 if (deviceDisplayGroupId == 0) { 1316 deviceDisplayGroupId = mNextNonDefaultGroupId++; 1317 mDeviceDisplayGroupIds.put(linkedDeviceUniqueId, deviceDisplayGroupId); 1318 } 1319 return deviceDisplayGroupId; 1320 } 1321 if (!isOwnDisplayGroup) return Display.DEFAULT_DISPLAY_GROUP; 1322 Integer displayGroupId = mDisplayGroupIdsByName.get(displayGroupName); 1323 if (displayGroupId == null) { 1324 displayGroupId = Integer.valueOf(mNextNonDefaultGroupId++); 1325 mDisplayGroupIdsByName.put(displayGroupName, displayGroupId); 1326 } 1327 return displayGroupId; 1328 } 1329 initializeDefaultDisplayDeviceLocked(DisplayDevice device)1330 private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) { 1331 // We always want to make sure that our default layout creates a logical 1332 // display for the default display device that is found. 1333 // To that end, when we are notified of a new default display, we add it to 1334 // the default layout definition if it is not already there. 1335 final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); 1336 if (layout.getById(DEFAULT_DISPLAY) != null) { 1337 // The layout should only have one default display 1338 return; 1339 } 1340 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 1341 layout.createDefaultDisplayLocked(info.address, mIdProducer); 1342 } 1343 assignLayerStackLocked(int displayId)1344 private int assignLayerStackLocked(int displayId) { 1345 // Currently layer stacks and display ids are the same. 1346 // This need not be the case. 1347 return displayId; 1348 } 1349 toSparseBooleanArray(int[] input)1350 private SparseBooleanArray toSparseBooleanArray(int[] input) { 1351 final SparseBooleanArray retval = new SparseBooleanArray(2); 1352 for (int i = 0; input != null && i < input.length; i++) { 1353 retval.put(input[i], true); 1354 } 1355 return retval; 1356 } 1357 1358 /** 1359 * Returns true if the device would definitely have outer display ON/Stay Awake on fold based on 1360 * the value of `Continue using app on fold` setting 1361 */ shouldStayAwakeOnFold()1362 private boolean shouldStayAwakeOnFold() { 1363 return mFoldSettingProvider.shouldStayAwakeOnFold() || ( 1364 mFoldSettingProvider.shouldSelectiveStayAwakeOnFold() 1365 && mFoldGracePeriodProvider.isEnabled()); 1366 } 1367 displayEventToString(int msg)1368 private String displayEventToString(int msg) { 1369 switch(msg) { 1370 case LOGICAL_DISPLAY_EVENT_ADDED: 1371 return "added"; 1372 case LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION: 1373 return "transition"; 1374 case LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED: 1375 return "framerate_override"; 1376 case LOGICAL_DISPLAY_EVENT_SWAPPED: 1377 return "swapped"; 1378 case LOGICAL_DISPLAY_EVENT_REMOVED: 1379 return "removed"; 1380 case LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED: 1381 return "hdr_sdr_ratio_changed"; 1382 case LOGICAL_DISPLAY_EVENT_CONNECTED: 1383 return "connected"; 1384 case LOGICAL_DISPLAY_EVENT_DISCONNECTED: 1385 return "disconnected"; 1386 case LOGICAL_DISPLAY_EVENT_STATE_CHANGED: 1387 return "state_changed"; 1388 case LOGICAL_DISPLAY_EVENT_COMMITTED_STATE_CHANGED: 1389 return "committed_state_changed"; 1390 case LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED: 1391 return "refresh_rate_changed"; 1392 case LOGICAL_DISPLAY_EVENT_BASIC_CHANGED: 1393 return "basic_changed"; 1394 } 1395 return null; 1396 } 1397 setDisplayEnabledLocked(@onNull LogicalDisplay display, boolean enabled)1398 void setDisplayEnabledLocked(@NonNull LogicalDisplay display, boolean enabled) { 1399 boolean isEnabled = display.isEnabledLocked(); 1400 if (isEnabled == enabled) { 1401 Slog.w(TAG, "Display is already " + (isEnabled ? "enabled" : "disabled") + ": " 1402 + display.getDisplayIdLocked()); 1403 return; 1404 } 1405 setEnabledLocked(display, enabled); 1406 updateLogicalDisplaysLocked(); 1407 } 1408 1409 public interface Listener { onLogicalDisplayEventLocked(LogicalDisplay display, int event)1410 void onLogicalDisplayEventLocked(LogicalDisplay display, int event); onDisplayGroupEventLocked(int groupId, int event)1411 void onDisplayGroupEventLocked(int groupId, int event); onTraversalRequested()1412 void onTraversalRequested(); 1413 } 1414 1415 private class LogicalDisplayMapperHandler extends Handler { LogicalDisplayMapperHandler(Looper looper)1416 LogicalDisplayMapperHandler(Looper looper) { 1417 super(looper, null, true /*async*/); 1418 } 1419 1420 @Override handleMessage(Message msg)1421 public void handleMessage(Message msg) { 1422 switch (msg.what) { 1423 case MSG_TRANSITION_TO_PENDING_DEVICE_STATE: 1424 synchronized (mSyncRoot) { 1425 finishStateTransitionLocked(true /*force*/); 1426 } 1427 break; 1428 } 1429 } 1430 } 1431 } 1432