1 /* 2 * Copyright (C) 2019 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.mode; 18 19 import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; 20 import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE; 21 import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT; 22 import static android.view.Display.Mode.INVALID_MODE_ID; 23 24 import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE; 25 26 import android.annotation.IntegerRes; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.content.ContentResolver; 30 import android.content.Context; 31 import android.content.res.Resources; 32 import android.database.ContentObserver; 33 import android.hardware.Sensor; 34 import android.hardware.SensorEvent; 35 import android.hardware.SensorEventListener; 36 import android.hardware.SensorManager; 37 import android.hardware.display.BrightnessInfo; 38 import android.hardware.display.DisplayManager; 39 import android.hardware.display.DisplayManagerInternal; 40 import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; 41 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; 42 import android.net.Uri; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.IThermalEventListener; 46 import android.os.IThermalService; 47 import android.os.Looper; 48 import android.os.Message; 49 import android.os.PowerManager; 50 import android.os.RemoteException; 51 import android.os.ServiceManager; 52 import android.os.SystemClock; 53 import android.os.Temperature; 54 import android.os.UserHandle; 55 import android.provider.DeviceConfig; 56 import android.provider.DeviceConfigInterface; 57 import android.provider.Settings; 58 import android.sysprop.SurfaceFlingerProperties; 59 import android.util.IndentingPrintWriter; 60 import android.util.Pair; 61 import android.util.Slog; 62 import android.util.SparseArray; 63 import android.util.SparseBooleanArray; 64 import android.util.SparseIntArray; 65 import android.view.Display; 66 import android.view.DisplayInfo; 67 import android.view.SurfaceControl; 68 import android.view.SurfaceControl.IdleScreenRefreshRateConfig; 69 import android.view.SurfaceControl.RefreshRateRange; 70 import android.view.SurfaceControl.RefreshRateRanges; 71 72 import com.android.internal.R; 73 import com.android.internal.annotations.GuardedBy; 74 import com.android.internal.annotations.VisibleForTesting; 75 import com.android.internal.display.BrightnessSynchronizer; 76 import com.android.internal.os.BackgroundThread; 77 import com.android.server.LocalServices; 78 import com.android.server.display.DisplayDeviceConfig; 79 import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint; 80 import com.android.server.display.config.RefreshRateData; 81 import com.android.server.display.config.SupportedModeData; 82 import com.android.server.display.feature.DeviceConfigParameterProvider; 83 import com.android.server.display.feature.DisplayManagerFlags; 84 import com.android.server.display.utils.AmbientFilter; 85 import com.android.server.display.utils.AmbientFilterFactory; 86 import com.android.server.display.utils.DeviceConfigParsingUtils; 87 import com.android.server.display.utils.SensorUtils; 88 import com.android.server.sensors.SensorManagerInternal; 89 import com.android.server.statusbar.StatusBarManagerInternal; 90 91 import java.io.PrintWriter; 92 import java.text.SimpleDateFormat; 93 import java.util.ArrayList; 94 import java.util.Arrays; 95 import java.util.Date; 96 import java.util.HashSet; 97 import java.util.List; 98 import java.util.Locale; 99 import java.util.Objects; 100 import java.util.Set; 101 import java.util.concurrent.Callable; 102 import java.util.function.Function; 103 import java.util.function.IntSupplier; 104 105 /** 106 * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically 107 * picked by the system based on system-wide and display-specific configuration. 108 */ 109 public class DisplayModeDirector { 110 111 public static final float SYNCHRONIZED_REFRESH_RATE_TARGET = DEFAULT_LOW_REFRESH_RATE; 112 public static final float SYNCHRONIZED_REFRESH_RATE_TOLERANCE = 1; 113 private static final String TAG = "DisplayModeDirector"; 114 private boolean mLoggingEnabled; 115 116 private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1; 117 private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2; 118 private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3; 119 private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4; 120 private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5; 121 private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6; 122 private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7; 123 private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8; 124 125 private final Object mLock = new Object(); 126 private final Context mContext; 127 128 private final DisplayModeDirectorHandler mHandler; 129 private final Injector mInjector; 130 131 private final AppRequestObserver mAppRequestObserver; 132 private final SettingsObserver mSettingsObserver; 133 private final DisplayObserver mDisplayObserver; 134 private final UdfpsObserver mUdfpsObserver; 135 private final ProximitySensorObserver mSensorObserver; 136 private final HbmObserver mHbmObserver; 137 private final SkinThermalStatusObserver mSkinThermalStatusObserver; 138 139 @Nullable 140 private final SystemRequestObserver mSystemRequestObserver; 141 private final DeviceConfigParameterProvider mConfigParameterProvider; 142 private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; 143 144 @GuardedBy("mLock") 145 @Nullable 146 private DisplayDeviceConfig mDefaultDisplayDeviceConfig; 147 148 // A map from the display ID to the supported modes on that display. 149 private SparseArray<Display.Mode[]> mSupportedModesByDisplay; 150 // A map from the display ID to the app supported modes on that display, might be different from 151 // mSupportedModesByDisplay for VRR displays, used in app mode requests. 152 private SparseArray<Display.Mode[]> mAppSupportedModesByDisplay; 153 // A map from the display ID to the default mode of that display. 154 private SparseArray<Display.Mode> mDefaultModeByDisplay; 155 // a map from display id to display device config 156 private SparseArray<DisplayDeviceConfig> mDisplayDeviceConfigByDisplay = new SparseArray<>(); 157 158 private BrightnessObserver mBrightnessObserver; 159 160 private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener; 161 162 private boolean mAlwaysRespectAppRequest; 163 164 private final boolean mSupportsFrameRateOverride; 165 166 private final VotesStorage mVotesStorage; 167 168 @Nullable 169 private final VotesStatsReporter mVotesStatsReporter; 170 171 /** 172 * The allowed refresh rate switching type. This is used by SurfaceFlinger. 173 */ 174 @DisplayManager.SwitchingType 175 private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS; 176 177 /** 178 * Whether resolution range voting feature is enabled. 179 */ 180 private final boolean mIsDisplayResolutionRangeVotingEnabled; 181 182 /** 183 * Whether user preferred mode voting feature is enabled. 184 */ 185 private final boolean mIsUserPreferredModeVoteEnabled; 186 187 /** 188 * Whether limit display mode feature is enabled. 189 */ 190 private final boolean mIsExternalDisplayLimitModeEnabled; 191 192 private final boolean mIsDisplaysRefreshRatesSynchronizationEnabled; 193 194 private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled; 195 196 private final DisplayManagerFlags mDisplayManagerFlags; 197 198 private final DisplayDeviceConfigProvider mDisplayDeviceConfigProvider; 199 DisplayModeDirector(@onNull Context context, @NonNull Handler handler, @NonNull DisplayManagerFlags displayManagerFlags, @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider)200 public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, 201 @NonNull DisplayManagerFlags displayManagerFlags, 202 @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider) { 203 this(context, handler, new RealInjector(context), 204 displayManagerFlags, displayDeviceConfigProvider); 205 } 206 DisplayModeDirector(@onNull Context context, @NonNull Handler handler, @NonNull Injector injector, @NonNull DisplayManagerFlags displayManagerFlags, @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider)207 public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler, 208 @NonNull Injector injector, 209 @NonNull DisplayManagerFlags displayManagerFlags, 210 @NonNull DisplayDeviceConfigProvider displayDeviceConfigProvider) { 211 mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags 212 .isDisplayResolutionRangeVotingEnabled(); 213 mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled(); 214 mIsExternalDisplayLimitModeEnabled = displayManagerFlags 215 .isExternalDisplayLimitModeEnabled(); 216 mIsDisplaysRefreshRatesSynchronizationEnabled = displayManagerFlags 217 .isDisplaysRefreshRatesSynchronizationEnabled(); 218 mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags 219 .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled(); 220 mDisplayManagerFlags = displayManagerFlags; 221 mDisplayDeviceConfigProvider = displayDeviceConfigProvider; 222 mContext = context; 223 mHandler = new DisplayModeDirectorHandler(handler.getLooper()); 224 mInjector = injector; 225 mVotesStatsReporter = injector.getVotesStatsReporter( 226 displayManagerFlags.isRefreshRateVotingTelemetryEnabled()); 227 mSupportedModesByDisplay = new SparseArray<>(); 228 mAppSupportedModesByDisplay = new SparseArray<>(); 229 mDefaultModeByDisplay = new SparseArray<>(); 230 mAppRequestObserver = new AppRequestObserver(displayManagerFlags); 231 mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig()); 232 mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); 233 mSettingsObserver = new SettingsObserver(context, handler, displayManagerFlags); 234 mBrightnessObserver = new BrightnessObserver(context, handler, injector, 235 displayManagerFlags); 236 mDefaultDisplayDeviceConfig = null; 237 mUdfpsObserver = new UdfpsObserver(); 238 mVotesStorage = new VotesStorage(this::notifyDesiredDisplayModeSpecsChangedLocked, 239 mVotesStatsReporter); 240 mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage, injector); 241 mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector); 242 mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage); 243 mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(), 244 mDeviceConfigDisplaySettings); 245 if (displayManagerFlags.isRestrictDisplayModesEnabled()) { 246 mSystemRequestObserver = new SystemRequestObserver(mVotesStorage); 247 } else { 248 mSystemRequestObserver = null; 249 } 250 mAlwaysRespectAppRequest = false; 251 mSupportsFrameRateOverride = injector.supportsFrameRateOverride(); 252 } 253 254 /** 255 * Tells the DisplayModeDirector to update allowed votes and begin observing relevant system 256 * state. 257 * 258 * This has to be deferred because the object may be constructed before the rest of the system 259 * is ready. 260 */ start(SensorManager sensorManager)261 public void start(SensorManager sensorManager) { 262 // This has to be called first to read the supported display modes that will be used by 263 // other observers 264 mDisplayObserver.observe(); 265 266 mSettingsObserver.observe(); 267 mBrightnessObserver.observe(sensorManager); 268 mSensorObserver.observe(); 269 mHbmObserver.observe(); 270 mSkinThermalStatusObserver.observe(); 271 synchronized (mLock) { 272 // We may have a listener already registered before the call to start, so go ahead and 273 // notify them to pick up our newly initialized state. 274 notifyDesiredDisplayModeSpecsChangedLocked(); 275 } 276 } 277 278 /** 279 * Same as {@link #start(SensorManager)}, but for observers that need to be delayed even more, 280 * for example until SystemUI is ready. 281 */ onBootCompleted()282 public void onBootCompleted() { 283 // UDFPS observer registers a listener with SystemUI which might not be ready until the 284 // system is fully booted. 285 mUdfpsObserver.observe(); 286 } 287 288 /** 289 * Enables or disables component logging 290 */ setLoggingEnabled(boolean loggingEnabled)291 public void setLoggingEnabled(boolean loggingEnabled) { 292 if (mLoggingEnabled == loggingEnabled) { 293 return; 294 } 295 mLoggingEnabled = loggingEnabled; 296 mBrightnessObserver.setLoggingEnabled(loggingEnabled); 297 mSkinThermalStatusObserver.setLoggingEnabled(loggingEnabled); 298 mVotesStorage.setLoggingEnabled(loggingEnabled); 299 } 300 301 /** 302 * Calculates the refresh rate ranges and display modes that the system is allowed to freely 303 * switch between based on global and display-specific constraints. 304 * 305 * @param displayId The display to query for. 306 * @return The ID of the default mode the system should use, and the refresh rate range the 307 * system is allowed to switch between. 308 */ 309 @NonNull getDesiredDisplayModeSpecs(int displayId)310 public DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(int displayId) { 311 synchronized (mLock) { 312 SparseArray<Vote> votes = mVotesStorage.getVotes(displayId); 313 Display.Mode[] modes = mSupportedModesByDisplay.get(displayId); 314 Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId); 315 if (modes == null || defaultMode == null) { 316 Slog.e(TAG, 317 "Asked about unknown display, returning empty display mode specs!" 318 + "(id=" + displayId + ")"); 319 return new DesiredDisplayModeSpecs(); 320 } 321 322 List<Display.Mode> availableModes = new ArrayList<>(); 323 availableModes.add(defaultMode); 324 VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled, 325 isVrrSupportedLocked(displayId), 326 mLoggingEnabled, mSupportsFrameRateOverride); 327 int lowestConsideredPriority = Vote.MIN_PRIORITY; 328 int highestConsideredPriority = Vote.MAX_PRIORITY; 329 330 if (mAlwaysRespectAppRequest) { 331 lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE; 332 highestConsideredPriority = Vote.PRIORITY_APP_REQUEST_SIZE; 333 } 334 335 // We try to find a range of priorities which define a non-empty set of allowed display 336 // modes. Each time we fail we increase the lowest priority. 337 while (lowestConsideredPriority <= highestConsideredPriority) { 338 primarySummary.applyVotes( 339 votes, lowestConsideredPriority, highestConsideredPriority); 340 341 primarySummary.adjustSize(defaultMode, modes); 342 343 availableModes = primarySummary.filterModes(modes); 344 if (!availableModes.isEmpty()) { 345 if (mLoggingEnabled) { 346 Slog.w(TAG, "Found available modes=" + availableModes 347 + " with lowest priority considered " 348 + Vote.priorityToString(lowestConsideredPriority) 349 + " and summary: " + primarySummary); 350 } 351 break; 352 } 353 354 if (mLoggingEnabled) { 355 Slog.w(TAG, "Couldn't find available modes with lowest priority set to " 356 + Vote.priorityToString(lowestConsideredPriority) 357 + " and with the following summary: " + primarySummary); 358 } 359 360 // If we haven't found anything with the current set of votes, drop the 361 // current lowest priority vote. 362 lowestConsideredPriority++; 363 } 364 365 VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled, 366 isVrrSupportedLocked(displayId), 367 mLoggingEnabled, mSupportsFrameRateOverride); 368 369 appRequestSummary.applyVotes(votes, 370 Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, 371 Vote.MAX_PRIORITY); 372 373 appRequestSummary.limitRefreshRanges(primarySummary); 374 375 Display.Mode baseMode = primarySummary.selectBaseMode(availableModes, defaultMode); 376 if (mVotesStatsReporter != null) { 377 mVotesStatsReporter.reportVotesActivated(displayId, lowestConsideredPriority, 378 baseMode, votes); 379 } 380 381 if (baseMode == null) { 382 Slog.w(TAG, "Can't find a set of allowed modes which satisfies the votes. Falling" 383 + " back to the default mode. Display = " + displayId + ", votes = " + votes 384 + ", supported modes = " + Arrays.toString(modes)); 385 386 float fps = defaultMode.getRefreshRate(); 387 final RefreshRateRange range = new RefreshRateRange(fps, fps); 388 final RefreshRateRanges ranges = new RefreshRateRanges(range, range); 389 return new DesiredDisplayModeSpecs(defaultMode.getModeId(), 390 /*allowGroupSwitching */ false, 391 ranges, ranges, mBrightnessObserver.getIdleScreenRefreshRateConfig()); 392 } 393 394 boolean modeSwitchingDisabled = 395 mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE 396 || mModeSwitchingType 397 == DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY; 398 399 if (modeSwitchingDisabled || primarySummary.disableRefreshRateSwitching) { 400 float fps = baseMode.getRefreshRate(); 401 primarySummary.disableModeSwitching(fps); 402 if (modeSwitchingDisabled) { 403 appRequestSummary.disableModeSwitching(fps); 404 primarySummary.disableRenderRateSwitching(fps); 405 if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) { 406 appRequestSummary.disableRenderRateSwitching(fps); 407 } 408 } 409 } 410 411 boolean allowGroupSwitching = 412 mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS; 413 414 // Some external displays physical refresh rate modes are slightly above 60hz. 415 // SurfaceFlinger will not enable these display modes unless it is configured to allow 416 // render rate at least at this frame rate. 417 if (mDisplayObserver.isExternalDisplayLocked(displayId)) { 418 primarySummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(), 419 primarySummary.maxRenderFrameRate); 420 appRequestSummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(), 421 appRequestSummary.maxRenderFrameRate); 422 } 423 424 return new DesiredDisplayModeSpecs(baseMode.getModeId(), 425 allowGroupSwitching, 426 new RefreshRateRanges( 427 new RefreshRateRange( 428 primarySummary.minPhysicalRefreshRate, 429 primarySummary.maxPhysicalRefreshRate), 430 new RefreshRateRange( 431 primarySummary.minRenderFrameRate, 432 primarySummary.maxRenderFrameRate)), 433 new RefreshRateRanges( 434 new RefreshRateRange( 435 appRequestSummary.minPhysicalRefreshRate, 436 appRequestSummary.maxPhysicalRefreshRate), 437 new RefreshRateRange( 438 appRequestSummary.minRenderFrameRate, 439 appRequestSummary.maxRenderFrameRate)), 440 mBrightnessObserver.getIdleScreenRefreshRateConfig()); 441 } 442 } 443 444 /** 445 * Gets the observer responsible for application display mode requests. 446 */ 447 @NonNull getAppRequestObserver()448 public AppRequestObserver getAppRequestObserver() { 449 // We don't need to lock here because mAppRequestObserver is a final field, which is 450 // guaranteed to be visible on all threads after construction. 451 return mAppRequestObserver; 452 } 453 isVrrSupportedLocked(int displayId)454 private boolean isVrrSupportedLocked(int displayId) { 455 DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.get(displayId); 456 return config != null && config.isVrrSupportEnabled(); 457 } 458 459 /** 460 * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate ranges. 461 */ setDesiredDisplayModeSpecsListener( @ullable DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener)462 public void setDesiredDisplayModeSpecsListener( 463 @Nullable DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener) { 464 synchronized (mLock) { 465 mDesiredDisplayModeSpecsListener = desiredDisplayModeSpecsListener; 466 } 467 } 468 469 /** 470 * Called when the underlying display device of the default display is changed. 471 * Some data in this class relates to the physical display of the device, and so we need to 472 * reload the configurations based on this. 473 * E.g. the brightness sensors and refresh rate capabilities depend on the physical display 474 * device that is being used, so will be reloaded. 475 * 476 * @param displayDeviceConfig configurations relating to the underlying display device. 477 */ defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig)478 public void defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig) { 479 synchronized (mLock) { 480 mDefaultDisplayDeviceConfig = displayDeviceConfig; 481 mSettingsObserver.setRefreshRates(displayDeviceConfig, 482 /* attemptReadFromFeatureParams= */ true); 483 mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig, 484 /* attemptReadFromFeatureParams= */ true); 485 mBrightnessObserver.reloadLightSensor(displayDeviceConfig); 486 mHbmObserver.setupHdrRefreshRates(displayDeviceConfig); 487 } 488 } 489 490 /** 491 * When enabled the app requested display mode is always selected and all 492 * other votes will be ignored. This is used for testing purposes. 493 */ setShouldAlwaysRespectAppRequestedMode(boolean enabled)494 public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { 495 synchronized (mLock) { 496 if (mAlwaysRespectAppRequest != enabled) { 497 mAlwaysRespectAppRequest = enabled; 498 notifyDesiredDisplayModeSpecsChangedLocked(); 499 } 500 } 501 } 502 503 /** 504 * Returns whether we are running in a mode which always selects the app requested display mode 505 * and ignores user settings and policies for low brightness, low battery etc. 506 */ shouldAlwaysRespectAppRequestedMode()507 public boolean shouldAlwaysRespectAppRequestedMode() { 508 synchronized (mLock) { 509 return mAlwaysRespectAppRequest; 510 } 511 } 512 513 /** 514 * Sets the display mode switching type. 515 * @param newType new mode switching type 516 */ setModeSwitchingType(@isplayManager.SwitchingType int newType)517 public void setModeSwitchingType(@DisplayManager.SwitchingType int newType) { 518 synchronized (mLock) { 519 if (newType != mModeSwitchingType) { 520 mModeSwitchingType = newType; 521 notifyDesiredDisplayModeSpecsChangedLocked(); 522 } 523 } 524 } 525 526 /** 527 * Returns the display mode switching type. 528 */ 529 @DisplayManager.SwitchingType getModeSwitchingType()530 public int getModeSwitchingType() { 531 synchronized (mLock) { 532 return mModeSwitchingType; 533 } 534 } 535 536 /** 537 * Retrieve the Vote for the given display and priority. Intended only for testing purposes. 538 * 539 * @param displayId the display to query for 540 * @param priority the priority of the vote to return 541 * @return the vote corresponding to the given {@code displayId} and {@code priority}, 542 * or {@code null} if there isn't one 543 */ 544 @VisibleForTesting 545 @Nullable getVote(int displayId, int priority)546 Vote getVote(int displayId, int priority) { 547 SparseArray<Vote> votes = mVotesStorage.getVotes(displayId); 548 return votes.get(priority); 549 } 550 551 /** 552 * Delegates requestDisplayModes call to SystemRequestObserver 553 */ requestDisplayModes(IBinder token, int displayId, int[] modeIds)554 public void requestDisplayModes(IBinder token, int displayId, int[] modeIds) { 555 if (mSystemRequestObserver != null) { 556 boolean vrrSupported; 557 synchronized (mLock) { 558 vrrSupported = isVrrSupportedLocked(displayId); 559 } 560 if (vrrSupported) { 561 mSystemRequestObserver.requestDisplayModes(token, displayId, modeIds); 562 } 563 } 564 } 565 566 /** 567 * Print the object's state and debug information into the given stream. 568 * 569 * @param pw The stream to dump information to. 570 */ dump(PrintWriter pw)571 public void dump(PrintWriter pw) { 572 pw.println("DisplayModeDirector"); 573 synchronized (mLock) { 574 pw.println(" mSupportedModesByDisplay:"); 575 for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { 576 final int id = mSupportedModesByDisplay.keyAt(i); 577 final Display.Mode[] modes = mSupportedModesByDisplay.valueAt(i); 578 pw.println(" " + id + " -> " + Arrays.toString(modes)); 579 } 580 pw.println(" mAppSupportedModesByDisplay:"); 581 for (int i = 0; i < mAppSupportedModesByDisplay.size(); i++) { 582 final int id = mAppSupportedModesByDisplay.keyAt(i); 583 final Display.Mode[] modes = mAppSupportedModesByDisplay.valueAt(i); 584 pw.println(" " + id + " -> " + Arrays.toString(modes)); 585 } 586 pw.println(" mDefaultModeByDisplay:"); 587 for (int i = 0; i < mDefaultModeByDisplay.size(); i++) { 588 final int id = mDefaultModeByDisplay.keyAt(i); 589 final Display.Mode mode = mDefaultModeByDisplay.valueAt(i); 590 pw.println(" " + id + " -> " + mode); 591 } 592 pw.println(" mModeSwitchingType: " + switchingTypeToString(mModeSwitchingType)); 593 pw.println(" mAlwaysRespectAppRequest: " + mAlwaysRespectAppRequest); 594 mSettingsObserver.dumpLocked(pw); 595 mAppRequestObserver.dumpLocked(pw); 596 mBrightnessObserver.dumpLocked(pw); 597 mUdfpsObserver.dumpLocked(pw); 598 mHbmObserver.dumpLocked(pw); 599 mSkinThermalStatusObserver.dumpLocked(pw); 600 } 601 mVotesStorage.dump(pw); 602 mSensorObserver.dump(pw); 603 } 604 605 @GuardedBy("mLock") getMaxRefreshRateLocked(int displayId)606 private float getMaxRefreshRateLocked(int displayId) { 607 Display.Mode[] modes = mSupportedModesByDisplay.get(displayId); 608 float maxRefreshRate = 0f; 609 for (Display.Mode mode : modes) { 610 if (mode.getRefreshRate() > maxRefreshRate) { 611 maxRefreshRate = mode.getRefreshRate(); 612 } 613 } 614 return maxRefreshRate; 615 } 616 notifyDesiredDisplayModeSpecsChangedLocked()617 private void notifyDesiredDisplayModeSpecsChangedLocked() { 618 if (mDesiredDisplayModeSpecsListener != null 619 && !mHandler.hasMessages(MSG_REFRESH_RATE_RANGE_CHANGED)) { 620 // We need to post this to a handler to avoid calling out while holding the lock 621 // since we know there are things that both listen for changes as well as provide 622 // information. If we did call out while holding the lock, then there's no 623 // guaranteed lock order and we run the real of risk deadlock. 624 Message msg = mHandler.obtainMessage( 625 MSG_REFRESH_RATE_RANGE_CHANGED, mDesiredDisplayModeSpecsListener); 626 msg.sendToTarget(); 627 } 628 } 629 switchingTypeToString(@isplayManager.SwitchingType int type)630 private static String switchingTypeToString(@DisplayManager.SwitchingType int type) { 631 switch (type) { 632 case DisplayManager.SWITCHING_TYPE_NONE: 633 return "SWITCHING_TYPE_NONE"; 634 case DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS: 635 return "SWITCHING_TYPE_WITHIN_GROUPS"; 636 case DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS: 637 return "SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS"; 638 case DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY: 639 return "SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY"; 640 default: 641 return "Unknown SwitchingType " + type; 642 } 643 } 644 645 @VisibleForTesting injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay)646 void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) { 647 mSupportedModesByDisplay = supportedModesByDisplay; 648 } 649 650 @VisibleForTesting injectAppSupportedModesByDisplay(SparseArray<Display.Mode[]> appSupportedModesByDisplay)651 void injectAppSupportedModesByDisplay(SparseArray<Display.Mode[]> appSupportedModesByDisplay) { 652 mAppSupportedModesByDisplay = appSupportedModesByDisplay; 653 } 654 655 @VisibleForTesting injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay)656 void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) { 657 mDefaultModeByDisplay = defaultModeByDisplay; 658 } 659 660 @VisibleForTesting injectDisplayDeviceConfigByDisplay(SparseArray<DisplayDeviceConfig> ddcByDisplay)661 void injectDisplayDeviceConfigByDisplay(SparseArray<DisplayDeviceConfig> ddcByDisplay) { 662 mDisplayDeviceConfigByDisplay = ddcByDisplay; 663 } 664 665 @VisibleForTesting injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay)666 void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) { 667 mVotesStorage.injectVotesByDisplay(votesByDisplay); 668 } 669 670 @VisibleForTesting injectBrightnessObserver(BrightnessObserver brightnessObserver)671 void injectBrightnessObserver(BrightnessObserver brightnessObserver) { 672 mBrightnessObserver = brightnessObserver; 673 } 674 675 @VisibleForTesting getBrightnessObserver()676 BrightnessObserver getBrightnessObserver() { 677 return mBrightnessObserver; 678 } 679 680 @VisibleForTesting getSettingsObserver()681 SettingsObserver getSettingsObserver() { 682 return mSettingsObserver; 683 } 684 685 @VisibleForTesting getUdpfsObserver()686 UdfpsObserver getUdpfsObserver() { 687 return mUdfpsObserver; 688 } 689 690 @VisibleForTesting getHbmObserver()691 HbmObserver getHbmObserver() { 692 return mHbmObserver; 693 } 694 695 @VisibleForTesting getDisplayObserver()696 DisplayObserver getDisplayObserver() { 697 return mDisplayObserver; 698 } 699 700 @VisibleForTesting getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate)701 DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( 702 float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { 703 synchronized (mLock) { 704 mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, 705 defaultRefreshRate, Display.DEFAULT_DISPLAY); 706 return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY); 707 } 708 } 709 710 /** 711 * Provides access to DisplayDeviceConfig for specific display 712 */ 713 public interface DisplayDeviceConfigProvider { 714 /** 715 * Returns DisplayDeviceConfig for specific display 716 */ getDisplayDeviceConfig(int displayId)717 @Nullable DisplayDeviceConfig getDisplayDeviceConfig(int displayId); 718 } 719 720 /** 721 * Listens for changes refresh rate coordination. 722 */ 723 public interface DesiredDisplayModeSpecsListener { 724 /** 725 * Called when the refresh rate range may have changed. 726 */ onDesiredDisplayModeSpecsChanged()727 void onDesiredDisplayModeSpecsChanged(); 728 } 729 730 private final class DisplayModeDirectorHandler extends Handler { DisplayModeDirectorHandler(Looper looper)731 DisplayModeDirectorHandler(Looper looper) { 732 super(looper, null, true /*async*/); 733 } 734 735 @Override handleMessage(Message msg)736 public void handleMessage(Message msg) { 737 switch (msg.what) { 738 case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: { 739 Pair<float[], float[]> thresholds = (Pair<float[], float[]>) msg.obj; 740 mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged( 741 thresholds.first, thresholds.second); 742 break; 743 } 744 745 case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: { 746 int refreshRateInZone = msg.arg1; 747 mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged( 748 refreshRateInZone); 749 break; 750 } 751 752 case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: { 753 Pair<float[], float[]> thresholds = (Pair<float[], float[]>) msg.obj; 754 755 mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged( 756 thresholds.first, thresholds.second); 757 758 break; 759 } 760 761 case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: { 762 int refreshRateInZone = msg.arg1; 763 mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged( 764 refreshRateInZone); 765 break; 766 } 767 768 case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED: 769 Float defaultPeakRefreshRate = (Float) msg.obj; 770 mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged( 771 defaultPeakRefreshRate); 772 break; 773 774 case MSG_REFRESH_RATE_RANGE_CHANGED: 775 DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener = 776 (DesiredDisplayModeSpecsListener) msg.obj; 777 desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged(); 778 break; 779 780 case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: { 781 int refreshRateInHbmSunlight = msg.arg1; 782 mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged( 783 refreshRateInHbmSunlight); 784 break; 785 } 786 787 case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: { 788 int refreshRateInHbmHdr = msg.arg1; 789 mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr); 790 break; 791 } 792 } 793 } 794 } 795 796 /** 797 * Information about the desired display mode to be set by the system. Includes the base 798 * mode ID and the primary and app request refresh rate ranges. 799 * 800 * We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the 801 * distinction between the config ID / physical index that 802 * SurfaceControl.DesiredDisplayConfigSpecs uses, and the mode ID used here. 803 */ 804 public static final class DesiredDisplayModeSpecs { 805 806 /** 807 * Base mode ID. This is what system defaults to for all other settings, or 808 * if the refresh rate range is not available. 809 */ 810 public int baseModeId; 811 812 /** 813 * If true this will allow switching between modes in different display configuration 814 * groups. This way the user may see visual interruptions when the display mode changes. 815 */ 816 public boolean allowGroupSwitching; 817 818 /** 819 * Represents the idle time of the screen after which the associated display's refresh rate 820 * is to be reduced to preserve power 821 * Defaults to null, meaning that the device is not configured to have a timeout based on 822 * the surrounding conditions 823 * -1 means that the current conditions require no timeout 824 */ 825 @Nullable 826 public IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig; 827 828 /** 829 * The primary refresh rate ranges. 830 */ 831 public final RefreshRateRanges primary; 832 /** 833 * The app request refresh rate ranges. Lower priority considerations won't be included in 834 * this range, allowing SurfaceFlinger to consider additional refresh rates for apps that 835 * call setFrameRate(). This range will be greater than or equal to the primary refresh rate 836 * range, never smaller. 837 */ 838 public final RefreshRateRanges appRequest; 839 DesiredDisplayModeSpecs()840 public DesiredDisplayModeSpecs() { 841 primary = new RefreshRateRanges(); 842 appRequest = new RefreshRateRanges(); 843 } 844 DesiredDisplayModeSpecs(int baseModeId, boolean allowGroupSwitching, @NonNull RefreshRateRanges primary, @NonNull RefreshRateRanges appRequest, @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig)845 public DesiredDisplayModeSpecs(int baseModeId, 846 boolean allowGroupSwitching, 847 @NonNull RefreshRateRanges primary, 848 @NonNull RefreshRateRanges appRequest, 849 @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) { 850 this.baseModeId = baseModeId; 851 this.allowGroupSwitching = allowGroupSwitching; 852 this.primary = primary; 853 this.appRequest = appRequest; 854 this.mIdleScreenRefreshRateConfig = idleScreenRefreshRateConfig; 855 } 856 857 /** 858 * Returns a string representation of the object. 859 */ 860 @Override toString()861 public String toString() { 862 return String.format("baseModeId=%d allowGroupSwitching=%b" 863 + " primary=%s" 864 + " appRequest=%s" 865 + " idleScreenRefreshRateConfig=%s", 866 baseModeId, allowGroupSwitching, primary.toString(), 867 appRequest.toString(), String.valueOf(mIdleScreenRefreshRateConfig)); 868 } 869 870 /** 871 * Checks whether the two objects have the same values. 872 */ 873 @Override equals(Object other)874 public boolean equals(Object other) { 875 if (other == this) { 876 return true; 877 } 878 879 if (!(other instanceof DesiredDisplayModeSpecs)) { 880 return false; 881 } 882 883 DesiredDisplayModeSpecs desiredDisplayModeSpecs = (DesiredDisplayModeSpecs) other; 884 885 if (baseModeId != desiredDisplayModeSpecs.baseModeId) { 886 return false; 887 } 888 if (allowGroupSwitching != desiredDisplayModeSpecs.allowGroupSwitching) { 889 return false; 890 } 891 if (!primary.equals(desiredDisplayModeSpecs.primary)) { 892 return false; 893 } 894 if (!appRequest.equals( 895 desiredDisplayModeSpecs.appRequest)) { 896 return false; 897 } 898 899 if (!Objects.equals(mIdleScreenRefreshRateConfig, 900 desiredDisplayModeSpecs.mIdleScreenRefreshRateConfig)) { 901 return false; 902 } 903 return true; 904 } 905 906 @Override hashCode()907 public int hashCode() { 908 return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest, 909 mIdleScreenRefreshRateConfig); 910 } 911 912 /** 913 * Copy values from the other object. 914 */ copyFrom(DesiredDisplayModeSpecs other)915 public void copyFrom(DesiredDisplayModeSpecs other) { 916 baseModeId = other.baseModeId; 917 allowGroupSwitching = other.allowGroupSwitching; 918 primary.physical.min = other.primary.physical.min; 919 primary.physical.max = other.primary.physical.max; 920 primary.render.min = other.primary.render.min; 921 primary.render.max = other.primary.render.max; 922 923 appRequest.physical.min = other.appRequest.physical.min; 924 appRequest.physical.max = other.appRequest.physical.max; 925 appRequest.render.min = other.appRequest.render.min; 926 appRequest.render.max = other.appRequest.render.max; 927 928 if (other.mIdleScreenRefreshRateConfig == null) { 929 mIdleScreenRefreshRateConfig = null; 930 } else { 931 mIdleScreenRefreshRateConfig = 932 new IdleScreenRefreshRateConfig( 933 other.mIdleScreenRefreshRateConfig.timeoutMillis); 934 } 935 } 936 } 937 938 @VisibleForTesting 939 final class SettingsObserver extends ContentObserver { 940 private final Uri mPeakRefreshRateSetting = 941 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); 942 private final Uri mMinRefreshRateSetting = 943 Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE); 944 private final Uri mLowPowerModeSetting = 945 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE); 946 private final Uri mMatchContentFrameRateSetting = 947 Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE); 948 949 private final boolean mVsyncLowPowerVoteEnabled; 950 private final boolean mPeakRefreshRatePhysicalLimitEnabled; 951 952 private final Context mContext; 953 private final Handler mHandler; 954 private float mDefaultPeakRefreshRate; 955 private float mDefaultRefreshRate; 956 private boolean mIsLowPower = false; 957 958 private final DisplayManager.DisplayListener mDisplayListener = 959 new DisplayManager.DisplayListener() { 960 @Override 961 public void onDisplayAdded(int displayId) { 962 synchronized (mLock) { 963 updateLowPowerModeAllowedModesLocked(); 964 } 965 } 966 967 @Override 968 public void onDisplayRemoved(int displayId) { 969 mVotesStorage.updateVote(displayId, Vote.PRIORITY_LOW_POWER_MODE_MODES, 970 null); 971 } 972 973 @Override 974 public void onDisplayChanged(int displayId) { 975 synchronized (mLock) { 976 updateLowPowerModeAllowedModesLocked(); 977 } 978 } 979 }; 980 SettingsObserver(@onNull Context context, @NonNull Handler handler, DisplayManagerFlags flags)981 SettingsObserver(@NonNull Context context, @NonNull Handler handler, 982 DisplayManagerFlags flags) { 983 super(handler); 984 mContext = context; 985 mHandler = handler; 986 mVsyncLowPowerVoteEnabled = flags.isVsyncLowPowerVoteEnabled(); 987 mPeakRefreshRatePhysicalLimitEnabled = flags.isPeakRefreshRatePhysicalLimitEnabled(); 988 // We don't want to load from the DeviceConfig while constructing since this leads to 989 // a spike in the latency of DisplayManagerService startup. This happens because 990 // reading from the DeviceConfig is an intensive IO operation and having it in the 991 // startup phase where we thrive to keep the latency very low has significant impact. 992 setRefreshRates(/* displayDeviceConfig= */ null, 993 /* attemptReadFromFeatureParams= */ false); 994 } 995 996 /** 997 * This is used to update the refresh rate configs from the DeviceConfig, which 998 * if missing from DisplayDeviceConfig, and finally fallback to config.xml. 999 */ setRefreshRates(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1000 void setRefreshRates(DisplayDeviceConfig displayDeviceConfig, 1001 boolean attemptReadFromFeatureParams) { 1002 RefreshRateData refreshRateData = displayDeviceConfig == null ? null 1003 : displayDeviceConfig.getRefreshRateData(); 1004 setDefaultPeakRefreshRate(displayDeviceConfig, attemptReadFromFeatureParams); 1005 mDefaultRefreshRate = 1006 (refreshRateData == null) ? (float) mContext.getResources().getInteger( 1007 R.integer.config_defaultRefreshRate) 1008 : (float) refreshRateData.defaultRefreshRate; 1009 } 1010 observe()1011 public void observe() { 1012 final ContentResolver cr = mContext.getContentResolver(); 1013 mInjector.registerPeakRefreshRateObserver(cr, this); 1014 mInjector.registerMinRefreshRateObserver(cr, this); 1015 cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this, 1016 UserHandle.USER_SYSTEM); 1017 cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/, 1018 this); 1019 mInjector.registerDisplayListener(mDisplayListener, mHandler); 1020 1021 float deviceConfigDefaultPeakRefresh = 1022 mConfigParameterProvider.getPeakRefreshRateDefault(); 1023 if (deviceConfigDefaultPeakRefresh != -1) { 1024 mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh; 1025 } 1026 1027 synchronized (mLock) { 1028 updateRefreshRateSettingLocked(); 1029 updateLowPowerModeSettingLocked(); 1030 updateModeSwitchingTypeSettingLocked(); 1031 } 1032 1033 } 1034 setDefaultRefreshRate(float refreshRate)1035 public void setDefaultRefreshRate(float refreshRate) { 1036 synchronized (mLock) { 1037 mDefaultRefreshRate = refreshRate; 1038 updateRefreshRateSettingLocked(); 1039 } 1040 } 1041 onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate)1042 public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) { 1043 synchronized (mLock) { 1044 if (defaultPeakRefreshRate == null) { 1045 setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, 1046 /* attemptReadFromFeatureParams= */ false); 1047 } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { 1048 mDefaultPeakRefreshRate = defaultPeakRefreshRate; 1049 } 1050 updateRefreshRateSettingLocked(); 1051 } 1052 } 1053 1054 @Override onChange(boolean selfChange, Uri uri, int userId)1055 public void onChange(boolean selfChange, Uri uri, int userId) { 1056 synchronized (mLock) { 1057 if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { 1058 updateRefreshRateSettingLocked(); 1059 } else if (mLowPowerModeSetting.equals(uri)) { 1060 updateLowPowerModeSettingLocked(); 1061 } else if (mMatchContentFrameRateSetting.equals(uri)) { 1062 updateModeSwitchingTypeSettingLocked(); 1063 } 1064 } 1065 } 1066 1067 @VisibleForTesting getDefaultRefreshRate()1068 float getDefaultRefreshRate() { 1069 return mDefaultRefreshRate; 1070 } 1071 1072 @VisibleForTesting getDefaultPeakRefreshRate()1073 float getDefaultPeakRefreshRate() { 1074 return mDefaultPeakRefreshRate; 1075 } 1076 setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1077 private void setDefaultPeakRefreshRate(DisplayDeviceConfig displayDeviceConfig, 1078 boolean attemptReadFromFeatureParams) { 1079 float defaultPeakRefreshRate = -1; 1080 1081 if (attemptReadFromFeatureParams) { 1082 try { 1083 defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault(); 1084 } catch (Exception exception) { 1085 // Do nothing 1086 } 1087 } 1088 if (defaultPeakRefreshRate == -1) { 1089 defaultPeakRefreshRate = 1090 (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger( 1091 R.integer.config_defaultPeakRefreshRate) 1092 : (float) displayDeviceConfig.getRefreshRateData() 1093 .defaultPeakRefreshRate; 1094 } 1095 mDefaultPeakRefreshRate = defaultPeakRefreshRate; 1096 } 1097 updateLowPowerModeSettingLocked()1098 private void updateLowPowerModeSettingLocked() { 1099 mIsLowPower = Settings.Global.getInt(mContext.getContentResolver(), 1100 Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0; 1101 final Vote vote; 1102 if (mIsLowPower) { 1103 vote = Vote.forRenderFrameRates(0f, 60f); 1104 } else { 1105 vote = null; 1106 } 1107 mVotesStorage.updateGlobalVote(Vote.PRIORITY_LOW_POWER_MODE_RENDER_RATE, vote); 1108 mBrightnessObserver.onLowPowerModeEnabledLocked(mIsLowPower); 1109 updateLowPowerModeAllowedModesLocked(); 1110 } 1111 updateLowPowerModeAllowedModesLocked()1112 private void updateLowPowerModeAllowedModesLocked() { 1113 if (!mVsyncLowPowerVoteEnabled) { 1114 return; 1115 } 1116 if (mIsLowPower) { 1117 for (int i = 0; i < mDisplayDeviceConfigByDisplay.size(); i++) { 1118 DisplayDeviceConfig config = mDisplayDeviceConfigByDisplay.valueAt(i); 1119 if (config == null) { 1120 continue; 1121 } 1122 List<SupportedModeData> supportedModes = config 1123 .getRefreshRateData().lowPowerSupportedModes; 1124 mVotesStorage.updateVote( 1125 mDisplayDeviceConfigByDisplay.keyAt(i), 1126 Vote.PRIORITY_LOW_POWER_MODE_MODES, 1127 Vote.forSupportedRefreshRates(supportedModes)); 1128 } 1129 } else { 1130 mVotesStorage.removeAllVotesForPriority(Vote.PRIORITY_LOW_POWER_MODE_MODES); 1131 } 1132 } 1133 1134 /** 1135 * Update refresh rate settings for all displays 1136 */ 1137 @GuardedBy("mLock") updateRefreshRateSettingLocked()1138 private void updateRefreshRateSettingLocked() { 1139 for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { 1140 updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i)); 1141 } 1142 } 1143 1144 /** 1145 * Update refresh rate settings for a specific display 1146 * @param displayId The display ID 1147 */ 1148 @GuardedBy("mLock") updateRefreshRateSettingLocked(int displayId)1149 private void updateRefreshRateSettingLocked(int displayId) { 1150 final ContentResolver cr = mContext.getContentResolver(); 1151 if (!mSupportedModesByDisplay.contains(displayId)) { 1152 Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display " 1153 + displayId); 1154 return; 1155 } 1156 float highestRefreshRate = getMaxRefreshRateLocked(displayId); 1157 1158 float minRefreshRate = Settings.System.getFloatForUser(cr, 1159 Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId()); 1160 if (Float.isInfinite(minRefreshRate)) { 1161 // Infinity means that we want the highest possible refresh rate 1162 minRefreshRate = highestRefreshRate; 1163 } 1164 1165 float peakRefreshRate = Settings.System.getFloatForUser(cr, 1166 Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate, cr.getUserId()); 1167 if (Float.isInfinite(peakRefreshRate)) { 1168 // Infinity means that we want the highest possible refresh rate 1169 peakRefreshRate = highestRefreshRate; 1170 } 1171 1172 updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate, 1173 displayId); 1174 } 1175 1176 @GuardedBy("mLock") updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, float defaultRefreshRate, int displayId)1177 private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, 1178 float defaultRefreshRate, int displayId) { 1179 // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is 1180 // used to predict if we're going to be doing frequent refresh rate switching, and if 1181 // so, enable the brightness observer. The logic here is more complicated and fragile 1182 // than necessary, and we should improve it. See b/156304339 for more info. 1183 if (mPeakRefreshRatePhysicalLimitEnabled) { 1184 Vote peakVote = peakRefreshRate == 0f 1185 ? null 1186 : Vote.forPhysicalRefreshRates(0f, 1187 Math.max(minRefreshRate, peakRefreshRate)); 1188 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, 1189 peakVote); 1190 } 1191 Vote peakRenderVote = peakRefreshRate == 0f 1192 ? null 1193 : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate)); 1194 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, 1195 peakRenderVote); 1196 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, 1197 Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY)); 1198 Vote defaultVote = 1199 defaultRefreshRate == 0f 1200 ? null : Vote.forRenderFrameRates(0f, defaultRefreshRate); 1201 mVotesStorage.updateGlobalVote(Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, defaultVote); 1202 1203 float maxRefreshRate; 1204 if (peakRefreshRate == 0f && defaultRefreshRate == 0f) { 1205 // We require that at least one of the peak or default refresh rate values are 1206 // set. The brightness observer requires that we're able to predict whether or not 1207 // we're going to do frequent refresh rate switching, and with the way the code is 1208 // currently written, we need either a default or peak refresh rate value for that. 1209 Slog.e(TAG, "Default and peak refresh rates are both 0. One of them should be set" 1210 + " to a valid value."); 1211 maxRefreshRate = minRefreshRate; 1212 } else if (peakRefreshRate == 0f) { 1213 maxRefreshRate = defaultRefreshRate; 1214 } else if (defaultRefreshRate == 0f) { 1215 maxRefreshRate = peakRefreshRate; 1216 } else { 1217 maxRefreshRate = Math.min(defaultRefreshRate, peakRefreshRate); 1218 } 1219 1220 // TODO(b/310237068): Make this work for multiple displays 1221 if (displayId == Display.DEFAULT_DISPLAY) { 1222 mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, 1223 maxRefreshRate); 1224 } 1225 } 1226 removeRefreshRateSetting(int displayId)1227 private void removeRefreshRateSetting(int displayId) { 1228 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, 1229 null); 1230 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, 1231 null); 1232 mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null); 1233 } 1234 updateModeSwitchingTypeSettingLocked()1235 private void updateModeSwitchingTypeSettingLocked() { 1236 final ContentResolver cr = mContext.getContentResolver(); 1237 int switchingType = Settings.Secure.getIntForUser( 1238 cr, Settings.Secure.MATCH_CONTENT_FRAME_RATE, mModeSwitchingType /*default*/, 1239 cr.getUserId()); 1240 if (switchingType != mModeSwitchingType) { 1241 mModeSwitchingType = switchingType; 1242 notifyDesiredDisplayModeSpecsChangedLocked(); 1243 } 1244 } 1245 dumpLocked(PrintWriter pw)1246 public void dumpLocked(PrintWriter pw) { 1247 pw.println(" SettingsObserver"); 1248 pw.println(" mDefaultRefreshRate: " + mDefaultRefreshRate); 1249 pw.println(" mDefaultPeakRefreshRate: " + mDefaultPeakRefreshRate); 1250 } 1251 } 1252 1253 /** 1254 * Responsible for keeping track of app requested refresh rates per display 1255 */ 1256 public final class AppRequestObserver { 1257 private final boolean mIgnorePreferredRefreshRate; 1258 AppRequestObserver(DisplayManagerFlags flags)1259 AppRequestObserver(DisplayManagerFlags flags) { 1260 mIgnorePreferredRefreshRate = flags.ignoreAppPreferredRefreshRateRequest(); 1261 } 1262 1263 /** 1264 * Sets refresh rates from app request 1265 */ setAppRequest(int displayId, int modeId, float requestedRefreshRate, float requestedMinRefreshRateRange, float requestedMaxRefreshRateRange)1266 public void setAppRequest(int displayId, int modeId, float requestedRefreshRate, 1267 float requestedMinRefreshRateRange, float requestedMaxRefreshRateRange) { 1268 Display.Mode requestedMode; 1269 synchronized (mLock) { 1270 requestedMode = findModeLocked(displayId, modeId, requestedRefreshRate); 1271 } 1272 1273 Vote frameRateVote = getFrameRateVote( 1274 requestedMinRefreshRateRange, requestedMaxRefreshRateRange); 1275 Vote baseModeRefreshRateVote = getBaseModeVote(requestedMode, requestedRefreshRate); 1276 Vote sizeVote = getSizeVote(requestedMode); 1277 1278 mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE, 1279 frameRateVote); 1280 mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE, 1281 baseModeRefreshRateVote); 1282 mVotesStorage.updateVote(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote); 1283 } 1284 findModeLocked(int displayId, int modeId, float requestedRefreshRate)1285 private Display.Mode findModeLocked(int displayId, int modeId, float requestedRefreshRate) { 1286 Display.Mode mode = null; 1287 if (modeId != 0) { 1288 mode = findAppModeByIdLocked(displayId, modeId); 1289 } else if (requestedRefreshRate != 0 && !mIgnorePreferredRefreshRate) { // modeId == 0 1290 // Scan supported modes returned to find a mode with the same 1291 // size as the default display mode but with the specified refresh rate instead. 1292 mode = findDefaultModeByRefreshRateLocked(displayId, requestedRefreshRate); 1293 if (mode == null) { 1294 Slog.e(TAG, "Couldn't find a mode for the requestedRefreshRate: " 1295 + requestedRefreshRate + " on Display: " + displayId); 1296 } 1297 } 1298 return mode; 1299 } 1300 getFrameRateVote(float minRefreshRate, float maxRefreshRate)1301 private Vote getFrameRateVote(float minRefreshRate, float maxRefreshRate) { 1302 RefreshRateRange refreshRateRange = null; 1303 if (minRefreshRate > 0 || maxRefreshRate > 0) { 1304 float max = maxRefreshRate > 0 1305 ? maxRefreshRate : Float.POSITIVE_INFINITY; 1306 refreshRateRange = new RefreshRateRange(minRefreshRate, max); 1307 if (refreshRateRange.min == 0 && refreshRateRange.max == 0) { 1308 // minRefreshRate/maxRefreshRate were invalid 1309 refreshRateRange = null; 1310 } 1311 } 1312 return refreshRateRange != null 1313 ? Vote.forRenderFrameRates(refreshRateRange.min, refreshRateRange.max) : null; 1314 } 1315 getSizeVote(@ullable Display.Mode mode)1316 private Vote getSizeVote(@Nullable Display.Mode mode) { 1317 return mode != null 1318 ? Vote.forSize(mode.getPhysicalWidth(), mode.getPhysicalHeight()) : null; 1319 } 1320 getBaseModeVote(@ullable Display.Mode mode, float requestedRefreshRate)1321 private Vote getBaseModeVote(@Nullable Display.Mode mode, float requestedRefreshRate) { 1322 Vote vote = null; 1323 if (mode != null) { 1324 if (mode.isSynthetic()) { 1325 vote = Vote.forRequestedRefreshRate(mode.getRefreshRate()); 1326 } else { 1327 vote = Vote.forBaseModeRefreshRate(mode.getRefreshRate()); 1328 } 1329 } else if (requestedRefreshRate != 0f && mIgnorePreferredRefreshRate) { 1330 vote = Vote.forRequestedRefreshRate(requestedRefreshRate); 1331 } // !mIgnorePreferredRefreshRate case is handled by findModeLocked 1332 return vote; 1333 } 1334 1335 @Nullable findDefaultModeByRefreshRateLocked(int displayId, float refreshRate)1336 private Display.Mode findDefaultModeByRefreshRateLocked(int displayId, float refreshRate) { 1337 Display.Mode[] modes = mAppSupportedModesByDisplay.get(displayId); 1338 Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId); 1339 for (int i = 0; i < modes.length; i++) { 1340 if (modes[i].matches(defaultMode.getPhysicalWidth(), 1341 defaultMode.getPhysicalHeight(), refreshRate)) { 1342 return modes[i]; 1343 } 1344 } 1345 return null; 1346 } 1347 findAppModeByIdLocked(int displayId, int modeId)1348 private Display.Mode findAppModeByIdLocked(int displayId, int modeId) { 1349 Display.Mode[] modes = mAppSupportedModesByDisplay.get(displayId); 1350 if (modes == null) { 1351 return null; 1352 } 1353 for (Display.Mode mode : modes) { 1354 if (mode.getModeId() == modeId) { 1355 return mode; 1356 } 1357 } 1358 return null; 1359 } 1360 dumpLocked(PrintWriter pw)1361 private void dumpLocked(PrintWriter pw) { 1362 pw.println(" AppRequestObserver"); 1363 pw.println(" mIgnorePreferredRefreshRate: " + mIgnorePreferredRefreshRate); 1364 } 1365 } 1366 1367 @VisibleForTesting 1368 public final class DisplayObserver implements DisplayManager.DisplayListener { 1369 // Note that we can never call into DisplayManager or any of the non-POD classes it 1370 // returns, while holding mLock since it may call into DMS, which might be simultaneously 1371 // calling into us already holding its own lock. 1372 private final Context mContext; 1373 private final Handler mHandler; 1374 private final VotesStorage mVotesStorage; 1375 1376 private int mExternalDisplayPeakWidth; 1377 private int mExternalDisplayPeakHeight; 1378 private int mExternalDisplayPeakRefreshRate; 1379 private final boolean mRefreshRateSynchronizationEnabled; 1380 private final Set<Integer> mExternalDisplaysConnected = new HashSet<>(); 1381 DisplayObserver(Context context, Handler handler, VotesStorage votesStorage, Injector injector)1382 DisplayObserver(Context context, Handler handler, VotesStorage votesStorage, 1383 Injector injector) { 1384 mContext = context; 1385 mHandler = handler; 1386 mVotesStorage = votesStorage; 1387 mExternalDisplayPeakRefreshRate = mContext.getResources().getInteger( 1388 R.integer.config_externalDisplayPeakRefreshRate); 1389 mExternalDisplayPeakWidth = mContext.getResources().getInteger( 1390 R.integer.config_externalDisplayPeakWidth); 1391 mExternalDisplayPeakHeight = mContext.getResources().getInteger( 1392 R.integer.config_externalDisplayPeakHeight); 1393 mRefreshRateSynchronizationEnabled = mContext.getResources().getBoolean( 1394 R.bool.config_refreshRateSynchronizationEnabled); 1395 } 1396 isExternalDisplayLimitModeEnabled()1397 private boolean isExternalDisplayLimitModeEnabled() { 1398 return mExternalDisplayPeakWidth > 0 1399 && mExternalDisplayPeakHeight > 0 1400 && mExternalDisplayPeakRefreshRate > 0 1401 && mIsExternalDisplayLimitModeEnabled 1402 && mIsDisplayResolutionRangeVotingEnabled 1403 && mIsUserPreferredModeVoteEnabled; 1404 } 1405 isRefreshRateSynchronizationEnabled()1406 private boolean isRefreshRateSynchronizationEnabled() { 1407 return mRefreshRateSynchronizationEnabled 1408 && mIsDisplaysRefreshRatesSynchronizationEnabled; 1409 } 1410 observe()1411 public void observe() { 1412 mInjector.registerDisplayListener(this, mHandler); 1413 1414 // Populate existing displays 1415 SparseArray<Display.Mode[]> modes = new SparseArray<>(); 1416 SparseArray<Display.Mode[]> appModes = new SparseArray<>(); 1417 SparseArray<Display.Mode> defaultModes = new SparseArray<>(); 1418 Display[] displays = mInjector.getDisplays(); 1419 for (Display d : displays) { 1420 final int displayId = d.getDisplayId(); 1421 DisplayInfo info = getDisplayInfo(displayId); 1422 modes.put(displayId, info.supportedModes); 1423 appModes.put(displayId, info.appsSupportedModes); 1424 defaultModes.put(displayId, info.getDefaultMode()); 1425 } 1426 DisplayDeviceConfig defaultDisplayConfig = mDisplayDeviceConfigProvider 1427 .getDisplayDeviceConfig(Display.DEFAULT_DISPLAY); 1428 synchronized (mLock) { 1429 final int size = modes.size(); 1430 for (int i = 0; i < size; i++) { 1431 mSupportedModesByDisplay.put(modes.keyAt(i), modes.valueAt(i)); 1432 mAppSupportedModesByDisplay.put(appModes.keyAt(i), appModes.valueAt(i)); 1433 mDefaultModeByDisplay.put(defaultModes.keyAt(i), defaultModes.valueAt(i)); 1434 } 1435 mDisplayDeviceConfigByDisplay.put(Display.DEFAULT_DISPLAY, defaultDisplayConfig); 1436 } 1437 } 1438 1439 @Override onDisplayAdded(int displayId)1440 public void onDisplayAdded(int displayId) { 1441 updateDisplayDeviceConfig(displayId); 1442 DisplayInfo displayInfo = getDisplayInfo(displayId); 1443 updateDisplayModes(displayId, displayInfo); 1444 updateLayoutLimitedFrameRate(displayId, displayInfo); 1445 updateUserSettingDisplayPreferredSize(displayInfo); 1446 updateDisplaysPeakRefreshRateAndResolution(displayInfo); 1447 addDisplaysSynchronizedPeakRefreshRate(displayInfo); 1448 } 1449 1450 @Override onDisplayRemoved(int displayId)1451 public void onDisplayRemoved(int displayId) { 1452 synchronized (mLock) { 1453 mSupportedModesByDisplay.remove(displayId); 1454 mAppSupportedModesByDisplay.remove(displayId); 1455 mDefaultModeByDisplay.remove(displayId); 1456 mDisplayDeviceConfigByDisplay.remove(displayId); 1457 mSettingsObserver.removeRefreshRateSetting(displayId); 1458 } 1459 updateLayoutLimitedFrameRate(displayId, null); 1460 removeUserSettingDisplayPreferredSize(displayId); 1461 removeDisplaysPeakRefreshRateAndResolution(displayId); 1462 removeDisplaysSynchronizedPeakRefreshRate(displayId); 1463 } 1464 1465 @Override onDisplayChanged(int displayId)1466 public void onDisplayChanged(int displayId) { 1467 updateDisplayDeviceConfig(displayId); 1468 DisplayInfo displayInfo = getDisplayInfo(displayId); 1469 updateDisplayModes(displayId, displayInfo); 1470 updateLayoutLimitedFrameRate(displayId, displayInfo); 1471 updateUserSettingDisplayPreferredSize(displayInfo); 1472 } 1473 isExternalDisplayLocked(int displayId)1474 boolean isExternalDisplayLocked(int displayId) { 1475 return mExternalDisplaysConnected.contains(displayId); 1476 } 1477 1478 @Nullable getDisplayInfo(int displayId)1479 private DisplayInfo getDisplayInfo(int displayId) { 1480 DisplayInfo info = new DisplayInfo(); 1481 // Display info might be invalid, in this case return null 1482 return mInjector.getDisplayInfo(displayId, info) ? info : null; 1483 } 1484 updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info)1485 private void updateLayoutLimitedFrameRate(int displayId, @Nullable DisplayInfo info) { 1486 Vote vote = info != null && info.layoutLimitedRefreshRate != null 1487 ? Vote.forPhysicalRefreshRates(info.layoutLimitedRefreshRate.min, 1488 info.layoutLimitedRefreshRate.max) : null; 1489 mVotesStorage.updateVote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote); 1490 } 1491 removeUserSettingDisplayPreferredSize(int displayId)1492 private void removeUserSettingDisplayPreferredSize(int displayId) { 1493 if (!mIsUserPreferredModeVoteEnabled) { 1494 return; 1495 } 1496 mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, 1497 null); 1498 } 1499 updateUserSettingDisplayPreferredSize(@ullable DisplayInfo info)1500 private void updateUserSettingDisplayPreferredSize(@Nullable DisplayInfo info) { 1501 if (info == null || !mIsUserPreferredModeVoteEnabled) { 1502 return; 1503 } 1504 1505 var preferredMode = findDisplayPreferredMode(info); 1506 if (preferredMode == null) { 1507 removeUserSettingDisplayPreferredSize(info.displayId); 1508 return; 1509 } 1510 1511 mVotesStorage.updateVote(info.displayId, 1512 Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE, 1513 Vote.forSize(/* width */ preferredMode.getPhysicalWidth(), 1514 /* height */ preferredMode.getPhysicalHeight())); 1515 } 1516 1517 @Nullable findDisplayPreferredMode(@onNull DisplayInfo info)1518 private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) { 1519 if (info.userPreferredModeId == INVALID_MODE_ID) { 1520 return null; 1521 } 1522 for (var mode : info.supportedModes) { 1523 if (mode.getModeId() == info.userPreferredModeId) { 1524 return mode; 1525 } 1526 } 1527 return null; 1528 } 1529 removeDisplaysPeakRefreshRateAndResolution(int displayId)1530 private void removeDisplaysPeakRefreshRateAndResolution(int displayId) { 1531 if (!isExternalDisplayLimitModeEnabled()) { 1532 return; 1533 } 1534 1535 mVotesStorage.updateVote(displayId, 1536 Vote.PRIORITY_LIMIT_MODE, null); 1537 } 1538 updateDisplaysPeakRefreshRateAndResolution(@ullable final DisplayInfo info)1539 private void updateDisplaysPeakRefreshRateAndResolution(@Nullable final DisplayInfo info) { 1540 // Only consider external display, only in case the refresh rate and resolution limits 1541 // are non-zero. 1542 if (info == null || info.type != Display.TYPE_EXTERNAL 1543 || !isExternalDisplayLimitModeEnabled()) { 1544 return; 1545 } 1546 1547 mVotesStorage.updateVote(info.displayId, 1548 Vote.PRIORITY_LIMIT_MODE, 1549 Vote.forSizeAndPhysicalRefreshRatesRange( 1550 /* minWidth */ 0, /* minHeight */ 0, 1551 mExternalDisplayPeakWidth, 1552 mExternalDisplayPeakHeight, 1553 /* minPhysicalRefreshRate */ 0, 1554 mExternalDisplayPeakRefreshRate)); 1555 } 1556 1557 /** 1558 * Sets 60Hz target refresh rate as the vote with 1559 * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority. 1560 */ addDisplaysSynchronizedPeakRefreshRate(@ullable final DisplayInfo info)1561 private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) { 1562 if (info == null || info.type != Display.TYPE_EXTERNAL 1563 || !isRefreshRateSynchronizationEnabled()) { 1564 return; 1565 } 1566 synchronized (mLock) { 1567 mExternalDisplaysConnected.add(info.displayId); 1568 if (mExternalDisplaysConnected.size() != 1) { 1569 return; 1570 } 1571 } 1572 // set minRefreshRate as the max refresh rate. 1573 mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, 1574 Vote.forPhysicalRefreshRates( 1575 SYNCHRONIZED_REFRESH_RATE_TARGET 1576 - SYNCHRONIZED_REFRESH_RATE_TOLERANCE, 1577 SYNCHRONIZED_REFRESH_RATE_TARGET 1578 + SYNCHRONIZED_REFRESH_RATE_TOLERANCE)); 1579 } 1580 removeDisplaysSynchronizedPeakRefreshRate(final int displayId)1581 private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) { 1582 if (!isRefreshRateSynchronizationEnabled()) { 1583 return; 1584 } 1585 synchronized (mLock) { 1586 if (!isExternalDisplayLocked(displayId)) { 1587 return; 1588 } 1589 mExternalDisplaysConnected.remove(displayId); 1590 if (mExternalDisplaysConnected.size() != 0) { 1591 return; 1592 } 1593 } 1594 mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null); 1595 } 1596 updateDisplayDeviceConfig(int displayId)1597 private void updateDisplayDeviceConfig(int displayId) { 1598 DisplayDeviceConfig config = mDisplayDeviceConfigProvider 1599 .getDisplayDeviceConfig(displayId); 1600 synchronized (mLock) { 1601 mDisplayDeviceConfigByDisplay.put(displayId, config); 1602 } 1603 } 1604 updateDisplayModes(int displayId, @Nullable DisplayInfo info)1605 private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) { 1606 if (info == null) { 1607 return; 1608 } 1609 boolean changed = false; 1610 synchronized (mLock) { 1611 if (!Arrays.equals(mSupportedModesByDisplay.get(displayId), info.supportedModes)) { 1612 mSupportedModesByDisplay.put(displayId, info.supportedModes); 1613 changed = true; 1614 } 1615 if (!Arrays.equals(mAppSupportedModesByDisplay.get(displayId), 1616 info.appsSupportedModes)) { 1617 mAppSupportedModesByDisplay.put(displayId, info.appsSupportedModes); 1618 changed = true; 1619 } 1620 if (!Objects.equals(mDefaultModeByDisplay.get(displayId), info.getDefaultMode())) { 1621 changed = true; 1622 mDefaultModeByDisplay.put(displayId, info.getDefaultMode()); 1623 } 1624 if (changed) { 1625 notifyDesiredDisplayModeSpecsChangedLocked(); 1626 mSettingsObserver.updateRefreshRateSettingLocked(displayId); 1627 } 1628 } 1629 } 1630 } 1631 1632 /** 1633 * This class manages brightness threshold for switching between 60 hz and higher refresh rate. 1634 * See more information at the definition of 1635 * {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and 1636 * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}. 1637 */ 1638 @VisibleForTesting 1639 public class BrightnessObserver implements DisplayManager.DisplayListener { 1640 private static final int LIGHT_SENSOR_RATE_MS = 250; 1641 1642 /** 1643 * Brightness thresholds for the low zone. Paired with lux thresholds. 1644 * 1645 * A negative value means that only the lux threshold should be applied. 1646 */ 1647 private float[] mLowDisplayBrightnessThresholds; 1648 /** 1649 * Lux thresholds for the low zone. Paired with brightness thresholds. 1650 * 1651 * A negative value means that only the display brightness threshold should be applied. 1652 */ 1653 private float[] mLowAmbientBrightnessThresholds; 1654 1655 /** 1656 * Brightness thresholds for the high zone. Paired with lux thresholds. 1657 * 1658 * A negative value means that only the lux threshold should be applied. 1659 */ 1660 private float[] mHighDisplayBrightnessThresholds; 1661 /** 1662 * Lux thresholds for the high zone. Paired with brightness thresholds. 1663 * 1664 * A negative value means that only the display brightness threshold should be applied. 1665 */ 1666 private float[] mHighAmbientBrightnessThresholds; 1667 // valid threshold if any item from the array >= 0 1668 private boolean mShouldObserveDisplayLowChange; 1669 private boolean mShouldObserveAmbientLowChange; 1670 private boolean mShouldObserveDisplayHighChange; 1671 private boolean mShouldObserveAmbientHighChange; 1672 private boolean mLoggingEnabled; 1673 1674 private SensorManager mSensorManager; 1675 private Sensor mLightSensor; 1676 private Sensor mRegisteredLightSensor; 1677 private String mLightSensorType; 1678 private String mLightSensorName; 1679 private final LightSensorEventListener mLightSensorListener = 1680 new LightSensorEventListener(); 1681 // Take it as low brightness before valid sensor data comes 1682 private float mAmbientLux = -1.0f; 1683 private AmbientFilter mAmbientFilter; 1684 1685 /** 1686 * The current timeout configuration. This value is used by surface flinger to track the 1687 * time after which an idle screen's refresh rate is to be reduced. 1688 */ 1689 @Nullable 1690 private SurfaceControl.IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig; 1691 1692 private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 1693 1694 private final Context mContext; 1695 private final Injector mInjector; 1696 private final Handler mHandler; 1697 1698 1699 private final boolean mVsyncLowLightBlockingVoteEnabled; 1700 1701 private final IThermalEventListener.Stub mThermalListener = 1702 new IThermalEventListener.Stub() { 1703 @Override 1704 public void notifyThrottling(Temperature temp) { 1705 @Temperature.ThrottlingStatus int currentStatus = temp.getStatus(); 1706 synchronized (mLock) { 1707 if (mThermalStatus != currentStatus) { 1708 mThermalStatus = currentStatus; 1709 } 1710 onBrightnessChangedLocked(); 1711 } 1712 } 1713 }; 1714 private boolean mThermalRegistered; 1715 1716 // Enable light sensor only when mShouldObserveAmbientLowChange is true or 1717 // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate 1718 // changeable and low power mode off. After initialization, these states will 1719 // be updated from the same handler thread. 1720 private int mDefaultDisplayState = Display.STATE_UNKNOWN; 1721 private boolean mRefreshRateChangeable = false; 1722 private boolean mLowPowerModeEnabled = false; 1723 1724 @Nullable 1725 private SparseArray<RefreshRateRange> mLowZoneRefreshRateForThermals; 1726 private int mRefreshRateInLowZone; 1727 1728 @Nullable 1729 private SparseArray<RefreshRateRange> mHighZoneRefreshRateForThermals; 1730 private int mRefreshRateInHighZone; 1731 1732 @GuardedBy("mLock") 1733 private @Temperature.ThrottlingStatus int mThermalStatus = Temperature.THROTTLING_NONE; 1734 BrightnessObserver(Context context, Handler handler, Injector injector, DisplayManagerFlags flags)1735 BrightnessObserver(Context context, Handler handler, Injector injector, 1736 DisplayManagerFlags flags) { 1737 mContext = context; 1738 mHandler = handler; 1739 mInjector = injector; 1740 updateBlockingZoneThresholds(/* displayDeviceConfig= */ null, 1741 /* attemptReadFromFeatureParams= */ false); 1742 mRefreshRateInHighZone = context.getResources().getInteger( 1743 R.integer.config_fixedRefreshRateInHighZone); 1744 mVsyncLowLightBlockingVoteEnabled = flags.isVsyncLowLightVoteEnabled(); 1745 } 1746 1747 /** 1748 * This is used to update the blocking zone thresholds from the DeviceConfig, which 1749 * if missing from DisplayDeviceConfig, and finally fallback to config.xml. 1750 */ updateBlockingZoneThresholds(@ullable DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1751 public void updateBlockingZoneThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig, 1752 boolean attemptReadFromFeatureParams) { 1753 loadLowBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams); 1754 loadHighBrightnessThresholds(displayDeviceConfig, attemptReadFromFeatureParams); 1755 } 1756 1757 @VisibleForTesting getLowDisplayBrightnessThresholds()1758 float[] getLowDisplayBrightnessThresholds() { 1759 return mLowDisplayBrightnessThresholds; 1760 } 1761 1762 @VisibleForTesting getLowAmbientBrightnessThresholds()1763 float[] getLowAmbientBrightnessThresholds() { 1764 return mLowAmbientBrightnessThresholds; 1765 } 1766 1767 @VisibleForTesting getHighDisplayBrightnessThresholds()1768 float[] getHighDisplayBrightnessThresholds() { 1769 return mHighDisplayBrightnessThresholds; 1770 } 1771 1772 @VisibleForTesting getHighAmbientBrightnessThresholds()1773 float[] getHighAmbientBrightnessThresholds() { 1774 return mHighAmbientBrightnessThresholds; 1775 } 1776 1777 /** 1778 * @return the refresh rate to lock to when in a high brightness zone 1779 */ 1780 @VisibleForTesting getRefreshRateInHighZone()1781 int getRefreshRateInHighZone() { 1782 return mRefreshRateInHighZone; 1783 } 1784 1785 /** 1786 * @return the refresh rate to lock to when in a low brightness zone 1787 */ 1788 @VisibleForTesting getRefreshRateInLowZone()1789 int getRefreshRateInLowZone() { 1790 return mRefreshRateInLowZone; 1791 } 1792 1793 @VisibleForTesting getIdleScreenRefreshRateConfig()1794 IdleScreenRefreshRateConfig getIdleScreenRefreshRateConfig() { 1795 return mIdleScreenRefreshRateConfig; 1796 } 1797 loadLowBrightnessThresholds(@ullable DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1798 private void loadLowBrightnessThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig, 1799 boolean attemptReadFromFeatureParams) { 1800 loadRefreshRateInHighZone(displayDeviceConfig, attemptReadFromFeatureParams); 1801 loadRefreshRateInLowZone(displayDeviceConfig, attemptReadFromFeatureParams); 1802 mLowDisplayBrightnessThresholds = loadBrightnessThresholds( 1803 () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), 1804 () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), 1805 R.array.config_brightnessThresholdsOfPeakRefreshRate, 1806 displayDeviceConfig, attemptReadFromFeatureParams, 1807 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 1808 mLowAmbientBrightnessThresholds = loadBrightnessThresholds( 1809 () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(), 1810 () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), 1811 R.array.config_ambientThresholdsOfPeakRefreshRate, 1812 displayDeviceConfig, attemptReadFromFeatureParams, 1813 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 1814 if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) { 1815 throw new RuntimeException("display low brightness threshold array and ambient " 1816 + "brightness threshold array have different length: " 1817 + "displayBrightnessThresholds=" 1818 + Arrays.toString(mLowDisplayBrightnessThresholds) 1819 + ", ambientBrightnessThresholds=" 1820 + Arrays.toString(mLowAmbientBrightnessThresholds)); 1821 } 1822 } 1823 loadRefreshRateInLowZone(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1824 private void loadRefreshRateInLowZone(DisplayDeviceConfig displayDeviceConfig, 1825 boolean attemptReadFromFeatureParams) { 1826 int refreshRateInLowZone = -1; 1827 if (attemptReadFromFeatureParams) { 1828 try { 1829 refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); 1830 } catch (Exception exception) { 1831 // Do nothing 1832 } 1833 } 1834 if (refreshRateInLowZone == -1) { 1835 refreshRateInLowZone = (displayDeviceConfig == null) 1836 ? mContext.getResources().getInteger( 1837 R.integer.config_defaultRefreshRateInZone) 1838 : displayDeviceConfig.getDefaultLowBlockingZoneRefreshRate(); 1839 } 1840 mLowZoneRefreshRateForThermals = displayDeviceConfig == null ? null 1841 : displayDeviceConfig.getLowBlockingZoneThermalMap(); 1842 mRefreshRateInLowZone = refreshRateInLowZone; 1843 } 1844 loadRefreshRateInHighZone(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1845 private void loadRefreshRateInHighZone(DisplayDeviceConfig displayDeviceConfig, 1846 boolean attemptReadFromFeatureParams) { 1847 int refreshRateInHighZone = -1; 1848 if (attemptReadFromFeatureParams) { 1849 try { 1850 refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); 1851 } catch (Exception exception) { 1852 // Do nothing 1853 } 1854 } 1855 if (refreshRateInHighZone == -1) { 1856 refreshRateInHighZone = (displayDeviceConfig == null) 1857 ? mContext.getResources().getInteger( 1858 R.integer.config_fixedRefreshRateInHighZone) 1859 : displayDeviceConfig.getDefaultHighBlockingZoneRefreshRate(); 1860 } 1861 mHighZoneRefreshRateForThermals = displayDeviceConfig == null ? null 1862 : displayDeviceConfig.getHighBlockingZoneThermalMap(); 1863 mRefreshRateInHighZone = refreshRateInHighZone; 1864 } 1865 loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams)1866 private void loadHighBrightnessThresholds(DisplayDeviceConfig displayDeviceConfig, 1867 boolean attemptReadFromFeatureParams) { 1868 mHighDisplayBrightnessThresholds = loadBrightnessThresholds( 1869 () -> mConfigParameterProvider.getHighDisplayBrightnessThresholds(), 1870 () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), 1871 R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, 1872 displayDeviceConfig, attemptReadFromFeatureParams, 1873 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 1874 mHighAmbientBrightnessThresholds = loadBrightnessThresholds( 1875 () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(), 1876 () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), 1877 R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, 1878 displayDeviceConfig, attemptReadFromFeatureParams, 1879 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 1880 if (mHighDisplayBrightnessThresholds.length 1881 != mHighAmbientBrightnessThresholds.length) { 1882 throw new RuntimeException("display high brightness threshold array and ambient " 1883 + "brightness threshold array have different length: " 1884 + "displayBrightnessThresholds=" 1885 + Arrays.toString(mHighDisplayBrightnessThresholds) 1886 + ", ambientBrightnessThresholds=" 1887 + Arrays.toString(mHighAmbientBrightnessThresholds)); 1888 } 1889 } 1890 loadBrightnessThresholds( Callable<float[]> loadFromDeviceConfigDisplaySettingsCallable, Callable<float[]> loadFromDisplayDeviceConfigCallable, int brightnessThresholdOfFixedRefreshRateKey, DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams, Function<int[], float[]> conversion)1891 private float[] loadBrightnessThresholds( 1892 Callable<float[]> loadFromDeviceConfigDisplaySettingsCallable, 1893 Callable<float[]> loadFromDisplayDeviceConfigCallable, 1894 int brightnessThresholdOfFixedRefreshRateKey, 1895 DisplayDeviceConfig displayDeviceConfig, boolean attemptReadFromFeatureParams, 1896 Function<int[], float[]> conversion) { 1897 float[] brightnessThresholds = null; 1898 1899 if (attemptReadFromFeatureParams) { 1900 try { 1901 brightnessThresholds = loadFromDeviceConfigDisplaySettingsCallable.call(); 1902 } catch (Exception exception) { 1903 // Do nothing 1904 } 1905 } 1906 if (brightnessThresholds == null) { 1907 try { 1908 brightnessThresholds = displayDeviceConfig == null ? conversion.apply( 1909 mContext.getResources().getIntArray( 1910 brightnessThresholdOfFixedRefreshRateKey)) : 1911 loadFromDisplayDeviceConfigCallable.call(); 1912 } catch (Exception e) { 1913 Slog.e(TAG, "Unexpectedly failed to load display brightness threshold"); 1914 e.printStackTrace(); 1915 } 1916 } 1917 return brightnessThresholds; 1918 } 1919 observe(SensorManager sensorManager)1920 private void observe(SensorManager sensorManager) { 1921 mSensorManager = sensorManager; 1922 mBrightness = getBrightness(Display.DEFAULT_DISPLAY); 1923 1924 // DeviceConfig is accessible after system ready. 1925 float[] lowDisplayBrightnessThresholds = 1926 mConfigParameterProvider.getLowDisplayBrightnessThresholds(); 1927 float[] lowAmbientBrightnessThresholds = 1928 mConfigParameterProvider.getLowAmbientBrightnessThresholds(); 1929 if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null 1930 && lowDisplayBrightnessThresholds.length 1931 == lowAmbientBrightnessThresholds.length) { 1932 mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds; 1933 mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds; 1934 } 1935 1936 float[] highDisplayBrightnessThresholds = 1937 mConfigParameterProvider.getHighDisplayBrightnessThresholds(); 1938 float[] highAmbientBrightnessThresholds = 1939 mConfigParameterProvider.getHighAmbientBrightnessThresholds(); 1940 if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null 1941 && highDisplayBrightnessThresholds.length 1942 == highAmbientBrightnessThresholds.length) { 1943 mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds; 1944 mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds; 1945 } 1946 1947 final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); 1948 if (refreshRateInLowZone != -1) { 1949 mRefreshRateInLowZone = refreshRateInLowZone; 1950 } 1951 1952 final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); 1953 if (refreshRateInHighZone != -1) { 1954 mRefreshRateInHighZone = refreshRateInHighZone; 1955 } 1956 1957 restartObserver(); 1958 mDeviceConfigDisplaySettings.startListening(); 1959 1960 mInjector.registerDisplayListener(this, mHandler, 1961 DisplayManager.EVENT_FLAG_DISPLAY_CHANGED 1962 | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); 1963 } 1964 setLoggingEnabled(boolean loggingEnabled)1965 private void setLoggingEnabled(boolean loggingEnabled) { 1966 if (mLoggingEnabled == loggingEnabled) { 1967 return; 1968 } 1969 mLoggingEnabled = loggingEnabled; 1970 mLightSensorListener.setLoggingEnabled(loggingEnabled); 1971 } 1972 1973 @VisibleForTesting onRefreshRateSettingChangedLocked(float min, float max)1974 public void onRefreshRateSettingChangedLocked(float min, float max) { 1975 boolean changeable = (max - min > 1f && max > 60f); 1976 if (mRefreshRateChangeable != changeable) { 1977 mRefreshRateChangeable = changeable; 1978 updateSensorStatus(); 1979 if (!changeable) { 1980 removeFlickerRefreshRateVotes(); 1981 } 1982 } 1983 } 1984 1985 @VisibleForTesting onLowPowerModeEnabledLocked(boolean enabled)1986 void onLowPowerModeEnabledLocked(boolean enabled) { 1987 if (mLowPowerModeEnabled != enabled) { 1988 mLowPowerModeEnabled = enabled; 1989 updateSensorStatus(); 1990 if (enabled) { 1991 removeFlickerRefreshRateVotes(); 1992 } 1993 } 1994 } 1995 removeFlickerRefreshRateVotes()1996 private void removeFlickerRefreshRateVotes() { 1997 // Revoke previous vote from BrightnessObserver 1998 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, null); 1999 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null); 2000 } 2001 onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)2002 private void onDeviceConfigLowBrightnessThresholdsChanged(float[] displayThresholds, 2003 float[] ambientThresholds) { 2004 if (displayThresholds != null && ambientThresholds != null 2005 && displayThresholds.length == ambientThresholds.length) { 2006 mLowDisplayBrightnessThresholds = displayThresholds; 2007 mLowAmbientBrightnessThresholds = ambientThresholds; 2008 } else { 2009 DisplayDeviceConfig displayDeviceConfig; 2010 synchronized (mLock) { 2011 displayDeviceConfig = mDefaultDisplayDeviceConfig; 2012 } 2013 mLowDisplayBrightnessThresholds = loadBrightnessThresholds( 2014 () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), 2015 () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), 2016 R.array.config_brightnessThresholdsOfPeakRefreshRate, 2017 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 2018 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 2019 mLowAmbientBrightnessThresholds = loadBrightnessThresholds( 2020 () -> mConfigParameterProvider.getLowAmbientBrightnessThresholds(), 2021 () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), 2022 R.array.config_ambientThresholdsOfPeakRefreshRate, 2023 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 2024 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 2025 } 2026 restartObserver(); 2027 } 2028 2029 /** 2030 * Used to reload the lower blocking zone refresh rate in case of changes in the 2031 * DeviceConfig properties. 2032 */ onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate)2033 public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) { 2034 if (refreshRate == -1) { 2035 // Given there is no value available in DeviceConfig, lets not attempt loading it 2036 // from there. 2037 synchronized (mLock) { 2038 loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig, 2039 /* attemptReadFromFeatureParams= */ false); 2040 } 2041 restartObserver(); 2042 } else if (refreshRate != mRefreshRateInLowZone) { 2043 mRefreshRateInLowZone = refreshRate; 2044 restartObserver(); 2045 } 2046 } 2047 onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds, float[] ambientThresholds)2048 private void onDeviceConfigHighBrightnessThresholdsChanged(float[] displayThresholds, 2049 float[] ambientThresholds) { 2050 if (displayThresholds != null && ambientThresholds != null 2051 && displayThresholds.length == ambientThresholds.length) { 2052 mHighDisplayBrightnessThresholds = displayThresholds; 2053 mHighAmbientBrightnessThresholds = ambientThresholds; 2054 } else { 2055 DisplayDeviceConfig displayDeviceConfig; 2056 synchronized (mLock) { 2057 displayDeviceConfig = mDefaultDisplayDeviceConfig; 2058 } 2059 mHighDisplayBrightnessThresholds = loadBrightnessThresholds( 2060 () -> mConfigParameterProvider.getLowDisplayBrightnessThresholds(), 2061 () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), 2062 R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, 2063 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 2064 DeviceConfigParsingUtils::displayBrightnessThresholdsIntToFloat); 2065 mHighAmbientBrightnessThresholds = loadBrightnessThresholds( 2066 () -> mConfigParameterProvider.getHighAmbientBrightnessThresholds(), 2067 () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), 2068 R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, 2069 displayDeviceConfig, /* attemptReadFromFeatureParams= */ false, 2070 DeviceConfigParsingUtils::ambientBrightnessThresholdsIntToFloat); 2071 } 2072 restartObserver(); 2073 } 2074 2075 /** 2076 * Used to reload the higher blocking zone refresh rate in case of changes in the 2077 * DeviceConfig properties. 2078 */ onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate)2079 public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) { 2080 if (refreshRate == -1) { 2081 // Given there is no value available in DeviceConfig, lets not attempt loading it 2082 // from there. 2083 synchronized (mLock) { 2084 loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig, 2085 /* attemptReadFromFeatureParams= */ false); 2086 } 2087 restartObserver(); 2088 } else if (refreshRate != mRefreshRateInHighZone) { 2089 mRefreshRateInHighZone = refreshRate; 2090 restartObserver(); 2091 } 2092 } 2093 dumpLocked(PrintWriter pw)2094 void dumpLocked(PrintWriter pw) { 2095 pw.println(" BrightnessObserver"); 2096 pw.println(" mAmbientLux: " + mAmbientLux); 2097 pw.println(" mBrightness: " + mBrightness); 2098 pw.println(" mDefaultDisplayState: " + mDefaultDisplayState); 2099 pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled); 2100 pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable); 2101 pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange); 2102 pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange); 2103 pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone); 2104 2105 for (float d : mLowDisplayBrightnessThresholds) { 2106 pw.println(" mDisplayLowBrightnessThreshold: " + d); 2107 } 2108 2109 for (float d : mLowAmbientBrightnessThresholds) { 2110 pw.println(" mAmbientLowBrightnessThreshold: " + d); 2111 } 2112 2113 pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange); 2114 pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange); 2115 pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone); 2116 2117 for (float d : mHighDisplayBrightnessThresholds) { 2118 pw.println(" mDisplayHighBrightnessThresholds: " + d); 2119 } 2120 2121 for (float d : mHighAmbientBrightnessThresholds) { 2122 pw.println(" mAmbientHighBrightnessThresholds: " + d); 2123 } 2124 2125 pw.println(" mRegisteredLightSensor: " + mRegisteredLightSensor); 2126 pw.println(" mLightSensor: " + mLightSensor); 2127 pw.println(" mLightSensorName: " + mLightSensorName); 2128 pw.println(" mLightSensorType: " + mLightSensorType); 2129 mLightSensorListener.dumpLocked(pw); 2130 2131 if (mAmbientFilter != null) { 2132 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 2133 mAmbientFilter.dump(ipw); 2134 } 2135 } 2136 2137 @Override onDisplayAdded(int displayId)2138 public void onDisplayAdded(int displayId) {} 2139 2140 @Override onDisplayRemoved(int displayId)2141 public void onDisplayRemoved(int displayId) {} 2142 2143 @Override onDisplayChanged(int displayId)2144 public void onDisplayChanged(int displayId) { 2145 if (displayId == Display.DEFAULT_DISPLAY) { 2146 updateDefaultDisplayState(); 2147 2148 // We don't support multiple display blocking zones yet, so only handle 2149 // brightness changes for the default display for now. 2150 float brightness = getBrightness(displayId); 2151 synchronized (mLock) { 2152 if (!BrightnessSynchronizer.floatEquals(brightness, mBrightness)) { 2153 mBrightness = brightness; 2154 onBrightnessChangedLocked(); 2155 } 2156 } 2157 } 2158 } 2159 hasLowLightVrrConfig()2160 private boolean hasLowLightVrrConfig() { 2161 DisplayDeviceConfig config; 2162 synchronized (mLock) { 2163 config = mDefaultDisplayDeviceConfig; 2164 } 2165 return mVsyncLowLightBlockingVoteEnabled 2166 && config != null 2167 && config.isVrrSupportEnabled() 2168 && !config.getRefreshRateData().lowLightBlockingZoneSupportedModes.isEmpty(); 2169 } 2170 restartObserver()2171 private void restartObserver() { 2172 if (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig()) { 2173 mShouldObserveDisplayLowChange = hasValidThreshold( 2174 mLowDisplayBrightnessThresholds); 2175 mShouldObserveAmbientLowChange = hasValidThreshold( 2176 mLowAmbientBrightnessThresholds); 2177 } else { 2178 mShouldObserveDisplayLowChange = false; 2179 mShouldObserveAmbientLowChange = false; 2180 } 2181 2182 if (mRefreshRateInHighZone > 0) { 2183 mShouldObserveDisplayHighChange = hasValidThreshold( 2184 mHighDisplayBrightnessThresholds); 2185 mShouldObserveAmbientHighChange = hasValidThreshold( 2186 mHighAmbientBrightnessThresholds); 2187 } else { 2188 mShouldObserveDisplayHighChange = false; 2189 mShouldObserveAmbientHighChange = false; 2190 } 2191 2192 if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) { 2193 Sensor lightSensor = getLightSensor(); 2194 2195 if (lightSensor != null && lightSensor != mLightSensor) { 2196 final Resources res = mContext.getResources(); 2197 2198 mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res); 2199 mLightSensor = lightSensor; 2200 } 2201 } else { 2202 mAmbientFilter = null; 2203 mLightSensor = null; 2204 } 2205 2206 updateSensorStatus(); 2207 synchronized (mLock) { 2208 onBrightnessChangedLocked(); 2209 } 2210 } 2211 reloadLightSensor(DisplayDeviceConfig displayDeviceConfig)2212 private void reloadLightSensor(DisplayDeviceConfig displayDeviceConfig) { 2213 reloadLightSensorData(displayDeviceConfig); 2214 restartObserver(); 2215 } 2216 reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig)2217 private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) { 2218 // The displayDeviceConfig (ddc) contains display specific preferences. When loaded, 2219 // it naturally falls back to the global config.xml. 2220 if (displayDeviceConfig != null 2221 && displayDeviceConfig.getAmbientLightSensor() != null) { 2222 // This covers both the ddc and the config.xml fallback 2223 mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type; 2224 mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name; 2225 } else if (mLightSensorName == null && mLightSensorType == null) { 2226 Resources resources = mContext.getResources(); 2227 mLightSensorType = resources.getString( 2228 com.android.internal.R.string.config_displayLightSensorType); 2229 mLightSensorName = ""; 2230 } 2231 } 2232 getLightSensor()2233 private Sensor getLightSensor() { 2234 return SensorUtils.findSensor(mSensorManager, mLightSensorType, 2235 mLightSensorName, Sensor.TYPE_LIGHT); 2236 } 2237 2238 /** 2239 * Checks to see if at least one value is positive, in which case it is necessary to listen 2240 * to value changes. 2241 */ hasValidThreshold(float[] a)2242 private boolean hasValidThreshold(float[] a) { 2243 for (float d: a) { 2244 if (d >= 0) { 2245 return true; 2246 } 2247 } 2248 2249 return false; 2250 } 2251 2252 /** 2253 * Check if we're in the low zone where higher refresh rates aren't allowed to prevent 2254 * flickering. 2255 * @param brightness The brightness value or a negative value meaning that only the lux 2256 * threshold should be applied 2257 * @param lux The lux value. If negative, only the brightness threshold is applied 2258 * @return True if we're in the low zone 2259 */ isInsideLowZone(float brightness, float lux)2260 private boolean isInsideLowZone(float brightness, float lux) { 2261 for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) { 2262 float disp = mLowDisplayBrightnessThresholds[i]; 2263 float ambi = mLowAmbientBrightnessThresholds[i]; 2264 2265 if (disp >= 0 && ambi >= 0) { 2266 if (brightness <= disp && lux <= ambi) { 2267 return true; 2268 } 2269 } else if (disp >= 0) { 2270 if (brightness <= disp) { 2271 return true; 2272 } 2273 } else if (ambi >= 0) { 2274 if (lux <= ambi) { 2275 return true; 2276 } 2277 } 2278 } 2279 2280 return false; 2281 } 2282 2283 /** 2284 * Check if we're in the high zone where higher refresh rates aren't allowed to prevent 2285 * flickering. 2286 * @param brightness The brightness value or a negative value meaning that only the lux 2287 * threshold should be applied 2288 * @param lux The lux value. If negative, only the brightness threshold is applied 2289 * @return True if we're in the high zone 2290 */ isInsideHighZone(float brightness, float lux)2291 private boolean isInsideHighZone(float brightness, float lux) { 2292 for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) { 2293 float disp = mHighDisplayBrightnessThresholds[i]; 2294 float ambi = mHighAmbientBrightnessThresholds[i]; 2295 2296 if (disp >= 0 && ambi >= 0) { 2297 if (brightness >= disp && lux >= ambi) { 2298 return true; 2299 } 2300 } else if (disp >= 0) { 2301 if (brightness >= disp) { 2302 return true; 2303 } 2304 } else if (ambi >= 0) { 2305 if (lux >= ambi) { 2306 return true; 2307 } 2308 } 2309 } 2310 2311 return false; 2312 } 2313 2314 @GuardedBy("mLock") onBrightnessChangedLocked()2315 private void onBrightnessChangedLocked() { 2316 if (!mRefreshRateChangeable || mLowPowerModeEnabled) { 2317 return; 2318 } 2319 Vote refreshRateVote = null; 2320 Vote refreshRateSwitchingVote = null; 2321 2322 if (Float.isNaN(mBrightness)) { 2323 // Either the setting isn't available or we shouldn't be observing yet anyways. 2324 // Either way, just bail out since there's nothing we can do here. 2325 return; 2326 } 2327 2328 boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux); 2329 if (insideLowZone) { 2330 if (hasLowLightVrrConfig()) { 2331 refreshRateVote = Vote.forSupportedRefreshRates(mDefaultDisplayDeviceConfig 2332 .getRefreshRateData().lowLightBlockingZoneSupportedModes); 2333 } else { 2334 refreshRateVote = Vote.forPhysicalRefreshRates( 2335 mRefreshRateInLowZone, mRefreshRateInLowZone); 2336 refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); 2337 } 2338 if (mLowZoneRefreshRateForThermals != null) { 2339 RefreshRateRange range = SkinThermalStatusObserver 2340 .findBestMatchingRefreshRateRange(mThermalStatus, 2341 mLowZoneRefreshRateForThermals); 2342 if (range != null) { 2343 refreshRateVote = 2344 Vote.forPhysicalRefreshRates(range.min, range.max); 2345 } 2346 } 2347 } 2348 2349 boolean insideHighZone = hasValidHighZone() 2350 && isInsideHighZone(mBrightness, mAmbientLux); 2351 if (insideHighZone) { 2352 refreshRateVote = 2353 Vote.forPhysicalRefreshRates(mRefreshRateInHighZone, 2354 mRefreshRateInHighZone); 2355 if (mHighZoneRefreshRateForThermals != null) { 2356 RefreshRateRange range = SkinThermalStatusObserver 2357 .findBestMatchingRefreshRateRange(mThermalStatus, 2358 mHighZoneRefreshRateForThermals); 2359 if (range != null) { 2360 refreshRateVote = 2361 Vote.forPhysicalRefreshRates(range.min, range.max); 2362 } 2363 } 2364 refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching(); 2365 } 2366 2367 if (mLoggingEnabled) { 2368 Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux 2369 + ", Vote " + refreshRateVote); 2370 } 2371 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote); 2372 mVotesStorage.updateGlobalVote(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, 2373 refreshRateSwitchingVote); 2374 } 2375 hasValidLowZone()2376 private boolean hasValidLowZone() { 2377 return (mRefreshRateInLowZone > 0 || hasLowLightVrrConfig()) 2378 && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange); 2379 } 2380 hasValidHighZone()2381 private boolean hasValidHighZone() { 2382 return mRefreshRateInHighZone > 0 2383 && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange); 2384 } 2385 updateDefaultDisplayState()2386 private void updateDefaultDisplayState() { 2387 Display display = mInjector.getDisplay(Display.DEFAULT_DISPLAY); 2388 if (display == null) { 2389 return; 2390 } 2391 2392 setDefaultDisplayState(display.getState()); 2393 } 2394 2395 @VisibleForTesting setDefaultDisplayState(int state)2396 void setDefaultDisplayState(int state) { 2397 if (mLoggingEnabled) { 2398 Slog.d(TAG, "setDefaultDisplayState: mDefaultDisplayState = " 2399 + mDefaultDisplayState + ", state = " + state); 2400 } 2401 2402 if (mDefaultDisplayState != state) { 2403 mDefaultDisplayState = state; 2404 updateSensorStatus(); 2405 } 2406 } 2407 updateSensorStatus()2408 private void updateSensorStatus() { 2409 if (mSensorManager == null || mLightSensorListener == null) { 2410 return; 2411 } 2412 2413 if (mLoggingEnabled) { 2414 Slog.d(TAG, "updateSensorStatus: mShouldObserveAmbientLowChange = " 2415 + mShouldObserveAmbientLowChange + ", mShouldObserveAmbientHighChange = " 2416 + mShouldObserveAmbientHighChange); 2417 Slog.d(TAG, "updateSensorStatus: mLowPowerModeEnabled = " 2418 + mLowPowerModeEnabled + ", mRefreshRateChangeable = " 2419 + mRefreshRateChangeable); 2420 } 2421 2422 boolean registerForThermals = false; 2423 if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) 2424 && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) { 2425 registerLightSensor(); 2426 registerForThermals = mLowZoneRefreshRateForThermals != null 2427 || mHighZoneRefreshRateForThermals != null; 2428 } else { 2429 unregisterSensorListener(); 2430 } 2431 2432 if (registerForThermals && !mThermalRegistered) { 2433 mThermalRegistered = mInjector.registerThermalServiceListener(mThermalListener); 2434 } else if (!registerForThermals && mThermalRegistered) { 2435 mInjector.unregisterThermalServiceListener(mThermalListener); 2436 mThermalRegistered = false; 2437 synchronized (mLock) { 2438 mThermalStatus = Temperature.THROTTLING_NONE; // reset 2439 } 2440 } 2441 } 2442 registerLightSensor()2443 private void registerLightSensor() { 2444 if (mRegisteredLightSensor == mLightSensor) { 2445 return; 2446 } 2447 2448 if (mRegisteredLightSensor != null) { 2449 unregisterSensorListener(); 2450 } 2451 2452 mSensorManager.registerListener(mLightSensorListener, 2453 mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); 2454 mRegisteredLightSensor = mLightSensor; 2455 if (mLoggingEnabled) { 2456 Slog.d(TAG, "updateSensorStatus: registerListener"); 2457 } 2458 } 2459 unregisterSensorListener()2460 private void unregisterSensorListener() { 2461 mLightSensorListener.removeCallbacks(); 2462 mSensorManager.unregisterListener(mLightSensorListener); 2463 mRegisteredLightSensor = null; 2464 if (mLoggingEnabled) { 2465 Slog.d(TAG, "updateSensorStatus: unregisterListener"); 2466 } 2467 } 2468 isDeviceActive()2469 private boolean isDeviceActive() { 2470 return mDefaultDisplayState == Display.STATE_ON; 2471 } 2472 2473 /** 2474 * Get the brightness value for a display 2475 * @param displayId The ID of the display 2476 * @return The brightness value 2477 */ getBrightness(int displayId)2478 private float getBrightness(int displayId) { 2479 final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); 2480 if (info != null) { 2481 return info.adjustedBrightness; 2482 } 2483 2484 return BRIGHTNESS_INVALID_FLOAT; 2485 } 2486 2487 private final class LightSensorEventListener implements SensorEventListener { 2488 private static final int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS; 2489 private float mLastSensorData; 2490 private long mTimestamp; 2491 private boolean mLoggingEnabled; 2492 dumpLocked(PrintWriter pw)2493 public void dumpLocked(PrintWriter pw) { 2494 pw.println(" mLastSensorData: " + mLastSensorData); 2495 pw.println(" mTimestamp: " + formatTimestamp(mTimestamp)); 2496 } 2497 2498 setLoggingEnabled(boolean loggingEnabled)2499 public void setLoggingEnabled(boolean loggingEnabled) { 2500 if (mLoggingEnabled == loggingEnabled) { 2501 return; 2502 } 2503 mLoggingEnabled = loggingEnabled; 2504 } 2505 2506 @Override onSensorChanged(SensorEvent event)2507 public void onSensorChanged(SensorEvent event) { 2508 mLastSensorData = event.values[0]; 2509 if (mLoggingEnabled) { 2510 Slog.d(TAG, "On sensor changed: " + mLastSensorData); 2511 } 2512 2513 boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, 2514 mLowAmbientBrightnessThresholds); 2515 boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux, 2516 mHighAmbientBrightnessThresholds); 2517 if ((lowZoneChanged && mLastSensorData < mAmbientLux) 2518 || (highZoneChanged && mLastSensorData > mAmbientLux)) { 2519 // Easier to see flicker at lower brightness environment or high brightness 2520 // environment. Forget the history to get immediate response. 2521 if (mAmbientFilter != null) { 2522 mAmbientFilter.clear(); 2523 } 2524 } 2525 2526 long now = SystemClock.uptimeMillis(); 2527 mTimestamp = System.currentTimeMillis(); 2528 if (mAmbientFilter != null) { 2529 mAmbientFilter.addValue(now, mLastSensorData); 2530 } 2531 2532 mHandler.removeCallbacks(mInjectSensorEventRunnable); 2533 processSensorData(now); 2534 2535 if ((lowZoneChanged && mLastSensorData > mAmbientLux) 2536 || (highZoneChanged && mLastSensorData < mAmbientLux)) { 2537 // Sensor may not report new event if there is no brightness change. 2538 // Need to keep querying the temporal filter for the latest estimation, 2539 // until sensor readout and filter estimation are in the same zone or 2540 // is interrupted by a new sensor event. 2541 mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); 2542 } 2543 2544 if (mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled()) { 2545 updateIdleScreenRefreshRate(mAmbientLux); 2546 } 2547 } 2548 2549 @Override onAccuracyChanged(Sensor sensor, int accuracy)2550 public void onAccuracyChanged(Sensor sensor, int accuracy) { 2551 // Not used. 2552 } 2553 removeCallbacks()2554 public void removeCallbacks() { 2555 mHandler.removeCallbacks(mInjectSensorEventRunnable); 2556 } 2557 formatTimestamp(long time)2558 private String formatTimestamp(long time) { 2559 SimpleDateFormat dateFormat = 2560 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US); 2561 return dateFormat.format(new Date(time)); 2562 } 2563 processSensorData(long now)2564 private void processSensorData(long now) { 2565 if (mAmbientFilter != null) { 2566 mAmbientLux = mAmbientFilter.getEstimate(now); 2567 } else { 2568 mAmbientLux = mLastSensorData; 2569 } 2570 2571 synchronized (mLock) { 2572 onBrightnessChangedLocked(); 2573 } 2574 } 2575 isDifferentZone(float lux1, float lux2, float[] luxThresholds)2576 private boolean isDifferentZone(float lux1, float lux2, float[] luxThresholds) { 2577 for (final float boundary : luxThresholds) { 2578 // Test each boundary. See if the current value and the new value are at 2579 // different sides. 2580 if ((lux1 <= boundary && lux2 > boundary) 2581 || (lux1 > boundary && lux2 <= boundary)) { 2582 return true; 2583 } 2584 } 2585 2586 return false; 2587 } 2588 2589 private final Runnable mInjectSensorEventRunnable = new Runnable() { 2590 @Override 2591 public void run() { 2592 long now = SystemClock.uptimeMillis(); 2593 // No need to really inject the last event into a temporal filter. 2594 processSensorData(now); 2595 2596 // Inject next event if there is a possible zone change. 2597 if (isDifferentZone(mLastSensorData, mAmbientLux, 2598 mLowAmbientBrightnessThresholds) 2599 || isDifferentZone(mLastSensorData, mAmbientLux, 2600 mHighAmbientBrightnessThresholds)) { 2601 mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS); 2602 } 2603 } 2604 }; 2605 } 2606 updateIdleScreenRefreshRate(float ambientLux)2607 private void updateIdleScreenRefreshRate(float ambientLux) { 2608 List<IdleScreenRefreshRateTimeoutLuxThresholdPoint> 2609 idleScreenRefreshRateTimeoutLuxThresholdPoints; 2610 synchronized (mLock) { 2611 if (mDefaultDisplayDeviceConfig == null || mDefaultDisplayDeviceConfig 2612 .getIdleScreenRefreshRateTimeoutLuxThresholdPoint().isEmpty()) { 2613 // Setting this to null will let surface flinger know that the idle timer is not 2614 // configured in the display configs 2615 mIdleScreenRefreshRateConfig = null; 2616 return; 2617 } 2618 2619 idleScreenRefreshRateTimeoutLuxThresholdPoints = 2620 mDefaultDisplayDeviceConfig 2621 .getIdleScreenRefreshRateTimeoutLuxThresholdPoint(); 2622 } 2623 int newTimeout = -1; 2624 for (IdleScreenRefreshRateTimeoutLuxThresholdPoint point : 2625 idleScreenRefreshRateTimeoutLuxThresholdPoints) { 2626 int newLux = point.getLux().intValue(); 2627 if (newLux <= ambientLux) { 2628 newTimeout = point.getTimeout().intValue(); 2629 } 2630 } 2631 if (mIdleScreenRefreshRateConfig == null 2632 || newTimeout != mIdleScreenRefreshRateConfig.timeoutMillis) { 2633 mIdleScreenRefreshRateConfig = 2634 new IdleScreenRefreshRateConfig(newTimeout); 2635 synchronized (mLock) { 2636 notifyDesiredDisplayModeSpecsChangedLocked(); 2637 } 2638 } 2639 } 2640 } 2641 2642 private class UdfpsObserver extends IUdfpsRefreshRateRequestCallback.Stub { 2643 private final SparseBooleanArray mUdfpsRefreshRateEnabled = new SparseBooleanArray(); 2644 private final SparseBooleanArray mAuthenticationPossible = new SparseBooleanArray(); 2645 observe()2646 public void observe() { 2647 StatusBarManagerInternal statusBar = mInjector.getStatusBarManagerInternal(); 2648 if (statusBar == null) { 2649 return; 2650 } 2651 2652 // Allow UDFPS vote by registering callback, only 2653 // if the device is configured to not ignore UDFPS vote. 2654 boolean ignoreUdfpsVote = mContext.getResources() 2655 .getBoolean(R.bool.config_ignoreUdfpsVote); 2656 if (!ignoreUdfpsVote) { 2657 statusBar.setUdfpsRefreshRateCallback(this); 2658 } 2659 } 2660 2661 @Override onRequestEnabled(int displayId)2662 public void onRequestEnabled(int displayId) { 2663 synchronized (mLock) { 2664 mUdfpsRefreshRateEnabled.put(displayId, true); 2665 updateVoteLocked(displayId, true, Vote.PRIORITY_UDFPS); 2666 } 2667 } 2668 2669 @Override onRequestDisabled(int displayId)2670 public void onRequestDisabled(int displayId) { 2671 synchronized (mLock) { 2672 mUdfpsRefreshRateEnabled.put(displayId, false); 2673 updateVoteLocked(displayId, false, Vote.PRIORITY_UDFPS); 2674 } 2675 } 2676 2677 @Override onAuthenticationPossible(int displayId, boolean isPossible)2678 public void onAuthenticationPossible(int displayId, boolean isPossible) { 2679 synchronized (mLock) { 2680 mAuthenticationPossible.put(displayId, isPossible); 2681 updateVoteLocked(displayId, isPossible, 2682 Vote.PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE); 2683 } 2684 } 2685 2686 @GuardedBy("mLock") updateVoteLocked(int displayId, boolean enabled, int votePriority)2687 private void updateVoteLocked(int displayId, boolean enabled, int votePriority) { 2688 final Vote vote; 2689 if (enabled) { 2690 float maxRefreshRate = DisplayModeDirector.this.getMaxRefreshRateLocked(displayId); 2691 vote = Vote.forPhysicalRefreshRates(maxRefreshRate, maxRefreshRate); 2692 } else { 2693 vote = null; 2694 } 2695 mVotesStorage.updateVote(displayId, votePriority, vote); 2696 } 2697 dumpLocked(PrintWriter pw)2698 void dumpLocked(PrintWriter pw) { 2699 pw.println(" UdfpsObserver"); 2700 pw.println(" mUdfpsRefreshRateEnabled: "); 2701 for (int i = 0; i < mUdfpsRefreshRateEnabled.size(); i++) { 2702 final int displayId = mUdfpsRefreshRateEnabled.keyAt(i); 2703 final String enabled = mUdfpsRefreshRateEnabled.valueAt(i) ? "enabled" : "disabled"; 2704 pw.println(" Display " + displayId + ": " + enabled); 2705 } 2706 pw.println(" mAuthenticationPossible: "); 2707 for (int i = 0; i < mAuthenticationPossible.size(); i++) { 2708 final int displayId = mAuthenticationPossible.keyAt(i); 2709 final String isPossible = mAuthenticationPossible.valueAt(i) ? "possible" 2710 : "impossible"; 2711 pw.println(" Display " + displayId + ": " + isPossible); 2712 } 2713 } 2714 } 2715 2716 2717 /** 2718 * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for 2719 * HBM that are associated with that display. Restrictions are retrieved from 2720 * DisplayManagerInternal but originate in the display-device-config file. 2721 */ 2722 public class HbmObserver implements DisplayManager.DisplayListener { 2723 private final VotesStorage mVotesStorage; 2724 private final Handler mHandler; 2725 private final SparseIntArray mHbmMode = new SparseIntArray(); 2726 private final SparseBooleanArray mHbmActive = new SparseBooleanArray(); 2727 private final Injector mInjector; 2728 private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; 2729 private int mRefreshRateInHbmSunlight; 2730 private int mRefreshRateInHbmHdr; 2731 2732 private DisplayManagerInternal mDisplayManagerInternal; 2733 HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler, DeviceConfigDisplaySettings displaySettings)2734 HbmObserver(Injector injector, VotesStorage votesStorage, Handler handler, 2735 DeviceConfigDisplaySettings displaySettings) { 2736 mInjector = injector; 2737 mVotesStorage = votesStorage; 2738 mHandler = handler; 2739 mDeviceConfigDisplaySettings = displaySettings; 2740 } 2741 2742 /** 2743 * Sets up the refresh rate to be used when HDR is enabled 2744 */ setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig)2745 public void setupHdrRefreshRates(DisplayDeviceConfig displayDeviceConfig) { 2746 mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings 2747 .getRefreshRateInHbmHdr(displayDeviceConfig); 2748 mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings 2749 .getRefreshRateInHbmSunlight(displayDeviceConfig); 2750 } 2751 2752 /** 2753 * Sets up the HDR refresh rates, and starts observing for the changes in the display that 2754 * might impact it 2755 */ observe()2756 public void observe() { 2757 synchronized (mLock) { 2758 setupHdrRefreshRates(mDefaultDisplayDeviceConfig); 2759 } 2760 mDisplayManagerInternal = mInjector.getDisplayManagerInternal(); 2761 mInjector.registerDisplayListener(this, mHandler, 2762 DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS 2763 | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); 2764 } 2765 2766 /** 2767 * @return the refresh to lock to when the device is in high brightness mode for Sunlight. 2768 */ 2769 @VisibleForTesting getRefreshRateInHbmSunlight()2770 int getRefreshRateInHbmSunlight() { 2771 return mRefreshRateInHbmSunlight; 2772 } 2773 2774 /** 2775 * @return the refresh to lock to when the device is in high brightness mode for HDR. 2776 */ 2777 @VisibleForTesting getRefreshRateInHbmHdr()2778 int getRefreshRateInHbmHdr() { 2779 return mRefreshRateInHbmHdr; 2780 } 2781 2782 /** 2783 * Recalculates the HBM vote when the device config has been changed. 2784 */ onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate)2785 public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) { 2786 if (refreshRate != mRefreshRateInHbmSunlight) { 2787 mRefreshRateInHbmSunlight = refreshRate; 2788 onDeviceConfigRefreshRateInHbmChanged(); 2789 } 2790 } 2791 2792 /** 2793 * Recalculates the HBM vote when the device config has been changed. 2794 */ onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate)2795 public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) { 2796 if (refreshRate != mRefreshRateInHbmHdr) { 2797 mRefreshRateInHbmHdr = refreshRate; 2798 onDeviceConfigRefreshRateInHbmChanged(); 2799 } 2800 } 2801 2802 @Override onDisplayAdded(int displayId)2803 public void onDisplayAdded(int displayId) {} 2804 2805 @Override onDisplayRemoved(int displayId)2806 public void onDisplayRemoved(int displayId) { 2807 mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); 2808 mHbmMode.delete(displayId); 2809 mHbmActive.delete(displayId); 2810 } 2811 2812 @Override onDisplayChanged(int displayId)2813 public void onDisplayChanged(int displayId) { 2814 final BrightnessInfo info = mInjector.getBrightnessInfo(displayId); 2815 if (info == null) { 2816 // Display no longer there. Assume we'll get an onDisplayRemoved very soon. 2817 return; 2818 } 2819 2820 final int hbmMode = info.highBrightnessMode; 2821 final boolean isHbmActive = hbmMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF 2822 && info.adjustedBrightness > info.highBrightnessTransitionPoint; 2823 if (hbmMode == mHbmMode.get(displayId) 2824 && isHbmActive == mHbmActive.get(displayId)) { 2825 // no change, ignore. 2826 return; 2827 } 2828 mHbmMode.put(displayId, hbmMode); 2829 mHbmActive.put(displayId, isHbmActive); 2830 recalculateVotesForDisplay(displayId); 2831 } 2832 onDeviceConfigRefreshRateInHbmChanged()2833 private void onDeviceConfigRefreshRateInHbmChanged() { 2834 final int[] displayIds = mHbmMode.copyKeys(); 2835 if (displayIds != null) { 2836 for (int id : displayIds) { 2837 recalculateVotesForDisplay(id); 2838 } 2839 } 2840 } 2841 recalculateVotesForDisplay(int displayId)2842 private void recalculateVotesForDisplay(int displayId) { 2843 Vote vote = null; 2844 if (mHbmActive.get(displayId, false)) { 2845 final int hbmMode = 2846 mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); 2847 if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) { 2848 // Device resource properties take priority over DisplayDeviceConfig 2849 if (mRefreshRateInHbmSunlight > 0) { 2850 vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmSunlight, 2851 mRefreshRateInHbmSunlight); 2852 } else { 2853 final List<RefreshRateLimitation> limits = 2854 mDisplayManagerInternal.getRefreshRateLimitations(displayId); 2855 for (int i = 0; limits != null && i < limits.size(); i++) { 2856 final RefreshRateLimitation limitation = limits.get(i); 2857 if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { 2858 vote = Vote.forPhysicalRefreshRates(limitation.range.min, 2859 limitation.range.max); 2860 break; 2861 } 2862 } 2863 } 2864 } else if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR 2865 && mRefreshRateInHbmHdr > 0) { 2866 // HBM for HDR vote isn't supported through DisplayDeviceConfig yet, so look for 2867 // a vote from Device properties 2868 vote = Vote.forPhysicalRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr); 2869 } else { 2870 Slog.w(TAG, "Unexpected HBM mode " + hbmMode + " for display ID " + displayId); 2871 } 2872 2873 } 2874 mVotesStorage.updateVote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); 2875 } 2876 dumpLocked(PrintWriter pw)2877 void dumpLocked(PrintWriter pw) { 2878 pw.println(" HbmObserver"); 2879 pw.println(" mHbmMode: " + mHbmMode); 2880 pw.println(" mHbmActive: " + mHbmActive); 2881 pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight); 2882 pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr); 2883 } 2884 } 2885 2886 private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener { startListening()2887 public void startListening() { 2888 mConfigParameterProvider.addOnPropertiesChangedListener( 2889 BackgroundThread.getExecutor(), this); 2890 } 2891 getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig)2892 private int getRefreshRateInHbmHdr(DisplayDeviceConfig displayDeviceConfig) { 2893 return getRefreshRate( 2894 () -> mConfigParameterProvider.getRefreshRateInHbmHdr(), 2895 () -> displayDeviceConfig.getRefreshRateData().defaultRefreshRateInHbmHdr, 2896 R.integer.config_defaultRefreshRateInHbmHdr, 2897 displayDeviceConfig 2898 ); 2899 } 2900 getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig)2901 private int getRefreshRateInHbmSunlight(DisplayDeviceConfig displayDeviceConfig) { 2902 return getRefreshRate( 2903 () -> mConfigParameterProvider.getRefreshRateInHbmSunlight(), 2904 () -> displayDeviceConfig.getRefreshRateData().defaultRefreshRateInHbmSunlight, 2905 R.integer.config_defaultRefreshRateInHbmSunlight, 2906 displayDeviceConfig 2907 ); 2908 } 2909 getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig)2910 private int getRefreshRate(IntSupplier fromConfigPram, IntSupplier fromDisplayDeviceConfig, 2911 @IntegerRes int configKey, DisplayDeviceConfig displayDeviceConfig) { 2912 int refreshRate = -1; 2913 try { 2914 refreshRate = fromConfigPram.getAsInt(); 2915 } catch (NullPointerException npe) { 2916 // Do Nothing 2917 } 2918 if (refreshRate == -1) { 2919 refreshRate = (displayDeviceConfig == null) 2920 ? mContext.getResources().getInteger(configKey) 2921 : fromDisplayDeviceConfig.getAsInt(); 2922 } 2923 return refreshRate; 2924 } 2925 2926 @Override onPropertiesChanged(@onNull DeviceConfig.Properties properties)2927 public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { 2928 float defaultPeakRefreshRate = mConfigParameterProvider.getPeakRefreshRateDefault(); 2929 mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED, 2930 defaultPeakRefreshRate == -1 ? null : defaultPeakRefreshRate).sendToTarget(); 2931 2932 float[] lowDisplayBrightnessThresholds = 2933 mConfigParameterProvider.getLowDisplayBrightnessThresholds(); 2934 float[] lowAmbientBrightnessThresholds = 2935 mConfigParameterProvider.getLowAmbientBrightnessThresholds(); 2936 final int refreshRateInLowZone = mConfigParameterProvider.getRefreshRateInLowZone(); 2937 2938 mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED, 2939 new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds)) 2940 .sendToTarget(); 2941 2942 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 2943 0).sendToTarget(); 2944 2945 float[] highDisplayBrightnessThresholds = 2946 mConfigParameterProvider.getHighDisplayBrightnessThresholds(); 2947 float[] highAmbientBrightnessThresholds = 2948 mConfigParameterProvider.getHighAmbientBrightnessThresholds(); 2949 final int refreshRateInHighZone = mConfigParameterProvider.getRefreshRateInHighZone(); 2950 2951 mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED, 2952 new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds)) 2953 .sendToTarget(); 2954 2955 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 2956 0).sendToTarget(); 2957 2958 synchronized (mLock) { 2959 final int refreshRateInHbmSunlight = 2960 getRefreshRateInHbmSunlight(mDefaultDisplayDeviceConfig); 2961 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED, 2962 refreshRateInHbmSunlight, 0) 2963 .sendToTarget(); 2964 2965 final int refreshRateInHbmHdr = 2966 getRefreshRateInHbmHdr(mDefaultDisplayDeviceConfig); 2967 mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0) 2968 .sendToTarget(); 2969 } 2970 } 2971 } 2972 2973 interface Injector { 2974 Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE); 2975 Uri MIN_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE); 2976 2977 @NonNull getDeviceConfig()2978 DeviceConfigInterface getDeviceConfig(); 2979 registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2980 void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, 2981 @NonNull ContentObserver observer); 2982 registerMinRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)2983 void registerMinRefreshRateObserver(@NonNull ContentResolver cr, 2984 @NonNull ContentObserver observer); 2985 registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler)2986 void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, 2987 Handler handler); 2988 registerDisplayListener(@onNull DisplayManager.DisplayListener listener, Handler handler, long flags)2989 void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener, 2990 Handler handler, long flags); 2991 getDisplay(int displayId)2992 Display getDisplay(int displayId); 2993 getDisplays()2994 Display[] getDisplays(); 2995 getDisplayInfo(int displayId, DisplayInfo displayInfo)2996 boolean getDisplayInfo(int displayId, DisplayInfo displayInfo); 2997 getBrightnessInfo(int displayId)2998 BrightnessInfo getBrightnessInfo(int displayId); 2999 isDozeState(Display d)3000 boolean isDozeState(Display d); 3001 registerThermalServiceListener(IThermalEventListener listener)3002 boolean registerThermalServiceListener(IThermalEventListener listener); unregisterThermalServiceListener(IThermalEventListener listener)3003 void unregisterThermalServiceListener(IThermalEventListener listener); 3004 supportsFrameRateOverride()3005 boolean supportsFrameRateOverride(); 3006 getDisplayManagerInternal()3007 DisplayManagerInternal getDisplayManagerInternal(); 3008 getStatusBarManagerInternal()3009 StatusBarManagerInternal getStatusBarManagerInternal(); 3010 getSensorManagerInternal()3011 SensorManagerInternal getSensorManagerInternal(); 3012 3013 @Nullable getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled)3014 VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled); 3015 } 3016 3017 @VisibleForTesting 3018 static class RealInjector implements Injector { 3019 private final Context mContext; 3020 private DisplayManager mDisplayManager; 3021 RealInjector(Context context)3022 RealInjector(Context context) { 3023 mContext = context; 3024 } 3025 3026 @Override 3027 @NonNull getDeviceConfig()3028 public DeviceConfigInterface getDeviceConfig() { 3029 return DeviceConfigInterface.REAL; 3030 } 3031 3032 @Override registerPeakRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)3033 public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr, 3034 @NonNull ContentObserver observer) { 3035 cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/, 3036 observer, UserHandle.USER_SYSTEM); 3037 } 3038 3039 @Override registerMinRefreshRateObserver(@onNull ContentResolver cr, @NonNull ContentObserver observer)3040 public void registerMinRefreshRateObserver(@NonNull ContentResolver cr, 3041 @NonNull ContentObserver observer) { 3042 cr.registerContentObserver(MIN_REFRESH_RATE_URI, false /*notifyDescendants*/, 3043 observer, UserHandle.USER_SYSTEM); 3044 } 3045 3046 @Override registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)3047 public void registerDisplayListener(DisplayManager.DisplayListener listener, 3048 Handler handler) { 3049 getDisplayManager().registerDisplayListener(listener, handler); 3050 } 3051 3052 @Override registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler, long flags)3053 public void registerDisplayListener(DisplayManager.DisplayListener listener, 3054 Handler handler, long flags) { 3055 getDisplayManager().registerDisplayListener(listener, handler, flags); 3056 } 3057 3058 @Override getDisplay(int displayId)3059 public Display getDisplay(int displayId) { 3060 return getDisplayManager().getDisplay(displayId); 3061 } 3062 3063 @Override getDisplays()3064 public Display[] getDisplays() { 3065 return getDisplayManager().getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED); 3066 } 3067 3068 @Override getDisplayInfo(int displayId, DisplayInfo displayInfo)3069 public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) { 3070 Display display = getDisplayManager().getDisplay(displayId); 3071 if (display == null) { 3072 // We can occasionally get a display added or changed event for a display that was 3073 // subsequently removed, which means this returns null. Check this case and bail 3074 // out early; if it gets re-attached we'll eventually get another call back for it. 3075 return false; 3076 } 3077 return display.getDisplayInfo(displayInfo); 3078 } 3079 3080 @Override getBrightnessInfo(int displayId)3081 public BrightnessInfo getBrightnessInfo(int displayId) { 3082 final Display display = getDisplayManager().getDisplay(displayId); 3083 if (display != null) { 3084 return display.getBrightnessInfo(); 3085 } 3086 return null; 3087 } 3088 3089 @Override isDozeState(Display d)3090 public boolean isDozeState(Display d) { 3091 if (d == null) { 3092 return false; 3093 } 3094 return Display.isDozeState(d.getState()); 3095 } 3096 3097 @Override registerThermalServiceListener(IThermalEventListener listener)3098 public boolean registerThermalServiceListener(IThermalEventListener listener) { 3099 IThermalService thermalService = getThermalService(); 3100 if (thermalService == null) { 3101 Slog.w(TAG, "Could not observe thermal status. Service not available"); 3102 return false; 3103 } 3104 try { 3105 thermalService.registerThermalEventListenerWithType(listener, 3106 Temperature.TYPE_SKIN); 3107 } catch (RemoteException e) { 3108 Slog.e(TAG, "Failed to register thermal status listener", e); 3109 return false; 3110 } 3111 return true; 3112 } 3113 3114 @Override unregisterThermalServiceListener(IThermalEventListener listener)3115 public void unregisterThermalServiceListener(IThermalEventListener listener) { 3116 IThermalService thermalService = getThermalService(); 3117 if (thermalService == null) { 3118 Slog.w(TAG, "Could not unregister thermal status. Service not available"); 3119 } 3120 try { 3121 thermalService.unregisterThermalEventListener(listener); 3122 } catch (RemoteException e) { 3123 Slog.e(TAG, "Failed to unregister thermal status listener", e); 3124 } 3125 } 3126 3127 @Override supportsFrameRateOverride()3128 public boolean supportsFrameRateOverride() { 3129 return SurfaceFlingerProperties.enable_frame_rate_override().orElse(true); 3130 } 3131 3132 @Override getDisplayManagerInternal()3133 public DisplayManagerInternal getDisplayManagerInternal() { 3134 return LocalServices.getService(DisplayManagerInternal.class); 3135 } 3136 3137 @Override getStatusBarManagerInternal()3138 public StatusBarManagerInternal getStatusBarManagerInternal() { 3139 return LocalServices.getService(StatusBarManagerInternal.class); 3140 } 3141 3142 @Override getSensorManagerInternal()3143 public SensorManagerInternal getSensorManagerInternal() { 3144 return LocalServices.getService(SensorManagerInternal.class); 3145 } 3146 3147 @Override getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled)3148 public VotesStatsReporter getVotesStatsReporter(boolean refreshRateVotingTelemetryEnabled) { 3149 // if frame rate override supported, renderRates will be ignored in mode selection 3150 return new VotesStatsReporter(supportsFrameRateOverride(), 3151 refreshRateVotingTelemetryEnabled); 3152 } 3153 getDisplayManager()3154 private DisplayManager getDisplayManager() { 3155 if (mDisplayManager == null) { 3156 mDisplayManager = mContext.getSystemService(DisplayManager.class); 3157 } 3158 return mDisplayManager; 3159 } 3160 getThermalService()3161 private IThermalService getThermalService() { 3162 return IThermalService.Stub.asInterface( 3163 ServiceManager.getService(Context.THERMAL_SERVICE)); 3164 } 3165 } 3166 } 3167