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